diff --git a/include/etl/memory.h b/include/etl/memory.h index 0cf22460..3c9f576c 100644 --- a/include/etl/memory.h +++ b/include/etl/memory.h @@ -37,6 +37,7 @@ SOFTWARE. #include "iterator.h" #include "utility.h" #include "nullptr.h" +#include "alignment.h" #include @@ -1900,6 +1901,156 @@ namespace etl memory_clear(static_cast(*this)); } }; + + //*************************************************************************** + /// Declares an aligned buffer of N_OBJECTS x of size OBJECT_SIZE at alignment ALIGNMENT. + ///\ingroup alignment + //*************************************************************************** + template + class uninitialized_buffer + { + public: + + static ETL_CONSTANT size_t OBJECT_SIZE = OBJECT_SIZE_; + static ETL_CONSTANT size_t N_OBJECTS = N_OBJECTS_; + static ETL_CONSTANT size_t ALIGNMENT = ALIGNMENT_; + + /// Convert to T reference. + template + operator T& () + { + ETL_STATIC_ASSERT((etl::is_same::value || ((ALIGNMENT % etl::alignment_of::value) == 0)), "Incompatible alignment"); + return *reinterpret_cast(raw); + } + + /// Convert to const T reference. + template + operator const T& () const + { + ETL_STATIC_ASSERT((etl::is_same::value || ((ALIGNMENT % etl::alignment_of::value) == 0)), "Incompatible alignment"); + return *reinterpret_cast(raw); + } + + /// Convert to T pointer. + template + operator T* () + { + ETL_STATIC_ASSERT((etl::is_same::value || ((ALIGNMENT % etl::alignment_of::value) == 0)), "Incompatible alignment"); + return reinterpret_cast(raw); + } + + /// Convert to const T pointer. + template + operator const T* () const + { + ETL_STATIC_ASSERT((etl::is_same::value || ((ALIGNMENT % etl::alignment_of::value) == 0)), "Incompatible alignment"); + return reinterpret_cast(raw); + } + +#if ETL_CPP11_SUPPORTED && !defined(ETL_COMPILER_ARM5) && !defined(ETL_UNINITIALIZED_BUFFER_FORCE_CPP03) + alignas(ALIGNMENT) char raw[OBJECT_SIZE * N_OBJECTS]; +#else + union + { + char raw[OBJECT_SIZE * N_OBJECTS]; + typename etl::type_with_alignment::type etl_alignment_type; // A POD type that has the same alignment as ALIGNMENT. + }; +#endif + }; + + //*************************************************************************** + /// Declares an aligned buffer of N_OBJECTS as if they were type T. + ///\ingroup alignment + //*************************************************************************** + template + class uninitialized_buffer_of + { + public: + + typedef T value_type; + typedef T& reference; + typedef const T& const_reference; + typedef T* pointer; + typedef const T* const_pointer; + typedef T* iterator; + typedef const T* const_iterator; + + static ETL_CONSTANT size_t OBJECT_SIZE = sizeof(T); + static ETL_CONSTANT size_t N_OBJECTS = N_OBJECTS_; + static ETL_CONSTANT size_t ALIGNMENT = etl::alignment_of::value; + + /// Index operator. + T& operator [](int i) + { + return ((T*)this->raw)[i]; + } + + /// Index operator. + const T& operator [](int i) const + { + return ((T*)this->raw)[i]; + } + + /// Convert to T reference. + operator T& () + { + return *reinterpret_cast(raw); + } + + /// Convert to const T reference. + operator const T& () const + { + return *reinterpret_cast(raw); + } + + /// Convert to T pointer. + operator T* () + + { + return reinterpret_cast(raw); + } + + /// Convert to const T pointer. + operator const T* () const + { + return reinterpret_cast(raw); + } + + T* begin() + { + return reinterpret_cast(raw); + } + + const T* begin() const + { + return reinterpret_cast(raw); + } + + T* end() + { + return reinterpret_cast(raw + (sizeof(T) * N_OBJECTS)); + } + + const T* end() const + { + return reinterpret_cast(raw + (sizeof(T) * N_OBJECTS)); + } + +#if ETL_CPP11_SUPPORTED && !defined(ETL_COMPILER_ARM5) && !defined(ETL_UNINITIALIZED_BUFFER_FORCE_CPP03) + alignas(ALIGNMENT) char raw[sizeof(T) * N_OBJECTS]; +#else + union + { + char raw[sizeof(T) * N_OBJECTS]; + typename etl::type_with_alignment::type etl_alignment_type; // A POD type that has the same alignment as ALIGNMENT. + }; +#endif + }; + +#if ETL_CPP14_SUPPORTED + template + using uninitialized_buffer_of_v = typename uninitialized_buffer_of::buffer; +#endif } #endif diff --git a/test/test_memory.cpp b/test/test_memory.cpp index 68f86d43..73962a9e 100644 --- a/test/test_memory.cpp +++ b/test/test_memory.cpp @@ -1040,5 +1040,50 @@ namespace CHECK_EQUAL(6, up1[2]); CHECK_EQUAL(7, up1[3]); } + + //************************************************************************* + TEST(test_uninitialized_buffer) + { + typedef etl::uninitialized_buffer> storage32_t; + + size_t alignment = etl::alignment_of_v; + size_t expected = std::alignment_of_v; + + CHECK_EQUAL(expected, alignment); + } + + //************************************************************************* + TEST(test_uninitialized_buffer_of) + { + typedef etl::uninitialized_buffer_of storage32_t; + static storage32_t buffer; + + uint32_t* i = buffer; + const uint32_t* ci = buffer; + + CHECK(i == ci); + + buffer[0] = 0U; + buffer[1] = 1U; + buffer[2] = 2U; + buffer[3] = 3U; + + CHECK_EQUAL(0U, buffer[0]); + CHECK_EQUAL(1U, buffer[1]); + CHECK_EQUAL(2U, buffer[2]); + CHECK_EQUAL(3U, buffer[3]); + + const storage32_t& refbuffer = buffer; + + CHECK_EQUAL(0U, refbuffer[0]); + CHECK_EQUAL(1U, refbuffer[1]); + CHECK_EQUAL(2U, refbuffer[2]); + CHECK_EQUAL(3U, refbuffer[3]); + + size_t alignment = etl::alignment_of_v; + size_t expected = std::alignment_of_v; + + CHECK_EQUAL(expected, alignment); + } }; }