From 800b9b355536c3ab42d017e6659f1595c6906b4a Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sat, 18 Jun 2016 07:07:51 +0100 Subject: [PATCH] Modified element creation so that fundamental types do not make unnecessary calls to constructors and destructors. --- src/ideque.h | 138 ++++++++++++++++++++++++++++++++++++++++++++++---- src/ipool.h | 87 +++++++++++++++++++++++++++++-- src/iqueue.h | 89 ++++++++++++++++++++++++++++++-- src/istack.h | 80 +++++++++++++++++++++++++++-- src/ivector.h | 71 ++++++++++++++++++++++---- 5 files changed, 433 insertions(+), 32 deletions(-) diff --git a/src/ideque.h b/src/ideque.h index 62911c42..9317e2d8 100644 --- a/src/ideque.h +++ b/src/ideque.h @@ -1240,7 +1240,7 @@ namespace etl _end = iterator(0, *this, p_buffer); } - iterator _begin; ///Iterator to the _begin item in the deque. + iterator _begin; ///Iterator to the _begin item in the deque. iterator _end; ///Iterator to the _end item in the deque. pointer p_buffer; ///The buffer for the deque. @@ -1249,7 +1249,24 @@ namespace etl //********************************************************************* /// Create a new element with a default value at the front. //********************************************************************* - void create_element_front() + template + typename etl::enable_if::value, void>::type + create_element_front() + { + if (!empty()) + { + --_begin; + } + + ++current_size; + } + + //********************************************************************* + /// Create a new element with a default value at the front. + //********************************************************************* + template + typename etl::enable_if::value, void>::type + create_element_front() { if (!empty()) { @@ -1264,7 +1281,40 @@ namespace etl /// Create a new elements from a range at the front. //********************************************************************* template - void create_element_front(size_t n, TIterator from) + typename etl::enable_if::value_type>::value, void>::type + create_element_front(size_t n, TIterator from) + { + if (n == 0) + { + return; + } + + if (!empty()) + { + --_begin; + --n; + } + + if (n > 0) + { + _begin -= n; + } + + iterator item = _begin; + + do + { + *item++ = *from++; + ++current_size; + } while (n-- != 0); + } + + //********************************************************************* + /// Create a new elements from a range at the front. + //********************************************************************* + template + typename etl::enable_if::value_type>::value, void>::type + create_element_front(size_t n, TIterator from) { if (n == 0) { @@ -1295,7 +1345,20 @@ namespace etl //********************************************************************* /// Create a new element with a default value at the back. //********************************************************************* - void create_element_back() + template + typename etl::enable_if::value, void>::type + create_element_back() + { + ++_end; + ++current_size; + } + + //********************************************************************* + /// Create a new element with a default value at the back. + //********************************************************************* + template + typename etl::enable_if::value, void>::type + create_element_back() { new(&(*_end)) T(); ++_end; @@ -1305,7 +1368,20 @@ namespace etl //********************************************************************* /// Create a new element with a default value at the front. //********************************************************************* - void create_element_front(parameter_t value) + template + typename etl::enable_if::value, void>::type + create_element_front(parameter_t value) + { + --_begin; + ++current_size; + } + + //********************************************************************* + /// Create a new element with a default value at the front. + //********************************************************************* + template + typename etl::enable_if::value, void>::type + create_element_front(parameter_t value) { --_begin; new(&(*_begin)) T(value); @@ -1315,7 +1391,21 @@ namespace etl //********************************************************************* /// Create a new element with a value at the back //********************************************************************* - void create_element_back(parameter_t value) + template + typename etl::enable_if::value, void>::type + create_element_back(parameter_t value) + { + *_end = value; + ++_end; + ++current_size; + } + + //********************************************************************* + /// Create a new element with a value at the back + //********************************************************************* + template + typename etl::enable_if::value, void>::type + create_element_back(parameter_t value) { new(&(*_end)) T(value); ++_end; @@ -1325,7 +1415,20 @@ namespace etl //********************************************************************* /// Destroy an element at the front. //********************************************************************* - void destroy_element_front() + template + typename etl::enable_if::value, void>::type + destroy_element_front() + { + --current_size; + ++_begin; + } + + //********************************************************************* + /// Destroy an element at the front. + //********************************************************************* + template + typename etl::enable_if::value, void>::type + destroy_element_front() { (*_begin).~T(); --current_size; @@ -1335,7 +1438,20 @@ namespace etl //********************************************************************* /// Destroy an element at the back. //********************************************************************* - void destroy_element_back() + template + typename etl::enable_if::value, void>::type + destroy_element_back() + { + --_end; + --current_size; + } + + //********************************************************************* + /// Destroy an element at the back. + //********************************************************************* + template + typename etl::enable_if::value, void>::type + destroy_element_back() { --_end; (*_end).~T(); @@ -1431,7 +1547,7 @@ bool operator <(const etl::ideque& lhs, const etl::ideque& rhs) template bool operator <=(const etl::ideque& lhs, const etl::ideque& rhs) { - return !operator >(lhs, rhs); + return !(lhs > rhs); } //*************************************************************************** @@ -1444,7 +1560,7 @@ bool operator <=(const etl::ideque& lhs, const etl::ideque& rhs) template bool operator >(const etl::ideque& lhs, const etl::ideque& rhs) { - return operator <(rhs, lhs); + return (rhs < lhs); } //*************************************************************************** @@ -1457,7 +1573,7 @@ bool operator >(const etl::ideque& lhs, const etl::ideque& rhs) template bool operator >=(const etl::ideque& lhs, const etl::ideque& rhs) { - return !operator <(lhs, rhs); + return !(lhs < rhs); } #undef __ETL_IN_IDEQUE_H__ diff --git a/src/ipool.h b/src/ipool.h index fdd8620f..ea2c9529 100644 --- a/src/ipool.h +++ b/src/ipool.h @@ -312,6 +312,30 @@ namespace etl return end(); } + //************************************************************************* + /// Allocate an object from the pool. + /// Uses the default constructor. + /// If asserts or exceptions are enabled and there are no more free items an + /// etl::pool_no_allocation if thrown, otherwise a nullptr is returned. + /// \note The state of the object returned is undefined. + //************************************************************************* + template + typename etl::enable_if::value, T*>::type + allocate() + { +#if defined(_DEBUG) || defined(DEBUG) + ETL_ASSERT(items_allocated < MAX_SIZE && !in_use_flags.test(next_free), ETL_ERROR(pool_no_allocation)); +#else + ETL_ASSERT(items_allocated < MAX_SIZE, ETL_ERROR(pool_no_allocation)); +#endif + + T* result = &p_buffer[next_free]; + in_use_flags.set(next_free); + next_free = in_use_flags.find_first(false); + ++items_allocated; + return result; + } + //************************************************************************* /// Allocate an object from the pool. /// Uses the default constructor. @@ -319,7 +343,9 @@ namespace etl /// etl::pool_no_allocation if thrown, otherwise a nullptr is returned. /// \note The state of the object returned is undefined. //************************************************************************* - T* allocate() + template + typename etl::enable_if::value, T*>::type + allocate() { #if defined(_DEBUG) || defined(DEBUG) ETL_ASSERT(items_allocated < MAX_SIZE && !in_use_flags.test(next_free), ETL_ERROR(pool_no_allocation)); @@ -340,7 +366,33 @@ namespace etl /// etl::pool_no_allocation if thrown, otherwise a nullptr is returned. /// \note The state of the object returned is undefined. //************************************************************************* - T* allocate(const T& initial) + template + typename etl::enable_if::value, T*>::type + allocate(const T& initial) + { +#if defined(_DEBUG) || defined(DEBUG) + ETL_ASSERT(items_allocated < MAX_SIZE && !in_use_flags.test(next_free), ETL_ERROR(pool_no_allocation)); +#else + ETL_ASSERT(items_allocated < MAX_SIZE, ETL_ERROR(pool_no_allocation)); +#endif + + T* result = &p_buffer[next_free]; + *result = initial; + in_use_flags.set(next_free); + next_free = in_use_flags.find_first(false); + ++items_allocated; + return result; + } + + //************************************************************************* + /// Allocate an object from the pool from an ititial value. + /// If asserts or exceptions are enabled and there are no more free items an + /// etl::pool_no_allocation if thrown, otherwise a nullptr is returned. + /// \note The state of the object returned is undefined. + //************************************************************************* + template + typename etl::enable_if::value, T*>::type + allocate(const T& initial) { #if defined(_DEBUG) || defined(DEBUG) ETL_ASSERT(items_allocated < MAX_SIZE && !in_use_flags.test(next_free), ETL_ERROR(pool_no_allocation)); @@ -372,7 +424,36 @@ namespace etl /// pool then an etl::pool_object_not_in_pool is thrown. /// \param p_object A pointer to the object to be released. //************************************************************************* - void release(const T* const p_object) + template + typename etl::enable_if::value, void>::type + release(const T* const p_object) + { + // Does it belong to me? + ETL_ASSERT(is_in_pool(p_object), ETL_ERROR(pool_object_not_in_pool)); + + // Where is it in the buffer? + typename std::iterator_traits::difference_type distance = p_object - p_buffer; + size_t index = static_cast(distance); + + // Check that it hasn't already been released. + if (in_use_flags.test(index)) + { + // Destroy the object and mark as available. + in_use_flags.reset(index); + --items_allocated; + next_free = index; + } + } + + //************************************************************************* + /// Release an object in the pool. + /// If asserts or exceptions are enabled and the object does not belong to this + /// pool then an etl::pool_object_not_in_pool is thrown. + /// \param p_object A pointer to the object to be released. + //************************************************************************* + template + typename etl::enable_if::value, void>::type + release(const T* const p_object) { // Does it belong to me? ETL_ASSERT(is_in_pool(p_object), ETL_ERROR(pool_object_not_in_pool)); diff --git a/src/iqueue.h b/src/iqueue.h index 8a59ab1d..f69c985e 100644 --- a/src/iqueue.h +++ b/src/iqueue.h @@ -112,7 +112,27 @@ namespace etl /// otherwise does nothing if full. ///\param value The value to push to the queue. //************************************************************************* - void push(parameter_t value) + template + typename etl::enable_if::value, void>::type + push(parameter_t value) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(queue_full)); +#endif + p_buffer[in] = value; + in = (in == (MAX_SIZE - 1)) ? 0 : in + 1; + ++current_size; + } + + //************************************************************************* + /// Adds a value to the queue. + /// If asserts or exceptions are enabled, throws an etl::queue_full is the queue is already full, + /// otherwise does nothing if full. + ///\param value The value to push to the queue. + //************************************************************************* + template + typename etl::enable_if::value, void>::type + push(parameter_t value) { #if defined(ETL_CHECK_PUSH_POP) ETL_ASSERT(!full(), ETL_ERROR(queue_full)); @@ -130,7 +150,32 @@ namespace etl /// otherwise does nothing if full. /// \return A reference to the position to 'push' to. //************************************************************************* - reference push() + template + typename etl::enable_if::value, reference>::type + push() + { + const size_type next = in; + +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(queue_full)); +#endif + in = (in == (MAX_SIZE - 1)) ? 0 : in + 1; + ++current_size; + + return p_buffer[next]; + } + + //************************************************************************* + /// Allows a possibly more efficient 'push' by moving to the next input value + /// and returning a reference to it. + /// This may eliminate a copy by allowing direct construction in-place.
+ /// If asserts or exceptions are enabled, throws an etl::queue_full is the queue is already full, + /// otherwise does nothing if full. + /// \return A reference to the position to 'push' to. + //************************************************************************* + template + typename etl::enable_if::value, reference>::type + push() { const size_type next = in; @@ -147,7 +192,26 @@ namespace etl //************************************************************************* /// Clears the queue to the empty state. //************************************************************************* - void clear() + template + typename etl::enable_if::value, void>::type + clear() + { + while (current_size > 0) + { + out = (out == (MAX_SIZE - 1)) ? 0 : out + 1; + --current_size; + } + + in = 0; + out = 0; + } + + //************************************************************************* + /// Clears the queue to the empty state. + //************************************************************************* + template + typename etl::enable_if::value, void>::type + clear() { while (current_size > 0) { @@ -164,7 +228,24 @@ namespace etl /// Removes the oldest value from the back of the queue. /// Does nothing if the queue is already empty. //************************************************************************* - void pop() + template + typename etl::enable_if::value, void>::type + pop() + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!empty(), ETL_ERROR(queue_empty)); +#endif + out = (out == (MAX_SIZE - 1)) ? 0 : out + 1; + --current_size; + } + + //************************************************************************* + /// Removes the oldest value from the back of the queue. + /// Does nothing if the queue is already empty. + //************************************************************************* + template + typename etl::enable_if::value, void>::type + pop() { #if defined(ETL_CHECK_PUSH_POP) ETL_ASSERT(!empty(), ETL_ERROR(queue_empty)); diff --git a/src/istack.h b/src/istack.h index f3d0a430..a1e0a90e 100644 --- a/src/istack.h +++ b/src/istack.h @@ -84,7 +84,25 @@ namespace etl /// If asserts or exceptions are enabled, throws an etl::stack_full is the stack is already full. ///\param value The value to push to the stack. //************************************************************************* - void push(parameter_t value) + template + typename etl::enable_if::value, void>::type + push(parameter_t value) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(stack_full)); +#endif + top_index = current_size++; + p_buffer[top_index] = value; + } + + //************************************************************************* + /// Adds a value to the stack. + /// If asserts or exceptions are enabled, throws an etl::stack_full is the stack is already full. + ///\param value The value to push to the stack. + //************************************************************************* + template + typename etl::enable_if::value, void>::type + push(parameter_t value) { #if defined(ETL_CHECK_PUSH_POP) ETL_ASSERT(!full(), ETL_ERROR(stack_full)); @@ -100,7 +118,28 @@ namespace etl /// If asserts or exceptions are enabled, throws an etl::stack_full is the stack is already full. /// \return A reference to the position to 'push' to. //************************************************************************* - reference push() + template + typename etl::enable_if::value, reference>::type + push() + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(stack_full)); +#endif + top_index = current_size++; + + return p_buffer[top_index]; + } + + //************************************************************************* + /// Allows a possibly more efficient 'push' by moving to the next input value + /// and returning a reference to it. + /// This may eliminate a copy by allowing direct construction in-place.
+ /// If asserts or exceptions are enabled, throws an etl::stack_full is the stack is already full. + /// \return A reference to the position to 'push' to. + //************************************************************************* + template + typename etl::enable_if::value, reference>::type + push() { #if defined(ETL_CHECK_PUSH_POP) ETL_ASSERT(!full(), ETL_ERROR(stack_full)); @@ -123,7 +162,23 @@ namespace etl //************************************************************************* /// Clears the stack to the empty state. //************************************************************************* - void clear() + template + typename etl::enable_if::value, void>::type + clear() + { + while (current_size > 0) + { + --top_index; + --current_size; + } + } + + //************************************************************************* + /// Clears the stack to the empty state. + //************************************************************************* + template + typename etl::enable_if::value, void>::type + clear() { while (current_size > 0) { @@ -137,7 +192,24 @@ namespace etl /// Removes the oldest item from the top of the stack. /// Does nothing if the stack is already empty. //************************************************************************* - void pop() + template + typename etl::enable_if::value, void>::type + pop() + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!empty(), ETL_ERROR(stack_empty)); +#endif + --top_index; + --current_size; + } + + //************************************************************************* + /// Removes the oldest item from the top of the stack. + /// Does nothing if the stack is already empty. + //************************************************************************* + template + typename etl::enable_if::value, void>::type + pop() { #if defined(ETL_CHECK_PUSH_POP) ETL_ASSERT(!empty(), ETL_ERROR(stack_empty)); diff --git a/src/ivector.h b/src/ivector.h index 541ed3f8..756b160e 100644 --- a/src/ivector.h +++ b/src/ivector.h @@ -439,13 +439,16 @@ namespace etl { ETL_ASSERT((current_size)+1 <= MAX_SIZE, ETL_ERROR(vector_full)); - create_element(value); - if (position != end()) { + create_element(); std::copy_backward(position, end() - 1, end()); *position = value; } + else + { + create_element(value); + } return position; } @@ -647,7 +650,19 @@ namespace etl //********************************************************************* /// Create a new element with a default value at the back. //********************************************************************* - void create_element() + template + typename etl::enable_if::value, void>::type + create_element() + { + current_size++; + } + + //********************************************************************* + /// Create a new element with a default value at the back. + //********************************************************************* + template + typename etl::enable_if::value, void>::type + create_element() { new(&p_buffer[current_size++]) T(); } @@ -655,7 +670,19 @@ namespace etl //********************************************************************* /// Create a new element with a value at the back //********************************************************************* - void create_element(parameter_t value) + template + typename etl::enable_if::value, void>::type + create_element(parameter_t value) + { + p_buffer[current_size++] = value; + } + + //********************************************************************* + /// Create a new element with a value at the back + //********************************************************************* + template + typename etl::enable_if::value, void>::type + create_element(parameter_t value) { new(&p_buffer[current_size++]) T(value); } @@ -663,7 +690,19 @@ namespace etl //********************************************************************* /// Create a new element with a value at the index //********************************************************************* - void create_element_at(size_t index, parameter_t value) + template + typename etl::enable_if::value, void>::type + create_element_at(size_t index, parameter_t value) + { + p_buffer[index] = value; + } + + //********************************************************************* + /// Create a new element with a value at the index + //********************************************************************* + template + typename etl::enable_if::value, void>::type + create_element_at(size_t index, parameter_t value) { new(&p_buffer[index]) T(value); } @@ -671,9 +710,21 @@ namespace etl //********************************************************************* /// Destroy an element at the back. //********************************************************************* - void destroy_element() + template + typename etl::enable_if::value, void>::type + destroy_element() { - p_buffer[--current_size].~T(); + --current_size; + } + + //********************************************************************* + /// Destroy an element at the back. + //********************************************************************* + template + typename etl::enable_if::value, void>::type + destroy_element() + { + p_buffer[--current_size].~U(); } // Disable copy construction. @@ -731,7 +782,7 @@ namespace etl template bool operator >(const etl::ivector& lhs, const etl::ivector& rhs) { - return operator <(rhs, lhs); + return (rhs < lhs); } //*************************************************************************** @@ -744,7 +795,7 @@ namespace etl template bool operator <=(const etl::ivector& lhs, const etl::ivector& rhs) { - return !operator >(lhs, rhs); + return !(lhs > rhs); } //*************************************************************************** @@ -757,7 +808,7 @@ namespace etl template bool operator >=(const etl::ivector& lhs, const etl::ivector& rhs) { - return !operator <(lhs, rhs); + return !(lhs < rhs); } }