From 410109d72c262d642e5097e113d36d557cf8e863 Mon Sep 17 00:00:00 2001 From: jwellbelove Date: Sun, 15 Mar 2015 16:29:46 +0000 Subject: [PATCH] Complete rewrite of aligned storage functionality and subsequent changes to the containers. --- alignment.h | 205 ++++++++++++++++++++++++++++++++++-------------- ibitset.h | 5 +- iflat_map.h | 4 +- iforward_list.h | 13 +++ ilist.h | 13 +++ ivector.h | 43 +++++----- map.h | 2 +- pool.h | 4 +- queue.h | 6 +- stack.h | 8 +- variant.h | 30 +++---- vector.h | 10 +-- 12 files changed, 229 insertions(+), 114 deletions(-) diff --git a/alignment.h b/alignment.h index b4467c4f..2b143e8e 100644 --- a/alignment.h +++ b/alignment.h @@ -4,6 +4,7 @@ The MIT License(MIT) Embedded Template Library. +https://github.com/ETLCPP/etl Copyright(c) 2014 jwellbelove @@ -29,79 +30,163 @@ SOFTWARE. #ifndef __ETL_ALIGNEMENT__ #define __ETL_ALIGNEMENT__ -#include "type_traits.h" +#include -///\defgroup align_at align_at +#include "type_traits.h" +#include "static_assert.h" + +///\defgroup alignment alignment /// Creates a variable of the specified type at the specified alignment. /// \ingroup utilities -#if !defined(COMPILER_IAR) - -#if defined(COMPILER_MICROSOFT) -#define ETL_ALIGNMENT_PRE(n) __declspec(align(n)) -#define ETL_ALIGNMENT_POST(n) -#endif - -#if defined(COMPILER_GCC) -#define ETL_ALIGNMENT_PRE(n) -#define ETL_ALIGNMENT_POST(n) __attribute__((aligned(n))) -#endif - -#if defined (COMPILER_KEIL) -#define ETL_ALIGNMENT_PRE(n) -#define ETL_ALIGNMENT_POST(n) __attribute__((aligned(n))) -#endif - namespace etl -{ - /// Template declaration. - template - struct align_at; - - /// Align 1 - template - struct align_at +{ + namespace __private_alignment__ { - ETL_ALIGNMENT_PRE(1) T value ETL_ALIGNMENT_POST(1); + //*************************************************************************** + // Matcher. + //*************************************************************************** + template + class type_with_alignment_matcher; + + // Matching alignment. + template + class type_with_alignment_matcher + { + public: + + typedef T1 type; + }; + + // Non-matching alignment. + template + class type_with_alignment_matcher + { + public: + + typedef typename type_with_alignment_matcher::value, ALIGNMENT, T2, T3, T4, T5, T6, T7, T8, void>::type type; + }; + + // Non-matching alignment, non left. + template + class type_with_alignment_matcher + { + public: + }; + + //*************************************************************************** + // Helper. + //*************************************************************************** + template + class type_with_alignment_helper + { + public: + + typedef typename type_with_alignment_matcher::value, ALIGNMENT, T1, T2, T3, T4, T5, T6, T7, T8>::type type; + }; + } + + //*************************************************************************** + /// Gets a type that has the same as the specified alignment. + ///\ingroup alignment + //*************************************************************************** + template + class type_with_alignment + { + public: + + typedef typename __private_alignment__::type_with_alignment_helper::type type; }; - /// Align 2 - template - struct align_at + //*************************************************************************** + /// Aligned storage + ///\ingroup alignment + //*************************************************************************** + template + struct aligned_storage { - ETL_ALIGNMENT_PRE(2) T value ETL_ALIGNMENT_POST(2); + struct type + { + /// Convert to T reference. + template + operator T& () + { + STATIC_ASSERT(ALIGNMENT % etl::alignment_of::value == 0, "Incompatible alignment"); + return reinterpret_cast(*data); + } + + /// Convert to const T reference. + template + operator const T& () const + { + STATIC_ASSERT(ALIGNMENT % etl::alignment_of::value == 0, "Incompatible alignment"); + return reinterpret_cast(*data); + } + + /// Convert to T pointer. + template + operator T* () + { + STATIC_ASSERT(ALIGNMENT % etl::alignment_of::value == 0, "Incompatible alignment"); + return reinterpret_cast(data); + } + + /// Convert to const T pointer. + template + operator const T* () const + { + STATIC_ASSERT(ALIGNMENT % etl::alignment_of::value == 0, "Incompatible alignment"); + return reinterpret_cast(data); + } + + /// Get address as T reference. + template + T* get_reference() + { + STATIC_ASSERT(ALIGNMENT % etl::alignment_of::value == 0, "Incompatible alignment"); + return reinterpret_cast(*data); + } + + /// Get address as const T reference. + template + const T* get_reference() const + { + STATIC_ASSERT(ALIGNMENT % etl::alignment_of::value == 0, "Incompatible alignment"); + return reinterpret_cast(*data); + } + + /// Get address as T pointer. + template + T* get_address() + { + STATIC_ASSERT(ALIGNMENT % etl::alignment_of::value == 0, "Incompatible alignment"); + return reinterpret_cast(data); + } + + /// Get address as const T pointer. + template + const T* get_address() const + { + STATIC_ASSERT(ALIGNMENT % etl::alignment_of::value == 0, "Incompatible alignment"); + return reinterpret_cast(data); + } + + union + { + uint8_t data[LENGTH]; + typename etl::type_with_alignment::type __etl_alignment_type__; // A POD type has has the same alignment as ALIGNMENT. + }; + }; }; - /// Align 4 - template - struct align_at - { - ETL_ALIGNMENT_PRE(4) T value ETL_ALIGNMENT_POST(4); - }; - - /// Align 8 - template - struct align_at - { - ETL_ALIGNMENT_PRE(8) T value ETL_ALIGNMENT_POST(8); - }; - - /// Align 16 - template - struct align_at - { - ETL_ALIGNMENT_PRE(16) T value ETL_ALIGNMENT_POST(16); - }; - - /// Align As - template - struct align_as : public align_at::value> + //*************************************************************************** + /// Aligned storage as + ///\ingroup alignment + //*************************************************************************** + template + struct aligned_storage_as : public etl::aligned_storage::value> { }; } -#endif - -#undef ETL_ALIGNMENT_PRE -#undef ETL_ALIGNMENT_POST #endif diff --git a/ibitset.h b/ibitset.h index 7923d442..8ca437d8 100644 --- a/ibitset.h +++ b/ibitset.h @@ -42,7 +42,10 @@ namespace etl { public: - static const size_t npos = etl::integral_limits::max; + enum + { + npos = etl::integral_limits::max + }; //************************************************************************* /// Default constructor. diff --git a/iflat_map.h b/iflat_map.h index b6b2b980..ac377172 100644 --- a/iflat_map.h +++ b/iflat_map.h @@ -81,7 +81,7 @@ namespace etl typedef typename std::iterator_traits::difference_type difference_type; protected: - + typedef typename parameter_type::type key_value_parameter_t; private: @@ -499,7 +499,7 @@ namespace etl { return std::lower_bound(cbegin(), cend(), key, compare()); } - + //********************************************************************* /// Finds the upper bound of a key ///\param key The key to search for. diff --git a/iforward_list.h b/iforward_list.h index 18c2bf7f..472860fc 100644 --- a/iforward_list.h +++ b/iforward_list.h @@ -376,6 +376,19 @@ namespace etl template void assign(TIterator first, TIterator last) { +#ifdef _DEBUG + difference_type count = std::distance(first, last); + + if (count < 0) + { +#ifdef ETL_THROW_EXCEPTIONS + throw forward_list_iterator(); +#else + error_handler::error(forward_list_iterator()); +#endif + } +#endif + initialise(); Node* p_last_node = &start_node; diff --git a/ilist.h b/ilist.h index 4709b241..3b48e5b0 100644 --- a/ilist.h +++ b/ilist.h @@ -480,6 +480,19 @@ namespace etl template void assign(TIterator first, TIterator last) { +#ifdef _DEBUG + difference_type count = std::distance(first, last); + + if (count < 0) + { +#ifdef ETL_THROW_EXCEPTIONS + throw list_iterator(); +#else + error_handler::error(list_iterator()); +#endif + } +#endif + initialise(); // Add all of the elements. diff --git a/ivector.h b/ivector.h index f67947a5..9d52a10a 100644 --- a/ivector.h +++ b/ivector.h @@ -83,7 +83,7 @@ namespace etl { return &p_buffer[0]; } - + //********************************************************************* /// Returns a const_iterator to the beginning of the vector. ///\return A const iterator to the beginning of the vector. @@ -91,7 +91,7 @@ namespace etl const_iterator begin() const { return &p_buffer[0]; - } + } //********************************************************************* /// Returns an iterator to the end of the vector. @@ -118,7 +118,7 @@ namespace etl const_iterator cbegin() const { return &p_buffer[0]; - } + } //********************************************************************* /// Returns a const_iterator to the end of the vector. @@ -137,7 +137,7 @@ namespace etl { return reverse_iterator(end()); } - + //********************************************************************* /// Returns a const reverse iterator to the reverse beginning of the vector. ///\return Const iterator to the reverse beginning of the vector. @@ -145,7 +145,7 @@ namespace etl const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); - } + } //********************************************************************* /// Returns a reverse iterator to the end + 1 of the vector. @@ -172,7 +172,7 @@ namespace etl const_reverse_iterator crbegin() const { return const_reverse_iterator(cend()); - } + } //********************************************************************* /// Returns a const reverse iterator to the end + 1 of the vector. @@ -380,8 +380,7 @@ namespace etl template void assign(TIterator first, TIterator last) { - initialise(); - +#ifdef _DEBUG difference_type count = std::distance(first, last); if (count < 0) @@ -389,10 +388,11 @@ namespace etl #ifdef ETL_THROW_EXCEPTIONS throw vector_iterator(); #else - error_handler::error((vector_iterator)); + error_handler::error(vector_iterator()); #endif } - else if (static_cast(count) > MAX_SIZE) + + if (static_cast(count) > MAX_SIZE) { #ifdef ETL_THROW_EXCEPTIONS throw vector_full(); @@ -400,14 +400,15 @@ namespace etl error_handler::error(vector_full()); #endif } - else +#endif + + initialise(); + + // Safe to copy. + while (first != last) { - // Safe to copy. - while (first != last) - { - create_element(*first); - ++first; - } + create_element(*first); + ++first; } } @@ -592,10 +593,10 @@ namespace etl { create_element_at(to++, value); } - + current_size += n_insert; } - } + } } //********************************************************************* @@ -685,7 +686,7 @@ namespace etl //********************************************************************* /// Erases a range of elements. - /// The range includes all the elements between first and last, including the + /// The range includes all the elements between first and last, including the /// element pointed by first, but not the one pointed by last. ///\param first Iterator to the first element. ///\param last Iterator to the last element. @@ -695,7 +696,7 @@ namespace etl { std::copy(last, end(), first); size_t n_delete = std::distance(first, last); - + // Destroy the elements left over at the end. while (n_delete-- > 0) { diff --git a/map.h b/map.h index 968c5a5e..11e78159 100644 --- a/map.h +++ b/map.h @@ -67,7 +67,7 @@ namespace etl //************************************************************************* /// Copy constructor. //************************************************************************* - explicit map(const map& other) + map(const map& other) : imap(node_pool, MAX_SIZE) { imap::assign(other.cbegin(), other.cend()); diff --git a/pool.h b/pool.h index f5cccbec..0cfcfbd8 100644 --- a/pool.h +++ b/pool.h @@ -60,7 +60,7 @@ namespace etl /// Constructor //************************************************************************* pool() - : ipool(reinterpret_cast(&aligned_buffer.value[0]), in_use, SIZE) + : ipool(reinterpret_cast(&buffer[0]), in_use, SIZE) { } @@ -75,7 +75,7 @@ namespace etl private: ///< The memory for the pool of objects. - etl::align_as, T> aligned_buffer; + typename etl::aligned_storage::value>::type buffer[SIZE]; ///< The set of flags that indicate which items are free in the pool. bitset in_use; diff --git a/queue.h b/queue.h index 89665f7d..39baf2c6 100644 --- a/queue.h +++ b/queue.h @@ -63,7 +63,7 @@ namespace etl /// Default constructor. //************************************************************************* queue() - : iqueue(reinterpret_cast(&buffer.value[0]), SIZE) + : iqueue(reinterpret_cast(&buffer[0]), SIZE) { } @@ -71,7 +71,7 @@ namespace etl /// Copy constructor //************************************************************************* queue(const queue& rhs) - : iqueue(reinterpret_cast(&buffer.value[0]), SIZE) + : iqueue(reinterpret_cast(&buffer[0]), SIZE) { iqueue::clone(rhs); } @@ -100,7 +100,7 @@ namespace etl private: /// The unititialised buffer of T used in the stack. - etl::align_as, T> buffer; + typename etl::aligned_storage::value>::type buffer[SIZE]; }; } diff --git a/stack.h b/stack.h index 2025f5c2..ef6922f9 100644 --- a/stack.h +++ b/stack.h @@ -51,7 +51,7 @@ namespace etl //*************************************************************************** ///\ingroup stack /// A fixed capacity stack. - /// This stack does not support concurrent access by different threads. + /// This stack does not suppo7rt concurrent access by different threads. /// \tparam T The type this stack should support. /// \tparam MAX_SIZE The maximum capacity of the stack. //*************************************************************************** @@ -64,7 +64,7 @@ namespace etl /// Default constructor. //************************************************************************* stack() - : istack(reinterpret_cast(&buffer.value[0]), SIZE) + : istack(reinterpret_cast(&buffer[0]), SIZE) { } @@ -72,7 +72,7 @@ namespace etl /// Copy constructor //************************************************************************* stack(const stack& rhs) - : istack(reinterpret_cast(&buffer.value[0]), SIZE) + : istack(reinterpret_cast(&buffer[0]), SIZE) { istack::clone(rhs); } @@ -101,7 +101,7 @@ namespace etl private: /// The unititialised buffer of T used in the stack. - etl::align_as, T> buffer; + typename etl::aligned_storage::value>::type buffer[SIZE]; }; } diff --git a/variant.h b/variant.h index 7b520f49..6998208a 100644 --- a/variant.h +++ b/variant.h @@ -816,7 +816,7 @@ namespace etl { STATIC_ASSERT(Type_Is_Supported::value, "Unsupported type"); - new(&data.value[0]) T(value); + new(static_cast(data)) T(value); type_id = Type_Id_Lookup::type_id; } @@ -839,7 +839,7 @@ namespace etl { STATIC_ASSERT(Type_Is_Supported::value, "Unsupported type"); - new(&data.value[0]) T(value); + new(data) T(value); type_id = Type_Id_Lookup::type_id; return *this; } @@ -894,14 +894,14 @@ namespace etl { switch (type_id) { - case 0: reader.read(reinterpret_cast(*&data.value[0])); break; - case 1: reader.read(reinterpret_cast(*&data.value[0])); break; - case 2: reader.read(reinterpret_cast(*&data.value[0])); break; - case 3: reader.read(reinterpret_cast(*&data.value[0])); break; - case 4: reader.read(reinterpret_cast(*&data.value[0])); break; - case 5: reader.read(reinterpret_cast(*&data.value[0])); break; - case 6: reader.read(reinterpret_cast(*&data.value[0])); break; - case 7: reader.read(reinterpret_cast(*&data.value[0])); break; + case 0: reader.read(static_cast(data)); break; + case 1: reader.read(static_cast(data)); break; + case 2: reader.read(static_cast(data)); break; + case 3: reader.read(static_cast(data)); break; + case 4: reader.read(static_cast(data)); break; + case 5: reader.read(static_cast(data)); break; + case 6: reader.read(static_cast(data)); break; + case 7: reader.read(static_cast(data)); break; default: #ifdef ETL_THROW_EXCEPTIONS throw variant_invalid_type_id_exception(); @@ -958,7 +958,7 @@ namespace etl #endif } - return reinterpret_cast(*&data.value[0]); + return static_cast(data); } //*************************************************************************** @@ -980,7 +980,7 @@ namespace etl #endif } - return reinterpret_cast(*&data.value[0]); + return static_cast(data); } //*************************************************************************** @@ -990,7 +990,7 @@ namespace etl template TBase& upcast() { - return upcast_functor()(&data.value[0], type_id); + return upcast_functor()(data, type_id); } //*************************************************************************** @@ -1000,7 +1000,7 @@ namespace etl template const TBase& upcast() const { - return upcast_functor()(&data.value[0], type_id); + return upcast_functor()(data, type_id); } //*************************************************************************** @@ -1031,7 +1031,7 @@ namespace etl /// The internal storage. /// Aligned on a suitable boundary, which should be good for all types. //*************************************************************************** - align_at, ALIGNMENT> data; + typename etl::aligned_storage::value>::type data; //*************************************************************************** /// The id of the current stored type. diff --git a/vector.h b/vector.h index b93fb190..4575fdeb 100644 --- a/vector.h +++ b/vector.h @@ -64,7 +64,7 @@ namespace etl /// Constructor. //************************************************************************* vector() - : ivector(reinterpret_cast(&buffer.value[0]), MAX_SIZE) + : ivector(reinterpret_cast(&buffer[0]), MAX_SIZE) { } @@ -73,7 +73,7 @@ namespace etl ///\param initialSize The initial size of the vector. //************************************************************************* explicit vector(size_t initialSize) - : ivector(reinterpret_cast(&buffer.value[0]), MAX_SIZE) + : ivector(reinterpret_cast(&buffer[0]), MAX_SIZE) { ivector::resize(initialSize); } @@ -84,7 +84,7 @@ namespace etl ///\param value The value to fill the vector with. //************************************************************************* vector(size_t initialSize, typename ivector::parameter_t value) - : ivector(reinterpret_cast(&buffer.value[0]), MAX_SIZE) + : ivector(reinterpret_cast(&buffer[0]), MAX_SIZE) { ivector::resize(initialSize, value); } @@ -97,7 +97,7 @@ namespace etl //************************************************************************* template vector(TIterator first, TIterator last) - : ivector(reinterpret_cast(&buffer.value[0]), MAX_SIZE) + : ivector(reinterpret_cast(&buffer[0]), MAX_SIZE) { ivector::assign(first, last); } @@ -117,7 +117,7 @@ namespace etl private: - etl::align_as, T> buffer; + typename etl::aligned_storage::value>::type buffer[MAX_SIZE]; }; }