mirror of
https://github.com/ETLCPP/etl.git
synced 2026-11-09 14:49:53 +08:00
Performance enhancements
This commit is contained in:
parent
0508d796bc
commit
46a11d1747
706
src/ivector.h
706
src/ivector.h
@ -43,6 +43,7 @@ SOFTWARE.
|
||||
#include "type_traits.h"
|
||||
#include "parameter_type.h"
|
||||
#include "error_handler.h"
|
||||
#include "memory.h"
|
||||
|
||||
#ifdef ETL_COMPILER_GCC
|
||||
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
@ -72,14 +73,6 @@ namespace etl
|
||||
typedef size_t size_type;
|
||||
typedef typename std::iterator_traits<iterator>::difference_type difference_type;
|
||||
|
||||
private:
|
||||
|
||||
// Type trait to allow selection of simple algorithms for simple types.
|
||||
template <typename U>
|
||||
struct is_simple_type : integral_constant<bool, etl::is_fundamental<U>::value || etl::is_pointer<U>::value>
|
||||
{
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
typedef typename parameter_type<T>::type parameter_t;
|
||||
@ -92,7 +85,7 @@ namespace etl
|
||||
//*********************************************************************
|
||||
iterator begin()
|
||||
{
|
||||
return &p_buffer[0];
|
||||
return p_buffer;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
@ -101,7 +94,7 @@ namespace etl
|
||||
//*********************************************************************
|
||||
const_iterator begin() const
|
||||
{
|
||||
return &p_buffer[0];
|
||||
return p_buffer;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
@ -110,7 +103,7 @@ namespace etl
|
||||
//*********************************************************************
|
||||
iterator end()
|
||||
{
|
||||
return &p_buffer[current_size];
|
||||
return p_end;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
@ -119,7 +112,7 @@ namespace etl
|
||||
//*********************************************************************
|
||||
const_iterator end() const
|
||||
{
|
||||
return &p_buffer[current_size];
|
||||
return p_end;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
@ -128,7 +121,7 @@ namespace etl
|
||||
//*********************************************************************
|
||||
const_iterator cbegin() const
|
||||
{
|
||||
return &p_buffer[0];
|
||||
return p_buffer;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
@ -137,7 +130,7 @@ namespace etl
|
||||
//*********************************************************************
|
||||
const_iterator cend() const
|
||||
{
|
||||
return &p_buffer[current_size];
|
||||
return p_end;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
@ -202,42 +195,7 @@ namespace etl
|
||||
//*********************************************************************
|
||||
void resize(size_t new_size)
|
||||
{
|
||||
ETL_ASSERT(new_size <= MAX_SIZE, ETL_ERROR(vector_full));
|
||||
|
||||
// Choose the algorithm according to type.
|
||||
// The unused branch should be optimised away.
|
||||
if (is_simple_type<value_type>::value)
|
||||
{
|
||||
// Size up if necessary.
|
||||
if (current_size < new_size)
|
||||
{
|
||||
std::fill_n(&p_buffer[current_size], new_size - current_size, 0);
|
||||
}
|
||||
|
||||
current_size = new_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Size up or size down?
|
||||
if (new_size > current_size)
|
||||
{
|
||||
// Up.
|
||||
while (current_size < new_size)
|
||||
{
|
||||
create_element();
|
||||
}
|
||||
}
|
||||
else if (new_size < current_size)
|
||||
{
|
||||
// Down.
|
||||
while (current_size > new_size)
|
||||
{
|
||||
destroy_element();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
resize(new_size, T());
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
@ -247,42 +205,65 @@ namespace etl
|
||||
///\param new_size The new size.
|
||||
///\param value The value to fill new elements with. Default = default constructed value.
|
||||
//*********************************************************************
|
||||
void resize(size_t new_size, T value)
|
||||
template <typename U = T>
|
||||
typename etl::enable_if<etl::has_trivial_constructor<U>::value, void>::type
|
||||
resize(size_t new_size, T value)
|
||||
{
|
||||
ETL_ASSERT(new_size <= MAX_SIZE, ETL_ERROR(vector_full));
|
||||
|
||||
// Choose the algorithm according to type.
|
||||
// The unused branch should be optimised away.
|
||||
if (is_simple_type<value_type>::value)
|
||||
{
|
||||
// Size up if necessary.
|
||||
if (current_size < new_size)
|
||||
{
|
||||
std::fill_n(&p_buffer[current_size], new_size - current_size, value);
|
||||
}
|
||||
const size_t current_size = size();
|
||||
size_t delta = (current_size < new_size) ? new_size - current_size : current_size - new_size;
|
||||
|
||||
current_size = new_size;
|
||||
if (current_size < new_size)
|
||||
{
|
||||
std::fill_n(p_end, delta, value);
|
||||
#if defined(ETL_DEBUG)
|
||||
construct_count += delta;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// Size up or size down?
|
||||
if (new_size > current_size)
|
||||
{
|
||||
// Up.
|
||||
while (current_size < new_size)
|
||||
{
|
||||
create_element(value);
|
||||
}
|
||||
}
|
||||
else if (new_size < current_size)
|
||||
{
|
||||
// Down.
|
||||
while (current_size > new_size)
|
||||
{
|
||||
destroy_element();
|
||||
}
|
||||
}
|
||||
p_end -= delta;
|
||||
#if defined(ETL_DEBUG)
|
||||
construct_count -= delta;
|
||||
#endif
|
||||
}
|
||||
|
||||
p_end = p_buffer + new_size;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
/// Resizes the vector.
|
||||
/// If asserts or exceptions are enabled and the new size is larger than the
|
||||
/// maximum then a vector_full is thrown.
|
||||
///\param new_size The new size.
|
||||
///\param value The value to fill new elements with. Default = default constructed value.
|
||||
//*********************************************************************
|
||||
template <typename U = T>
|
||||
typename etl::enable_if<!etl::has_trivial_constructor<U>::value, void>::type
|
||||
resize(size_t new_size, T value)
|
||||
{
|
||||
ETL_ASSERT(new_size <= MAX_SIZE, ETL_ERROR(vector_full));
|
||||
|
||||
const size_t current_size = size();
|
||||
size_t delta = (current_size < new_size) ? new_size - current_size : current_size - new_size;
|
||||
|
||||
if (current_size < new_size)
|
||||
{
|
||||
etl::uninitialized_fill_n(p_end, delta, value);
|
||||
#if defined(ETL_DEBUG)
|
||||
construct_count += delta;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
etl::destroy_n(p_end - delta, delta);
|
||||
#if defined(ETL_DEBUG)
|
||||
construct_count -= delta;
|
||||
#endif
|
||||
}
|
||||
|
||||
p_end = p_buffer + new_size;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
@ -320,7 +301,7 @@ namespace etl
|
||||
//*********************************************************************
|
||||
reference at(size_t i)
|
||||
{
|
||||
ETL_ASSERT(i < current_size, ETL_ERROR(vector_out_of_bounds));
|
||||
ETL_ASSERT(i < size(), ETL_ERROR(vector_out_of_bounds));
|
||||
return p_buffer[i];
|
||||
}
|
||||
|
||||
@ -332,7 +313,7 @@ namespace etl
|
||||
//*********************************************************************
|
||||
const_reference at(size_t i) const
|
||||
{
|
||||
ETL_ASSERT(i < current_size, ETL_ERROR(vector_out_of_bounds));
|
||||
ETL_ASSERT(i < size(), ETL_ERROR(vector_out_of_bounds));
|
||||
return p_buffer[i];
|
||||
}
|
||||
|
||||
@ -342,7 +323,7 @@ namespace etl
|
||||
//*********************************************************************
|
||||
reference front()
|
||||
{
|
||||
return p_buffer[0];
|
||||
return *p_buffer;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
@ -351,7 +332,7 @@ namespace etl
|
||||
//*********************************************************************
|
||||
const_reference front() const
|
||||
{
|
||||
return p_buffer[0];
|
||||
return *p_buffer;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
@ -360,7 +341,7 @@ namespace etl
|
||||
//*********************************************************************
|
||||
reference back()
|
||||
{
|
||||
return p_buffer[current_size - 1];
|
||||
return *(p_end - 1);
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
@ -369,7 +350,7 @@ namespace etl
|
||||
//*********************************************************************
|
||||
const_reference back() const
|
||||
{
|
||||
return p_buffer[current_size - 1];
|
||||
return *(p_end - 1);
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
@ -400,34 +381,18 @@ namespace etl
|
||||
template <typename TIterator>
|
||||
void assign(TIterator first, TIterator last)
|
||||
{
|
||||
#if defined(_DEBUG) || defined(DEBUG)
|
||||
#if defined(ETL_DEBUG)
|
||||
difference_type count = std::distance(first, last);
|
||||
ETL_ASSERT(static_cast<size_t>(count) <= MAX_SIZE, ETL_ERROR(vector_full));
|
||||
#endif
|
||||
|
||||
initialise();
|
||||
|
||||
// Choose the algorithm according to type.
|
||||
// The unused branch should be optimised away.
|
||||
if (is_simple_type<value_type>::value)
|
||||
{
|
||||
while (first != last)
|
||||
{
|
||||
p_buffer[current_size++] = *first++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
T* p = &p_buffer[0];
|
||||
while (first != last)
|
||||
{
|
||||
new (p) T(*first);
|
||||
++p;
|
||||
++first;
|
||||
++current_size;
|
||||
++construct_count;
|
||||
}
|
||||
}
|
||||
#if defined(ETL_DEBUG)
|
||||
p_end = etl::uninitialized_copy(first, last, p_buffer, construct_count);
|
||||
#else
|
||||
p_end = etl::uninitialized_copy(first, last, p_buffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
@ -438,32 +403,15 @@ namespace etl
|
||||
//*********************************************************************
|
||||
void assign(size_t n, parameter_t value)
|
||||
{
|
||||
initialise();
|
||||
|
||||
ETL_ASSERT(n <= MAX_SIZE, ETL_ERROR(vector_full));
|
||||
|
||||
// Choose the algorithm according to type.
|
||||
// The unused branch should be optimised away.
|
||||
if (is_simple_type<value_type>::value)
|
||||
{
|
||||
while (n > 0)
|
||||
{
|
||||
p_buffer[current_size++] = value;
|
||||
--n;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
T* p = &p_buffer[0];
|
||||
while (n > 0)
|
||||
{
|
||||
new (p) T(value);
|
||||
++p;
|
||||
--n;
|
||||
++current_size;
|
||||
++construct_count;
|
||||
}
|
||||
}
|
||||
initialise();
|
||||
|
||||
#if defined(ETL_DEBUG)
|
||||
p_end = etl::uninitialized_fill_n(p_buffer, n, value, construct_count);
|
||||
#else
|
||||
p_end = etl::uninitialized_fill_n(p_buffer, n, value);
|
||||
#endif
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
@ -481,9 +429,10 @@ namespace etl
|
||||
void push_back()
|
||||
{
|
||||
#if defined(ETL_CHECK_PUSH_POP)
|
||||
ETL_ASSERT(current_size != MAX_SIZE, ETL_ERROR(vector_full));
|
||||
ETL_ASSERT(size() != MAX_SIZE, ETL_ERROR(vector_full));
|
||||
#endif
|
||||
create_element();
|
||||
|
||||
create_back();
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
@ -494,9 +443,9 @@ namespace etl
|
||||
void push_back(parameter_t value)
|
||||
{
|
||||
#if defined(ETL_CHECK_PUSH_POP)
|
||||
ETL_ASSERT(current_size != MAX_SIZE, ETL_ERROR(vector_full));
|
||||
ETL_ASSERT(size() != MAX_SIZE, ETL_ERROR(vector_full));
|
||||
#endif
|
||||
create_element(value);
|
||||
create_back(value);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
@ -506,9 +455,9 @@ namespace etl
|
||||
void pop_back()
|
||||
{
|
||||
#if defined(ETL_CHECK_PUSH_POP)
|
||||
ETL_ASSERT(current_size > 0, ETL_ERROR(vector_empty));
|
||||
ETL_ASSERT(size() > 0, ETL_ERROR(vector_empty));
|
||||
#endif
|
||||
destroy_element();
|
||||
destroy_back();
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
@ -519,18 +468,17 @@ namespace etl
|
||||
//*********************************************************************
|
||||
iterator insert(iterator position, parameter_t value)
|
||||
{
|
||||
ETL_ASSERT((current_size)+1 <= MAX_SIZE, ETL_ERROR(vector_full));
|
||||
ETL_ASSERT(size() + 1 <= MAX_SIZE, ETL_ERROR(vector_full));
|
||||
|
||||
if (position != end())
|
||||
if (position == end())
|
||||
{
|
||||
T* p_last = &p_buffer[current_size - 1];
|
||||
create_element(*p_last);
|
||||
std::copy_backward(position, p_last, p_last + 1);
|
||||
*position = value;
|
||||
create_back(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
create_element(value);
|
||||
create_back(back());
|
||||
std::copy_backward(position, p_end - 1, p_end);
|
||||
*position = value;
|
||||
}
|
||||
|
||||
return position;
|
||||
@ -544,17 +492,16 @@ namespace etl
|
||||
///\param value The value to insert.
|
||||
//*********************************************************************
|
||||
template <typename U = T>
|
||||
typename etl::enable_if<is_simple_type<U>::value, void>::type
|
||||
typename etl::enable_if<etl::has_trivial_constructor<U>::value, void>::type
|
||||
insert(iterator position, size_t n, parameter_t value)
|
||||
{
|
||||
ETL_ASSERT((current_size + n) <= MAX_SIZE, ETL_ERROR(vector_full));
|
||||
|
||||
T* p_end = &p_buffer[current_size];
|
||||
ETL_ASSERT((size() + n) <= MAX_SIZE, ETL_ERROR(vector_full));
|
||||
|
||||
std::copy_backward(position, p_end, p_end + n);
|
||||
std::fill_n(position, n, value);
|
||||
|
||||
current_size += n;
|
||||
construct_count += n;
|
||||
p_end += n;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
@ -565,173 +512,163 @@ namespace etl
|
||||
///\param value The value to insert.
|
||||
//*********************************************************************
|
||||
template <typename U = T>
|
||||
typename etl::enable_if<!is_simple_type<U>::value, void>::type
|
||||
typename etl::enable_if<!etl::has_trivial_constructor<U>::value, void>::type
|
||||
insert(iterator position, size_t n, parameter_t value)
|
||||
{
|
||||
ETL_ASSERT((current_size + n) <= MAX_SIZE, ETL_ERROR(vector_full));
|
||||
|
||||
U v = value;
|
||||
ETL_ASSERT((size() + n) <= MAX_SIZE, ETL_ERROR(vector_full));
|
||||
|
||||
size_t insert_n = n;
|
||||
|
||||
size_t insert_begin = std::distance(begin(), position);
|
||||
size_t insert_end = insert_begin + insert_n;
|
||||
size_t new_size = current_size + n;
|
||||
|
||||
size_t old_move_n = new_size - insert_end;
|
||||
size_t new_copy_n = insert_n;
|
||||
// Copy old data.
|
||||
size_t copy_old_n;
|
||||
size_t construct_old_n;
|
||||
iterator p_construct_old;
|
||||
|
||||
// Move old.
|
||||
if (old_move_n > 0)
|
||||
if (insert_end > size())
|
||||
{
|
||||
size_t index = new_size;
|
||||
T* from = &p_buffer[size() - 1];
|
||||
T* to = &p_buffer[size() - 1 + insert_n];
|
||||
|
||||
while (index > insert_end)
|
||||
{
|
||||
if (index > size())
|
||||
{
|
||||
// Construct.
|
||||
new (to--) U(*from--);
|
||||
++construct_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy
|
||||
*to-- = *from--;
|
||||
}
|
||||
|
||||
--index;
|
||||
}
|
||||
copy_old_n = 0;
|
||||
construct_old_n = size() - insert_begin;
|
||||
p_construct_old = p_buffer + insert_end;
|
||||
}
|
||||
else
|
||||
{
|
||||
copy_old_n = size() - insert_begin - insert_n;
|
||||
construct_old_n = insert_n;
|
||||
p_construct_old = p_end;
|
||||
}
|
||||
|
||||
size_t copy_new_n = construct_old_n;
|
||||
size_t construct_new_n = insert_n - copy_new_n;
|
||||
|
||||
#if defined(ETL_DEBUG)
|
||||
// Construct old.
|
||||
etl::uninitialized_copy_n(p_end - construct_old_n, construct_old_n, p_construct_old, construct_count);
|
||||
|
||||
// Copy old.
|
||||
etl::copy_n(p_buffer + insert_begin, copy_old_n, p_buffer + insert_end);
|
||||
|
||||
// Construct new.
|
||||
etl::uninitialized_fill_n(p_end, construct_new_n, value, construct_count);
|
||||
|
||||
// Copy new.
|
||||
if (new_copy_n > 0)
|
||||
std::fill_n(p_buffer + insert_begin, copy_new_n, value);
|
||||
#else
|
||||
// Construct old.
|
||||
etl::uninitialized_copy_n(p_end - construct_old_n, construct_old_n, p_construct_old);
|
||||
|
||||
// Copy old.
|
||||
etl::copy_n(p_buffer + insert_begin, copy_old_n, p_buffer + insert_end);
|
||||
|
||||
// Construct new.
|
||||
etl::uninitialized_fill_n(p_end, construct_new_n, value);
|
||||
|
||||
// Copy new.
|
||||
std::fill_n(p_buffer + insert_begin, copy_new_n, value);
|
||||
#endif
|
||||
|
||||
p_end += n;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
/// Inserts a range of values to the vector.
|
||||
/// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
|
||||
/// For fundamental and pointer types.
|
||||
///\param position The position to insert before.
|
||||
///\param first The first element to add.
|
||||
///\param last The last + 1 element to add.
|
||||
//*********************************************************************
|
||||
template <class TIterator, typename U = T>
|
||||
typename etl::enable_if<etl::has_trivial_constructor<U>::value, void>::type
|
||||
insert(iterator position, TIterator first, TIterator last)
|
||||
{
|
||||
size_t count = std::distance(first, last);
|
||||
|
||||
ETL_ASSERT((size() + count) <= MAX_SIZE, ETL_ERROR(vector_full));
|
||||
|
||||
construct_count += count;
|
||||
|
||||
if (position == end())
|
||||
{
|
||||
size_t index = insert_begin;
|
||||
T* begin = &p_buffer[insert_begin];
|
||||
T* end = &p_buffer[insert_end];
|
||||
|
||||
while (begin != end)
|
||||
{
|
||||
if (index > size())
|
||||
{
|
||||
// Construct.
|
||||
new (begin++) U(v);
|
||||
++construct_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy.
|
||||
*begin++ = v;
|
||||
}
|
||||
|
||||
++index;
|
||||
}
|
||||
p_end = std::copy(first, last, p_end);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::copy_backward(position, p_end, p_end + count);
|
||||
std::copy(first, last, position);
|
||||
p_end += count;
|
||||
}
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
/// Inserts a range of values to the vector.
|
||||
/// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
|
||||
/// For fundamental and pointer types.
|
||||
///\param position The position to insert before.
|
||||
///\param first The first element to add.
|
||||
///\param last The last + 1 element to add.
|
||||
//*********************************************************************
|
||||
template <class TIterator, typename U = T>
|
||||
typename etl::enable_if<!etl::has_trivial_constructor<U>::value, void>::type
|
||||
insert(iterator position, TIterator first, TIterator last)
|
||||
{
|
||||
size_t count = std::distance(first, last);
|
||||
|
||||
ETL_ASSERT((size() + count) <= MAX_SIZE, ETL_ERROR(vector_full));
|
||||
|
||||
size_t insert_n = count;
|
||||
size_t insert_begin = std::distance(begin(), position);
|
||||
size_t insert_end = insert_begin + insert_n;
|
||||
|
||||
// Copy old data.
|
||||
size_t copy_old_n;
|
||||
size_t construct_old_n;
|
||||
iterator p_construct_old;
|
||||
|
||||
if (insert_end > size())
|
||||
{
|
||||
copy_old_n = 0;
|
||||
construct_old_n = size() - insert_begin;
|
||||
p_construct_old = p_buffer + insert_end;
|
||||
}
|
||||
else
|
||||
{
|
||||
copy_old_n = size() - insert_begin - insert_n;
|
||||
construct_old_n = insert_n;
|
||||
p_construct_old = p_end;
|
||||
}
|
||||
|
||||
size_t copy_new_n = construct_old_n;
|
||||
size_t construct_new_n = insert_n - copy_new_n;
|
||||
|
||||
current_size += n;
|
||||
}
|
||||
#if defined(ETL_DEBUG)
|
||||
// Construct old.
|
||||
etl::uninitialized_copy_n(p_end - construct_old_n, construct_old_n, p_construct_old, construct_count);
|
||||
|
||||
//*********************************************************************
|
||||
/// Inserts a range of values to the vector.
|
||||
/// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
|
||||
/// For fundamental and pointer types.
|
||||
///\param position The position to insert before.
|
||||
///\param first The first element to add.
|
||||
///\param last The last + 1 element to add.
|
||||
//*********************************************************************
|
||||
template <class TIterator, typename U = T>
|
||||
typename etl::enable_if<is_simple_type<U>::value, void>::type
|
||||
insert(iterator position, TIterator first, TIterator last)
|
||||
{
|
||||
size_t count = std::distance(first, last);
|
||||
// Copy old.
|
||||
etl::copy_n(p_buffer + insert_begin, copy_old_n, p_buffer + insert_end);
|
||||
|
||||
ETL_ASSERT((current_size + count) <= MAX_SIZE, ETL_ERROR(vector_full));
|
||||
|
||||
U* p_end = &p_buffer[current_size];
|
||||
|
||||
std::copy_backward(position, p_end, p_end + count);
|
||||
std::copy(first, last, position);
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
/// Inserts a range of values to the vector.
|
||||
/// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space.
|
||||
/// For fundamental and pointer types.
|
||||
///\param position The position to insert before.
|
||||
///\param first The first element to add.
|
||||
///\param last The last + 1 element to add.
|
||||
//*********************************************************************
|
||||
template <class TIterator, typename U = T>
|
||||
typename etl::enable_if<!is_simple_type<U>::value, void>::type
|
||||
insert(iterator position, TIterator first, TIterator last)
|
||||
{
|
||||
size_t count = std::distance(first, last);
|
||||
|
||||
ETL_ASSERT((current_size + count) <= MAX_SIZE, ETL_ERROR(vector_full));
|
||||
|
||||
size_t insert_n = count;
|
||||
|
||||
size_t insert_begin = std::distance(begin(), position);
|
||||
size_t insert_end = insert_begin + insert_n;
|
||||
size_t new_size = current_size + insert_n;
|
||||
|
||||
size_t old_move_n = new_size - insert_end;
|
||||
size_t new_copy_n = insert_n;
|
||||
|
||||
// Move old.
|
||||
if (old_move_n > 0)
|
||||
{
|
||||
size_t index = new_size;
|
||||
U* from = &p_buffer[size() - 1];
|
||||
U* to = &p_buffer[size() - 1 + insert_n];
|
||||
|
||||
while (index > insert_end)
|
||||
{
|
||||
if (index > size())
|
||||
{
|
||||
// Construct.
|
||||
new (to--) U(*from--);
|
||||
++construct_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy
|
||||
*to-- = *from--;
|
||||
}
|
||||
|
||||
--index;
|
||||
}
|
||||
}
|
||||
// Construct new.
|
||||
etl::uninitialized_copy_n(first + copy_new_n, construct_new_n, p_end, construct_count);
|
||||
|
||||
// Copy new.
|
||||
if (new_copy_n > 0)
|
||||
{
|
||||
size_t index = insert_begin;
|
||||
U* begin = &p_buffer[insert_begin];
|
||||
U* end = &p_buffer[insert_end];
|
||||
etl::copy_n(first, copy_new_n, p_buffer + insert_begin);
|
||||
#else
|
||||
// Construct old.
|
||||
etl::uninitialized_copy_n(p_end - construct_old_n, construct_old_n, p_construct_old);
|
||||
|
||||
while (begin != end)
|
||||
{
|
||||
if (index >= size())
|
||||
{
|
||||
// Construct.
|
||||
new (begin++) T(*first++);
|
||||
++construct_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy.
|
||||
*begin++ = *first++;
|
||||
}
|
||||
// Copy old.
|
||||
etl::copy_n(p_buffer + insert_begin, copy_old_n, p_buffer + insert_end);
|
||||
|
||||
++index;
|
||||
}
|
||||
}
|
||||
// Construct new.
|
||||
etl::uninitialized_copy_n(first + copy_new_n, construct_new_n, p_end);
|
||||
|
||||
current_size += count;
|
||||
// Copy new.
|
||||
etl::copy_n(first, copy_new_n, p_buffer + insert_begin);
|
||||
#endif
|
||||
|
||||
p_end += count;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
@ -742,7 +679,7 @@ namespace etl
|
||||
iterator erase(iterator i_element)
|
||||
{
|
||||
std::copy(i_element + 1, end(), i_element);
|
||||
destroy_element();
|
||||
destroy_back();
|
||||
|
||||
return i_element;
|
||||
}
|
||||
@ -755,7 +692,36 @@ namespace etl
|
||||
///\param last Iterator to the last element.
|
||||
///\return An iterator pointing to the element that followed the erased element.
|
||||
//*********************************************************************
|
||||
iterator erase(iterator first, iterator last)
|
||||
template <typename U = T>
|
||||
typename etl::enable_if<etl::has_trivial_constructor<U>::value, iterator>::type
|
||||
erase(iterator first, iterator last)
|
||||
{
|
||||
if (first == begin() && last == end())
|
||||
{
|
||||
clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::copy(last, end(), first);
|
||||
size_t n_delete = std::distance(first, last);
|
||||
construct_count -= n_delete;
|
||||
p_end -= n_delete;
|
||||
}
|
||||
|
||||
return first;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
/// Erases a range of elements.
|
||||
/// 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.
|
||||
///\return An iterator pointing to the element that followed the erased element.
|
||||
//*********************************************************************
|
||||
template <typename U = T>
|
||||
typename etl::enable_if<!etl::has_trivial_constructor<U>::value, iterator>::type
|
||||
erase(iterator first, iterator last)
|
||||
{
|
||||
if (first == begin() && last == end())
|
||||
{
|
||||
@ -766,19 +732,13 @@ namespace etl
|
||||
std::copy(last, end(), first);
|
||||
size_t n_delete = std::distance(first, last);
|
||||
|
||||
if (is_simple_type<value_type>::value)
|
||||
{
|
||||
// Just adjust the count.
|
||||
current_size -= n_delete;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Destroy the elements left over at the end.
|
||||
while (n_delete-- > 0)
|
||||
{
|
||||
destroy_element();
|
||||
}
|
||||
}
|
||||
// Destroy the elements left over at the end.
|
||||
#if defined(ETL_DEBUG)
|
||||
etl::destroy(p_end - n_delete, p_end, construct_count);
|
||||
#else
|
||||
etl::destroy(p_end - n_delete, p_end);
|
||||
#endif
|
||||
p_end -= n_delete;
|
||||
}
|
||||
|
||||
return first;
|
||||
@ -797,14 +757,51 @@ namespace etl
|
||||
return *this;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Gets the current size of the vector.
|
||||
///\return The current size of the vector.
|
||||
//*************************************************************************
|
||||
size_type size() const
|
||||
{
|
||||
return size_t(p_end - p_buffer);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Checks the 'empty' state of the vector.
|
||||
///\return <b>true</b> if empty.
|
||||
//*************************************************************************
|
||||
bool empty() const
|
||||
{
|
||||
return (p_end == p_buffer);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Checks the 'full' state of the vector.
|
||||
///\return <b>true</b> if full.
|
||||
//*************************************************************************
|
||||
bool full() const
|
||||
{
|
||||
return size() == MAX_SIZE;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Returns the remaining capacity.
|
||||
///\return The remaining capacity.
|
||||
//*************************************************************************
|
||||
size_t available() const
|
||||
{
|
||||
return max_size() - size();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
//*********************************************************************
|
||||
/// Constructor.
|
||||
//*********************************************************************
|
||||
ivector(T* p_buffer, size_t MAX_SIZE)
|
||||
ivector(T* p_buffer_, size_t MAX_SIZE)
|
||||
: vector_base(MAX_SIZE),
|
||||
p_buffer(p_buffer)
|
||||
p_buffer(p_buffer_),
|
||||
p_end(p_buffer_)
|
||||
{
|
||||
}
|
||||
|
||||
@ -813,87 +810,58 @@ namespace etl
|
||||
//*********************************************************************
|
||||
void initialise()
|
||||
{
|
||||
// Choose the algorithm according to type.
|
||||
// The unused branch should be optimised away.
|
||||
if (is_simple_type<value_type>::value)
|
||||
{
|
||||
current_size = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (current_size > 0)
|
||||
{
|
||||
destroy_element();
|
||||
}
|
||||
}
|
||||
}
|
||||
#if defined(ETL_DEBUG)
|
||||
etl::destroy(p_buffer, p_end, construct_count);
|
||||
#else
|
||||
etl::destroy(p_buffer, p_end);
|
||||
#endif
|
||||
|
||||
T* p_buffer;
|
||||
p_end = p_buffer;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
|
||||
pointer p_buffer; ///< Pointer to the start of the buffer.
|
||||
pointer p_end; ///< Pointer to one past the last element in the buffer.
|
||||
|
||||
//*********************************************************************
|
||||
/// Create a new element with a default value at the back.
|
||||
//*********************************************************************
|
||||
inline void create_element()
|
||||
inline void create_back()
|
||||
{
|
||||
if (is_simple_type<T>::value)
|
||||
{
|
||||
current_size++;
|
||||
}
|
||||
else
|
||||
{
|
||||
new (&p_buffer[current_size++]) T();
|
||||
++construct_count;
|
||||
}
|
||||
#if defined(ETL_DEBUG)
|
||||
etl::create_value_at(p_end, construct_count);
|
||||
#else
|
||||
etl::create_value_at(p_end);
|
||||
#endif
|
||||
++p_end;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
/// Create a new element with a value at the back
|
||||
//*********************************************************************
|
||||
inline void create_element(parameter_t value)
|
||||
inline void create_back(parameter_t value)
|
||||
{
|
||||
if (is_simple_type<T>::value)
|
||||
{
|
||||
p_buffer[current_size++] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
new (&p_buffer[current_size++]) T(value);
|
||||
++construct_count;
|
||||
}
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
/// Create a new element with a value at the index
|
||||
//*********************************************************************
|
||||
inline void create_element_at(size_t index, parameter_t value)
|
||||
{
|
||||
new (&p_buffer[index]) T(value);
|
||||
++construct_count;
|
||||
#if defined(ETL_DEBUG)
|
||||
etl::create_copy_at(p_end, value, construct_count);
|
||||
#else
|
||||
etl::create_copy_at(p_end, value);
|
||||
#endif
|
||||
++p_end;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
/// Destroy an element at the back.
|
||||
//*********************************************************************
|
||||
template <typename U = T>
|
||||
typename etl::enable_if<is_simple_type<U>::value, void>::type
|
||||
destroy_element()
|
||||
inline void destroy_back()
|
||||
{
|
||||
--current_size;
|
||||
}
|
||||
--p_end;
|
||||
|
||||
//*********************************************************************
|
||||
/// Destroy an element at the back.
|
||||
//*********************************************************************
|
||||
template <typename U = T>
|
||||
typename etl::enable_if<!is_simple_type<U>::value, void>::type
|
||||
destroy_element()
|
||||
{
|
||||
p_buffer[--current_size].~U();
|
||||
--construct_count;
|
||||
#if defined(ETL_DEBUG)
|
||||
etl::destroy_at(p_end, construct_count);
|
||||
#else
|
||||
etl::destroy_at(p_end);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Disable copy construction.
|
||||
|
||||
@ -312,7 +312,7 @@ namespace etl
|
||||
|
||||
while (first != last)
|
||||
{
|
||||
p_buffer[current_size++] = (void*)*first++;
|
||||
*p_end++ = (void*)*first++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user