Complete rewrite of aligned storage functionality and subsequent changes to the containers.

This commit is contained in:
jwellbelove 2015-03-15 16:29:46 +00:00
parent b7180770f5
commit 410109d72c
12 changed files with 229 additions and 114 deletions

View File

@ -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 <stdint.h>
///\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 <typename T, const size_t ALIGNMENT>
struct align_at;
/// Align 1
template <typename T>
struct align_at<T, 1>
{
namespace __private_alignment__
{
ETL_ALIGNMENT_PRE(1) T value ETL_ALIGNMENT_POST(1);
//***************************************************************************
// Matcher.
//***************************************************************************
template <const bool IS_MATCH, const size_t ALIGNMENT, typename T1 = void, typename T2 = void, typename T3 = void, typename T4 = void, typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void>
class type_with_alignment_matcher;
// Matching alignment.
template <const size_t ALIGNMENT, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
class type_with_alignment_matcher <true, ALIGNMENT, T1, T2, T3, T4, T5, T6, T7, T8>
{
public:
typedef T1 type;
};
// Non-matching alignment.
template <const size_t ALIGNMENT, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
class type_with_alignment_matcher <false, ALIGNMENT, T1, T2, T3, T4, T5, T6, T7, T8>
{
public:
typedef typename type_with_alignment_matcher<ALIGNMENT == etl::alignment_of<T2>::value, ALIGNMENT, T2, T3, T4, T5, T6, T7, T8, void>::type type;
};
// Non-matching alignment, non left.
template <const size_t ALIGNMENT>
class type_with_alignment_matcher <false, ALIGNMENT, void, void, void, void, void, void, void, void>
{
public:
};
//***************************************************************************
// Helper.
//***************************************************************************
template <const size_t ALIGNMENT, typename T1, typename T2 = void, typename T3 = void, typename T4 = void, typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void>
class type_with_alignment_helper
{
public:
typedef typename type_with_alignment_matcher<ALIGNMENT == etl::alignment_of<T1>::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 <const size_t ALIGNMENT>
class type_with_alignment
{
public:
typedef typename __private_alignment__::type_with_alignment_helper<ALIGNMENT, int8_t, int16_t, int32_t, int64_t, float, double, void*>::type type;
};
/// Align 2
template <typename T>
struct align_at<T, 2>
//***************************************************************************
/// Aligned storage
///\ingroup alignment
//***************************************************************************
template <const size_t LENGTH, const size_t ALIGNMENT>
struct aligned_storage
{
ETL_ALIGNMENT_PRE(2) T value ETL_ALIGNMENT_POST(2);
struct type
{
/// Convert to T reference.
template <typename T>
operator T& ()
{
STATIC_ASSERT(ALIGNMENT % etl::alignment_of<T>::value == 0, "Incompatible alignment");
return reinterpret_cast<T&>(*data);
}
/// Convert to const T reference.
template <typename T>
operator const T& () const
{
STATIC_ASSERT(ALIGNMENT % etl::alignment_of<T>::value == 0, "Incompatible alignment");
return reinterpret_cast<const T&>(*data);
}
/// Convert to T pointer.
template <typename T>
operator T* ()
{
STATIC_ASSERT(ALIGNMENT % etl::alignment_of<T>::value == 0, "Incompatible alignment");
return reinterpret_cast<T*>(data);
}
/// Convert to const T pointer.
template <typename T>
operator const T* () const
{
STATIC_ASSERT(ALIGNMENT % etl::alignment_of<T>::value == 0, "Incompatible alignment");
return reinterpret_cast<const T*>(data);
}
/// Get address as T reference.
template <typename T>
T* get_reference()
{
STATIC_ASSERT(ALIGNMENT % etl::alignment_of<T>::value == 0, "Incompatible alignment");
return reinterpret_cast<T&>(*data);
}
/// Get address as const T reference.
template <typename T>
const T* get_reference() const
{
STATIC_ASSERT(ALIGNMENT % etl::alignment_of<T>::value == 0, "Incompatible alignment");
return reinterpret_cast<const T&>(*data);
}
/// Get address as T pointer.
template <typename T>
T* get_address()
{
STATIC_ASSERT(ALIGNMENT % etl::alignment_of<T>::value == 0, "Incompatible alignment");
return reinterpret_cast<T*>(data);
}
/// Get address as const T pointer.
template <typename T>
const T* get_address() const
{
STATIC_ASSERT(ALIGNMENT % etl::alignment_of<T>::value == 0, "Incompatible alignment");
return reinterpret_cast<const T*>(data);
}
union
{
uint8_t data[LENGTH];
typename etl::type_with_alignment<ALIGNMENT>::type __etl_alignment_type__; // A POD type has has the same alignment as ALIGNMENT.
};
};
};
/// Align 4
template <typename T>
struct align_at<T, 4>
{
ETL_ALIGNMENT_PRE(4) T value ETL_ALIGNMENT_POST(4);
};
/// Align 8
template <typename T>
struct align_at<T, 8>
{
ETL_ALIGNMENT_PRE(8) T value ETL_ALIGNMENT_POST(8);
};
/// Align 16
template <typename T>
struct align_at<T, 16>
{
ETL_ALIGNMENT_PRE(16) T value ETL_ALIGNMENT_POST(16);
};
/// Align As
template <typename TValue, typename TAlign>
struct align_as : public align_at<TValue, etl::alignment_of<TAlign>::value>
//***************************************************************************
/// Aligned storage as
///\ingroup alignment
//***************************************************************************
template <const size_t LENGTH, typename T>
struct aligned_storage_as : public etl::aligned_storage<LENGTH, etl::alignment_of<T>::value>
{
};
}
#endif
#undef ETL_ALIGNMENT_PRE
#undef ETL_ALIGNMENT_POST
#endif

View File

@ -42,7 +42,10 @@ namespace etl
{
public:
static const size_t npos = etl::integral_limits<size_t>::max;
enum
{
npos = etl::integral_limits<size_t>::max
};
//*************************************************************************
/// Default constructor.

View File

@ -81,7 +81,7 @@ namespace etl
typedef typename std::iterator_traits<iterator>::difference_type difference_type;
protected:
typedef typename parameter_type<TKey>::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.

View File

@ -376,6 +376,19 @@ namespace etl
template <typename TIterator>
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;

13
ilist.h
View File

@ -480,6 +480,19 @@ namespace etl
template <typename TIterator>
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.

View File

@ -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 <typename TIterator>
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<size_t>(count) > MAX_SIZE)
if (static_cast<size_t>(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)
{

2
map.h
View File

@ -67,7 +67,7 @@ namespace etl
//*************************************************************************
/// Copy constructor.
//*************************************************************************
explicit map(const map& other)
map(const map& other)
: imap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
{
imap<TKey, TValue, TCompare>::assign(other.cbegin(), other.cend());

4
pool.h
View File

@ -60,7 +60,7 @@ namespace etl
/// Constructor
//*************************************************************************
pool()
: ipool<T>(reinterpret_cast<T*>(&aligned_buffer.value[0]), in_use, SIZE)
: ipool<T>(reinterpret_cast<T*>(&buffer[0]), in_use, SIZE)
{
}
@ -75,7 +75,7 @@ namespace etl
private:
///< The memory for the pool of objects.
etl::align_as<etl::array<uint8_t, SIZE * sizeof(T)>, T> aligned_buffer;
typename etl::aligned_storage<sizeof(T), etl::alignment_of<T>::value>::type buffer[SIZE];
///< The set of flags that indicate which items are free in the pool.
bitset<SIZE> in_use;

View File

@ -63,7 +63,7 @@ namespace etl
/// Default constructor.
//*************************************************************************
queue()
: iqueue<T>(reinterpret_cast<T*>(&buffer.value[0]), SIZE)
: iqueue<T>(reinterpret_cast<T*>(&buffer[0]), SIZE)
{
}
@ -71,7 +71,7 @@ namespace etl
/// Copy constructor
//*************************************************************************
queue(const queue& rhs)
: iqueue<T>(reinterpret_cast<T*>(&buffer.value[0]), SIZE)
: iqueue<T>(reinterpret_cast<T*>(&buffer[0]), SIZE)
{
iqueue<T>::clone(rhs);
}
@ -100,7 +100,7 @@ namespace etl
private:
/// The unititialised buffer of T used in the stack.
etl::align_as<array<uint8_t, SIZE * sizeof(T)>, T> buffer;
typename etl::aligned_storage<sizeof(T), etl::alignment_of<T>::value>::type buffer[SIZE];
};
}

View File

@ -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<T>(reinterpret_cast<T*>(&buffer.value[0]), SIZE)
: istack<T>(reinterpret_cast<T*>(&buffer[0]), SIZE)
{
}
@ -72,7 +72,7 @@ namespace etl
/// Copy constructor
//*************************************************************************
stack(const stack& rhs)
: istack<T>(reinterpret_cast<T*>(&buffer.value[0]), SIZE)
: istack<T>(reinterpret_cast<T*>(&buffer[0]), SIZE)
{
istack<T>::clone(rhs);
}
@ -101,7 +101,7 @@ namespace etl
private:
/// The unititialised buffer of T used in the stack.
etl::align_as<array<uint8_t, SIZE * sizeof(T)>, T> buffer;
typename etl::aligned_storage<sizeof(T), etl::alignment_of<T>::value>::type buffer[SIZE];
};
}

View File

@ -816,7 +816,7 @@ namespace etl
{
STATIC_ASSERT(Type_Is_Supported<T>::value, "Unsupported type");
new(&data.value[0]) T(value);
new(static_cast<T*>(data)) T(value);
type_id = Type_Id_Lookup<T>::type_id;
}
@ -839,7 +839,7 @@ namespace etl
{
STATIC_ASSERT(Type_Is_Supported<T>::value, "Unsupported type");
new(&data.value[0]) T(value);
new(data) T(value);
type_id = Type_Id_Lookup<T>::type_id;
return *this;
}
@ -894,14 +894,14 @@ namespace etl
{
switch (type_id)
{
case 0: reader.read(reinterpret_cast<T1&>(*&data.value[0])); break;
case 1: reader.read(reinterpret_cast<T2&>(*&data.value[0])); break;
case 2: reader.read(reinterpret_cast<T3&>(*&data.value[0])); break;
case 3: reader.read(reinterpret_cast<T4&>(*&data.value[0])); break;
case 4: reader.read(reinterpret_cast<T5&>(*&data.value[0])); break;
case 5: reader.read(reinterpret_cast<T6&>(*&data.value[0])); break;
case 6: reader.read(reinterpret_cast<T7&>(*&data.value[0])); break;
case 7: reader.read(reinterpret_cast<T8&>(*&data.value[0])); break;
case 0: reader.read(static_cast<T1&>(data)); break;
case 1: reader.read(static_cast<T2&>(data)); break;
case 2: reader.read(static_cast<T3&>(data)); break;
case 3: reader.read(static_cast<T4&>(data)); break;
case 4: reader.read(static_cast<T5&>(data)); break;
case 5: reader.read(static_cast<T6&>(data)); break;
case 6: reader.read(static_cast<T7&>(data)); break;
case 7: reader.read(static_cast<T8&>(data)); break;
default:
#ifdef ETL_THROW_EXCEPTIONS
throw variant_invalid_type_id_exception();
@ -958,7 +958,7 @@ namespace etl
#endif
}
return reinterpret_cast<T&>(*&data.value[0]);
return static_cast<T&>(data);
}
//***************************************************************************
@ -980,7 +980,7 @@ namespace etl
#endif
}
return reinterpret_cast<const T&>(*&data.value[0]);
return static_cast<const T&>(data);
}
//***************************************************************************
@ -990,7 +990,7 @@ namespace etl
template <typename TBase>
TBase& upcast()
{
return upcast_functor<TBase, T1, T2, T3, T4, T5, T6, T7, T8>()(&data.value[0], type_id);
return upcast_functor<TBase, T1, T2, T3, T4, T5, T6, T7, T8>()(data, type_id);
}
//***************************************************************************
@ -1000,7 +1000,7 @@ namespace etl
template <typename TBase>
const TBase& upcast() const
{
return upcast_functor<TBase, T1, T2, T3, T4, T5, T6, T7, T8>()(&data.value[0], type_id);
return upcast_functor<TBase, T1, T2, T3, T4, T5, T6, T7, T8>()(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<array<uint8_t, sizeof(largest_t)>, ALIGNMENT> data;
typename etl::aligned_storage<sizeof(largest_t), etl::alignment_of<largest_t>::value>::type data;
//***************************************************************************
/// The id of the current stored type.

View File

@ -64,7 +64,7 @@ namespace etl
/// Constructor.
//*************************************************************************
vector()
: ivector<T>(reinterpret_cast<T*>(&buffer.value[0]), MAX_SIZE)
: ivector<T>(reinterpret_cast<T*>(&buffer[0]), MAX_SIZE)
{
}
@ -73,7 +73,7 @@ namespace etl
///\param initialSize The initial size of the vector.
//*************************************************************************
explicit vector(size_t initialSize)
: ivector<T>(reinterpret_cast<T*>(&buffer.value[0]), MAX_SIZE)
: ivector<T>(reinterpret_cast<T*>(&buffer[0]), MAX_SIZE)
{
ivector<T>::resize(initialSize);
}
@ -84,7 +84,7 @@ namespace etl
///\param value The value to fill the vector with.
//*************************************************************************
vector(size_t initialSize, typename ivector<T>::parameter_t value)
: ivector<T>(reinterpret_cast<T*>(&buffer.value[0]), MAX_SIZE)
: ivector<T>(reinterpret_cast<T*>(&buffer[0]), MAX_SIZE)
{
ivector<T>::resize(initialSize, value);
}
@ -97,7 +97,7 @@ namespace etl
//*************************************************************************
template <typename TIterator>
vector(TIterator first, TIterator last)
: ivector<T>(reinterpret_cast<T*>(&buffer.value[0]), MAX_SIZE)
: ivector<T>(reinterpret_cast<T*>(&buffer[0]), MAX_SIZE)
{
ivector<T>::assign(first, last);
}
@ -117,7 +117,7 @@ namespace etl
private:
etl::align_as<array<uint8_t, MAX_SIZE * sizeof(T)>, T> buffer;
typename etl::aligned_storage<sizeof(T) * MAX_SIZE, etl::alignment_of<T>::value>::type buffer[MAX_SIZE];
};
}