// bsls_alignedbuffer.h -*-C++-*- #ifndef INCLUDED_BSLS_ALIGNEDBUFFER #define INCLUDED_BSLS_ALIGNEDBUFFER #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide raw buffers with user-specified size and alignment. // //@CLASSES: // bsls::AlignedBuffer: Uninitialized buffer of specified size and alignment // //@SEE_ALSO: bsls_objectbuffer, bsls_alignmenttotype // //@DESCRIPTION: This component provides a templated buffer type with a // user-specified compile-time size and user-specified alignment. The user // instantiates 'bsls::AlignedBuffer' with specific size and alignment // requirements, and then uses that memory as needed. If an alignment is not // specified at template instantiation, then the buffer object is maximally // aligned. // // Typically, 'bsls::AlignedBuffer' is used in situations where it is desirable // to allocate a block of properly-aligned raw memory from somewhere other than // the heap, e.g., on the stack or within an aggregate object, including within // a union. It is a convenient way to create a small heap from which one or // more objects are allocated at run-time. // ///Single-Object Buffers ///--------------------- // Although, for a given type 'T', // 'bsls::AlignedBuffer<sizeof(T), bsls::AlignmentFromType<T>::VALUE>' will // produce a buffer properly sized and aligned to hold a 'T' object, it is // simpler and clearer to use 'bsls::ObjectBuffer<T>' for this purpose. See // the 'bsls_objectbuffer' component for more information. // ///Stack Alignment ///--------------- // On platforms with 32-bit words, there is usually no efficiency gain by using // more than 4-byte alignment. Yet some compilers use 8-byte alignment for // 'long long' or 'double', presumably so that the code will run faster on a // future 64-bit CPU. The program loader, however, has no reason to presume // more than 4-byte alignment when allocating the program stack. This can // result in stack objects appearing to be misaligned relative to the // alignments computed by this component. This is not a bug in either this // component nor in the compiler, but it is somewhat surprising. We have seen // this behavior on the MS VC++ 7 platform. See also the "Surprises and // Anomalies" section in 'bsls_alignmentfromtype.h'. // ///Known issues ///------------ // On all versions of the Microsoft compiler prior to MSVC 14.0 (2015), passing // 'AlignedBuffer' or an object containing 'AlignedBuffer' as a *by-value* // function argument would lead to C2719 error (see // https://msdn.microsoft.com/en-us/library/373ak2y1.aspx). In versions 14.10 // (2017) through 16.8 (2019) it can trigger a compiler bug leading to crashes // due to the destructor being invoked with an incorrect 'this' pointer. This // bug has been observed only building for x86 (32-bit) platform in Debug mode // (specifically with /Od /Ob0 flags), e.g.: //.. // struct X { // bsls::AlignedBuffer<1, 8> d_buffer; // }; // // void func(X) {} // // int main() // { // func(X()); // The destructor of 'X' is called with broken 'this'. // } //.. // See DRQS 151904020 for more details. // // This was fixed my Microsoft in MSVC 2019 version 16.9, for details see: // https://developercommunity.visualstudio.com/t/incorrect-code-gen-missing-error/831543 // ///Usage ///----- // The 'allocateFromBuffer' function below uses an aligned buffer as a small // heap from which objects can be allocated. We choose 'int' alignment (4-byte // alignment) for our buffer because the objects we are allocating are composed // of 'char', 'short', and 'int' values only. If no alignment were specified, // the buffer would be maximally aligned, which could be wasteful on some // platforms. //.. // const int MY_ALIGNMENT = bsls::AlignmentFromType<int>::VALUE; // bsls::AlignedBuffer<1000, MY_ALIGNMENT> my_AllocBuffer; // const char* my_AllocEnd = my_AllocBuffer.buffer() + 1000; // char *my_AllocPtr = my_AllocBuffer.buffer(); // // Invariant: my_AllocPtr is always aligned on a multiple of 4 bytes // // static void *allocateFromBuffer(int size) // { // if (size > my_AllocEnd - my_AllocPtr) // return 0; // Out of buffer space // // void *result = my_AllocPtr; // my_AllocPtr += size; // if (size % MY_ALIGNMENT) { // // re-establish invariant by re-aligning my_AllocPtr // my_AllocPtr += MY_ALIGNMENT - size % MY_ALIGNMENT; // } // // assert(0 == size_t(my_AllocPtr) % MY_ALIGNMENT); // Test invariant // // return result; // } //.. // Below, we use our allocation function to allocate arrays of 'char', 'short', // and user-defined 'Object' types from the static buffer. Note that our // 'Object' structure is composed of members that have alignment requirements // less than or equal to 'int's alignment requirements. //.. // struct Object { // char d_c; // short d_s; // int d_i; // }; // // int main() // { // // Allocate three 'char's from the buffer. // char *charPtr = (char *) allocateFromBuffer(3 * sizeof(char)); // assert(0 == size_t(charPtr) % MY_ALIGNMENT); // // // Allocate three 'short's from the buffer. // short *shortPtr = (short *) allocateFromBuffer(3 * sizeof(short)); // assert(0 == size_t(shortPtr) % MY_ALIGNMENT); // // // Allocate three 'Object's from the buffer // Object *objPtr = (Object *) allocateFromBuffer(3 * sizeof(Object)); // assert(0 == size_t(objPtr) % MY_ALIGNMENT); // // if (!charPtr || !shortPtr || !objPtr) { // fprintf(stderr, "Global buffer is not large enough.\n"); // return -1; // } // // // ... // // return 0; // } //.. #include <bsls_alignmenttotype.h> #include <bsls_alignmentutil.h> #include <bsls_compilerfeatures.h> #include <bsls_platform.h> namespace BloombergLP { namespace bsls { // ======================== // union AlignedBuffer_Data // ======================== template <int SIZE, int ALIGNMENT> union AlignedBuffer_Data { // This *private* implementation type provides a public 'char' array // data member 'd_buffer' whose length is the specifed (template parameter) // 'SIZE' and which is aligned according to the specified (template // parameter) 'ALIGNMENT'. public: typedef typename AlignmentToType<ALIGNMENT>::Type AlignmentType; // Define an alias for alignment type to work around a Sun CC 5.5 bug // that gives a warning if the type is directly accessed in the union. // Note that to allow the union to access this typedef it must be // declared with public access. #if defined(BSLS_COMPILERFEATURES_SUPPORT_ALIGNAS) // The C++11 implementation uses the 'alignas' keyword to ensure the // alignment of 'd_buffer'. alignas(ALIGNMENT) char d_buffer[SIZE]; #else // The C++03 implementation uses a union data member to ensure the // alignment of 'd_buffer'. char d_buffer[SIZE]; AlignmentType d_align; #endif }; #if defined(BSLS_PLATFORM_CMP_MSVC) && !defined(BSLS_COMPILERFEATURES_SUPPORT_ALIGNAS) // We provide template specializations for MSVC using __declspec(align). // Note that MSVC does not enforce the alignment of (at least) 'double' // variables on the stack. (internal issue 64140445). #define BSLS_ALIGNAS(N) __declspec(align(N)) template <int SIZE> union AlignedBuffer_Data<SIZE, 1> {BSLS_ALIGNAS(1) char d_buffer[SIZE]; }; template <int SIZE> union AlignedBuffer_Data<SIZE, 2> {BSLS_ALIGNAS(2) char d_buffer[SIZE]; }; template <int SIZE> union AlignedBuffer_Data<SIZE, 4> {BSLS_ALIGNAS(4) char d_buffer[SIZE]; }; template <int SIZE> union AlignedBuffer_Data<SIZE, 8> {BSLS_ALIGNAS(8) char d_buffer[SIZE]; }; template <int SIZE> union AlignedBuffer_Data<SIZE, 16> {BSLS_ALIGNAS(16) char d_buffer[SIZE]; }; #undef BSLS_ALIGNAS #endif // defined(BSLS_PLATFORM_CMP_MSVC) // =================== // class AlignedBuffer // =================== template <int SIZE, int ALIGNMENT = AlignmentUtil::BSLS_MAX_ALIGNMENT> class AlignedBuffer { // An instance of this union is a block of raw memory of specified 'SIZE' // and 'ALIGNMENT'. A 'AlignedBuffer' object does not manage the // construction or destruction of any other objects. 'SIZE' is rounded up // to the nearest multiple of 'ALIGNMENT'. An instantiation of this union // template will not compile unless 'ALIGNMENT' is a power of two not // larger than 'AlignmentUtil::BSLS_MAX_ALIGNMENT'. // DATA AlignedBuffer_Data<SIZE, ALIGNMENT> d_data; public: // CREATORS Note that We deliberately omit defining constructors and // destructors in order to keep this union "POD-like". In particular, a // 'AlignedBuffer' may be used as a member in another 'union'. Copying a // 'AlignedBuffer' assignment or copy construction will result in a // bit-wise copy and will not invoke any user-defined assignment operators // or copy constructors. // MANIPULATORS char *buffer(); // Return a the address of the first byte of this object, cast to a // 'char*' pointer. // ACCESSORS const char *buffer() const; // Return a the address of the first byte of this object, cast to a // 'const char*' pointer. }; // ============================================================================ // INLINE FUNCTION DEFINITIONS // ============================================================================ // MANIPULATORS template <int SIZE, int ALIGNMENT> inline char *AlignedBuffer<SIZE, ALIGNMENT>::buffer() { return d_data.d_buffer; } // ACCESSORS template <int SIZE, int ALIGNMENT> inline const char *AlignedBuffer<SIZE, ALIGNMENT>::buffer() const { return d_data.d_buffer; } } // close package namespace #ifndef BDE_OPENSOURCE_PUBLICATION // BACKWARD_COMPATIBILITY // ============================================================================ // BACKWARD COMPATIBILITY // ============================================================================ #ifdef bsls_AlignedBuffer #undef bsls_AlignedBuffer #endif #define bsls_AlignedBuffer bsls::AlignedBuffer // This alias is defined for backward compatibility. #endif // BDE_OPENSOURCE_PUBLICATION -- BACKWARD_COMPATIBILITY } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2013 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------