From bb9b07a837fe89b06523ab90390baa9bcaafc4a3 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 9 Dec 2018 12:15:42 +0000 Subject: [PATCH] Merge remote-tracking branch 'origin/development' # Conflicts: # include/etl/private/pvoidvector.h --- include/etl/deque.h | 111 +++++++++++++ include/etl/flat_map.h | 12 +- include/etl/flat_multimap.h | 22 +++ include/etl/flat_multiset.h | 20 +++ include/etl/flat_set.h | 37 ++++- include/etl/forward_list.h | 35 ++++ include/etl/list.h | 81 +++++++--- include/etl/pool.h | 15 -- include/etl/priority_queue.h | 21 +++ include/etl/queue.h | 19 +++ include/etl/queue_mpmc_mutex.h | 191 ++++++++++++++++++++++ include/etl/queue_spsc_atomic.h | 119 ++++++++++++++ include/etl/queue_spsc_isr.h | 211 +++++++++++++++++++++++++ include/etl/stack.h | 17 ++ include/etl/variant.h | 35 ++-- include/etl/vector.h | 56 +++++-- test/CMakeLists.txt | 3 +- test/test_queue_memory_model_small.cpp | 2 + test/test_queue_mpmc_mutex.cpp | 32 +++- test/test_queue_mpmc_mutex_small.cpp | 32 +++- test/test_queue_spsc_atomic.cpp | 53 +++++++ test/test_queue_spsc_atomic_small.cpp | 53 +++++++ test/test_queue_spsc_isr.cpp | 53 +++++++ test/test_queue_spsc_isr_small.cpp | 53 +++++++ test/test_vector_non_trivial.cpp | 101 ++++++++++++ 25 files changed, 1306 insertions(+), 78 deletions(-) diff --git a/include/etl/deque.h b/include/etl/deque.h index a021f722..49b783ec 100644 --- a/include/etl/deque.h +++ b/include/etl/deque.h @@ -916,6 +916,74 @@ namespace etl return position; } + //************************************************************************* + /// Emplaces data into the deque. + /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is full. + ///\param insert_position>The insert position. + //************************************************************************* +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) + template + iterator emplace(const_iterator insert_position, Args && ... args) + { + iterator position(insert_position.index, *this, p_buffer); + + ETL_ASSERT(!full(), ETL_ERROR(deque_full)); + + void* p; + + if (insert_position == begin()) + { + --_begin; + p = etl::addressof(*_begin); + ++current_size; + ETL_INCREMENT_DEBUG_COUNT + position = _begin; + } + else if (insert_position == end()) + { + p = etl::addressof(*_end); + ++_end; + ++current_size; + ETL_INCREMENT_DEBUG_COUNT + position = _end - 1; + } + else + { + // Are we closer to the front? + if (std::distance(_begin, position) < std::distance(position, _end - 1)) + { + // Construct the _begin. + create_element_front(*_begin); + + // Move the values. + std::copy(_begin + 1, position, _begin); + + // Write the new value. + --position; + (*position).~T(); + p = etl::addressof(*position); + } + else + { + // Construct the _end. + create_element_back(*(_end - 1)); + + // Move the values. + std::copy_backward(position, _end - 2, _end - 1); + + // Write the new value. + (*position).~T(); + p = etl::addressof(*position); + } + } + + ::new (p) T(std::forward(args)...); + + return position; + } + +#else + //************************************************************************* /// Emplaces data into the deque. /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is full. @@ -1175,6 +1243,7 @@ namespace etl return position; } +#endif // ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) //************************************************************************* /// Inserts 'n' copies of a value into the deque. @@ -1508,6 +1577,26 @@ namespace etl create_element_back(item); } +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) + //************************************************************************* + /// Emplaces an item to the back of the deque. + /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full. + //************************************************************************* + template + void emplace_back(Args && ... args) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(deque_full)); +#endif + + ::new (&(*_end)) T(std::forward(args)...); + ++_end; + ++current_size; + ETL_INCREMENT_DEBUG_COUNT + } + +#else + //************************************************************************* /// Emplaces an item to the back of the deque. /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full. @@ -1575,6 +1664,7 @@ namespace etl ++current_size; ETL_INCREMENT_DEBUG_COUNT } +#endif // ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) //************************************************************************* /// Removes the oldest item from the deque. @@ -1600,6 +1690,26 @@ namespace etl create_element_front(item); } +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) + //************************************************************************* + /// Emplaces an item to the front of the deque. + /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full. + //************************************************************************* + template + void emplace_front(Args && ... args) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(deque_full)); +#endif + + --_begin; + ::new (&(*_begin)) T(std::forward(args)...); + ++current_size; + ETL_INCREMENT_DEBUG_COUNT + } + +#else + //************************************************************************* /// Emplaces an item to the front of the deque. /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full. @@ -1667,6 +1777,7 @@ namespace etl ++current_size; ETL_INCREMENT_DEBUG_COUNT } +#endif // ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) //************************************************************************* /// Removes the oldest item from the deque. diff --git a/include/etl/flat_map.h b/include/etl/flat_map.h index 7184590c..2f9771bc 100644 --- a/include/etl/flat_map.h +++ b/include/etl/flat_map.h @@ -347,20 +347,22 @@ namespace etl //************************************************************************* std::pair emplace(const value_type& value) { - return insert(value); + return emplace(value.first, value.second); } +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) //************************************************************************* /// Emplaces a value to the map. //************************************************************************* - std::pair emplace(const key_type& key, const mapped_type& value) + template + std::pair emplace(const key_type& key, Args && ... args) { ETL_ASSERT(!full(), ETL_ERROR(flat_map_full)); // Create it. value_type* pvalue = storage.allocate(); ::new ((void*)etl::addressof(pvalue->first)) key_type(key); - ::new ((void*)etl::addressof(pvalue->second)) mapped_type(value); + ::new ((void*)etl::addressof(pvalue->second)) mapped_type(std::forward(args)...); iterator i_element = lower_bound(key); @@ -381,6 +383,8 @@ namespace etl return result; } +#else + //************************************************************************* /// Emplaces a value to the map. //************************************************************************* @@ -509,6 +513,8 @@ namespace etl return result; } +#endif // ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) + //********************************************************************* /// Erases an element. ///\param key The key to erase. diff --git a/include/etl/flat_multimap.h b/include/etl/flat_multimap.h index 8244862f..54eed72f 100644 --- a/include/etl/flat_multimap.h +++ b/include/etl/flat_multimap.h @@ -320,6 +320,26 @@ namespace etl return refmap_t::insert_at(i_element, *pvalue); } +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) + //************************************************************************* + /// Emplaces a value to the map. + //************************************************************************* + template + std::pair emplace(const key_type& key, Args && ... args) + { + ETL_ASSERT(!full(), ETL_ERROR(flat_multimap_full)); + + // Create it. + value_type* pvalue = storage.allocate(); + ::new ((void*)etl::addressof(pvalue->first)) key_type(key); + ::new ((void*)etl::addressof(pvalue->second)) mapped_type(std::forward(args)...); + iterator i_element = lower_bound(key); + ETL_INCREMENT_DEBUG_COUNT + + return refmap_t::insert_at(i_element, *pvalue); + } + +#else //************************************************************************* /// Emplaces a value to the map. //************************************************************************* @@ -392,6 +412,8 @@ namespace etl return refmap_t::insert_at(i_element, *pvalue); } +#endif // ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) + //********************************************************************* /// Erases an element. ///\param key The key to erase. diff --git a/include/etl/flat_multiset.h b/include/etl/flat_multiset.h index 27d232a7..4c9e1bb9 100644 --- a/include/etl/flat_multiset.h +++ b/include/etl/flat_multiset.h @@ -281,6 +281,25 @@ namespace etl //************************************************************************* /// Emplaces a value to the set. //************************************************************************* +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) + template + std::pair emplace(Args && ... args) + { + ETL_ASSERT(!full(), ETL_ERROR(flat_multiset_full)); + + // Create it. + value_type* pvalue = storage.allocate(); + ::new (pvalue) value_type(std::forward(args)...); + + iterator i_element = lower_bound(*pvalue); + + ETL_INCREMENT_DEBUG_COUNT + return std::pair(refset_t::insert_at(i_element, *pvalue)); + } +#else + //************************************************************************* + /// Emplaces a value to the set. + //************************************************************************* template std::pair emplace(const T1& value1) { @@ -349,6 +368,7 @@ namespace etl ETL_INCREMENT_DEBUG_COUNT return std::pair(refset_t::insert_at(i_element, *pvalue)); } +#endif // ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) //********************************************************************* /// Erases an element. diff --git a/include/etl/flat_set.h b/include/etl/flat_set.h index bb1b4dbe..17e08554 100644 --- a/include/etl/flat_set.h +++ b/include/etl/flat_set.h @@ -284,6 +284,40 @@ namespace etl //************************************************************************* /// Emplaces a value to the set. //************************************************************************* +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) + template + std::pair emplace(Args && ... args) + { + ETL_ASSERT(!full(), ETL_ERROR(flat_set_full)); + + std::pair result; + + // Create it. + value_type* pvalue = storage.allocate(); + ::new (pvalue) value_type(std::forward(args)...); + + iterator i_element = lower_bound(*pvalue); + + // Doesn't already exist? + if ((i_element == end() || (*i_element != *pvalue))) + { + ETL_INCREMENT_DEBUG_COUNT + result = refset_t::insert_at(i_element, *pvalue); + } + else + { + // Destroy it. + pvalue->~value_type(); + storage.release(pvalue); + result = std::pair(end(), false); + } + + return result; + } +#else + //************************************************************************* + /// Emplaces a value to the set. + //************************************************************************* template std::pair emplace(const T1& value1) { @@ -295,7 +329,7 @@ namespace etl value_type* pvalue = storage.allocate(); ::new (pvalue) value_type(value1); - iterator i_element = lower_bound(*pvalue); + iterator i_element = lower_bound(*pvalue); // Doesn't already exist? if ((i_element == end() || (*i_element != *pvalue))) @@ -412,6 +446,7 @@ namespace etl return result; } +#endif // ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) //********************************************************************* /// Erases an element. diff --git a/include/etl/forward_list.h b/include/etl/forward_list.h index c021e465..9881a394 100644 --- a/include/etl/forward_list.h +++ b/include/etl/forward_list.h @@ -719,6 +719,22 @@ namespace etl insert_node_after(start_node, data_node); } +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) + //************************************************************************* + /// Emplaces a value to the front of the list.. + //************************************************************************* + template + void emplace_front(Args && ... args) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); +#endif + data_node_t* p_data_node = p_node_pool->allocate(); + ::new (&(p_data_node->value)) T(std::forward(args)...); + ETL_INCREMENT_DEBUG_COUNT + insert_node_after(start_node, *p_data_node); + } +#else //************************************************************************* /// Emplaces a value to the front of the list.. //************************************************************************* @@ -778,6 +794,7 @@ namespace etl ETL_INCREMENT_DEBUG_COUNT insert_node_after(start_node, *p_data_node); } +#endif // ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) //************************************************************************* /// Removes a value from the front of the forward_list. @@ -855,6 +872,23 @@ namespace etl return iterator(&data_node); } +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) + //************************************************************************* + /// Emplaces a value to the forward_list after the specified position. + //************************************************************************* + template + iterator emplace_after(iterator position, Args && ... args) + { + ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); + + data_node_t* p_data_node = p_node_pool->allocate(); + ::new (&(p_data_node->value)) T(std::forward(args)...); + ETL_INCREMENT_DEBUG_COUNT + insert_node_after(*position.p_node, *p_data_node); + + return iterator(p_data_node); + } +#else //************************************************************************* /// Emplaces a value to the forward_list after the specified position. //************************************************************************* @@ -918,6 +952,7 @@ namespace etl return iterator(p_data_node); } +#endif // ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) //************************************************************************* /// Inserts 'n' copies of a value to the forward_list after the specified position. diff --git a/include/etl/list.h b/include/etl/list.h index a9c8ca63..ed539543 100644 --- a/include/etl/list.h +++ b/include/etl/list.h @@ -851,8 +851,26 @@ namespace etl insert_node(get_head(), allocate_data_node(value)); } +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) //************************************************************************* - /// Emplaces a value to the front of the list.. + /// Emplaces a value to the front of the list. + //************************************************************************* + template + void emplace_front(Args && ... args) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(list_full)); +#endif + ETL_ASSERT(p_node_pool != nullptr, ETL_ERROR(list_no_pool)); + + data_node_t* p_data_node = p_node_pool->allocate(); + ::new (&(p_data_node->value)) T(std::forward(args)...); + ETL_INCREMENT_DEBUG_COUNT + insert_node(get_head(), *p_data_node); + } +#else + //************************************************************************* + /// Emplaces a value to the front of the list. //************************************************************************* template void emplace_front(const T1& value1) @@ -869,7 +887,7 @@ namespace etl } //************************************************************************* - /// Emplaces a value to the front of the list.. + /// Emplaces a value to the front of the list. //************************************************************************* template void emplace_front(const T1& value1, const T2& value2) @@ -886,7 +904,7 @@ namespace etl } //************************************************************************* - /// Emplaces a value to the front of the list.. + /// Emplaces a value to the front of the list. //************************************************************************* template void emplace_front(const T1& value1, const T2& value2, const T3& value3) @@ -903,7 +921,7 @@ namespace etl } //************************************************************************* - /// Emplaces a value to the front of the list.. + /// Emplaces a value to the front of the list. //************************************************************************* template void emplace_front(const T1& value1, const T2& value2, const T3& value3, const T4& value4) @@ -918,6 +936,7 @@ namespace etl ETL_INCREMENT_DEBUG_COUNT insert_node(get_head(), *p_data_node); } +#endif // ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) //************************************************************************* /// Removes a value from the front of the list. @@ -932,7 +951,7 @@ namespace etl } //************************************************************************* - /// Pushes a value to the back of the list.. + /// Pushes a value to the back of the list. //************************************************************************* void push_back(parameter_t value) { @@ -943,8 +962,23 @@ namespace etl } //************************************************************************* - /// Emplaces a value to the back of the list.. + /// Emplaces a value to the back of the list. //************************************************************************* +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) + template + void emplace_back(Args && ... args) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(list_full)); +#endif + ETL_ASSERT(p_node_pool != nullptr, ETL_ERROR(list_no_pool)); + + data_node_t* p_data_node = p_node_pool->allocate(); + ::new (&(p_data_node->value)) T(std::forward(args)...); + ETL_INCREMENT_DEBUG_COUNT + insert_node(terminal_node, *p_data_node); + } +#else template void emplace_back(const T1& value1) { @@ -959,9 +993,6 @@ namespace etl insert_node(terminal_node, *p_data_node); } - //************************************************************************* - /// Emplaces a value to the back of the list.. - //************************************************************************* template void emplace_back(const T1& value1, const T2& value2) { @@ -976,9 +1007,6 @@ namespace etl insert_node(terminal_node, *p_data_node); } - //************************************************************************* - /// Emplaces a value to the back of the list.. - //************************************************************************* template void emplace_back(const T1& value1, const T2& value2, const T3& value3) { @@ -993,9 +1021,6 @@ namespace etl insert_node(terminal_node, *p_data_node); } - //************************************************************************* - /// Emplaces a value to the back of the list.. - //************************************************************************* template void emplace_back(const T1& value1, const T2& value2, const T3& value3, const T4& value4) { @@ -1009,6 +1034,7 @@ namespace etl ETL_INCREMENT_DEBUG_COUNT insert_node(terminal_node, *p_data_node); } +#endif // ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) //************************************************************************* /// Removes a value from the back of the list. @@ -1038,6 +1064,21 @@ namespace etl //************************************************************************* /// Emplaces a value to the list at the specified position. //************************************************************************* +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) + template + iterator emplace(iterator position, Args && ... args) + { + ETL_ASSERT(!full(), ETL_ERROR(list_full)); + ETL_ASSERT(p_node_pool != nullptr, ETL_ERROR(list_no_pool)); + + data_node_t* p_data_node = p_node_pool->allocate(); + ::new (&(p_data_node->value)) T(std::forward(args)...); + ETL_INCREMENT_DEBUG_COUNT + insert_node(*position.p_node, *p_data_node); + + return iterator(*p_data_node); + } +#else template iterator emplace(iterator position, const T1& value1) { @@ -1052,9 +1093,6 @@ namespace etl return iterator(*p_data_node); } - //************************************************************************* - /// Emplaces a value to the list at the specified position. - //************************************************************************* template iterator emplace(iterator position, const T1& value1, const T2& value2) { @@ -1069,9 +1107,6 @@ namespace etl return iterator(*p_data_node); } - //************************************************************************* - /// Emplaces a value to the list at the specified position. - //************************************************************************* template iterator emplace(iterator position, const T1& value1, const T2& value2, const T3& value3) { @@ -1086,9 +1121,6 @@ namespace etl return iterator(*p_data_node); } - //************************************************************************* - /// Emplaces a value to the list at the specified position. - //************************************************************************* template iterator emplace(iterator position, const T1& value1, const T2& value2, const T3& value3, const T4& value4) { @@ -1102,6 +1134,7 @@ namespace etl return iterator(*p_data_node); } +#endif // ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) //************************************************************************* /// Inserts 'n' copies of a value to the list at the specified position. diff --git a/include/etl/pool.h b/include/etl/pool.h index a79f04bf..be56bd70 100644 --- a/include/etl/pool.h +++ b/include/etl/pool.h @@ -173,11 +173,6 @@ namespace etl return p; } - //************************************************************************* - /// Allocate storage for an object from the pool and create with 2 parameters. - /// 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. - //************************************************************************* template T* create(const T1& value1, const T2& value2) { @@ -191,11 +186,6 @@ namespace etl return p; } - //************************************************************************* - /// Allocate storage for an object from the pool and create with 3 parameters. - /// 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. - //************************************************************************* template T* create(const T1& value1, const T2& value2, const T3& value3) { @@ -209,11 +199,6 @@ namespace etl return p; } - //************************************************************************* - /// Allocate storage for an object from the pool and create with 4 parameters. - /// 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. - //************************************************************************* template T* create(const T1& value1, const T2& value2, const T3& value3, const T4& value4) { diff --git a/include/etl/priority_queue.h b/include/etl/priority_queue.h index 02eb6922..8614716a 100644 --- a/include/etl/priority_queue.h +++ b/include/etl/priority_queue.h @@ -48,6 +48,8 @@ SOFTWARE. #undef ETL_FILE #define ETL_FILE "12" +#define ETL_PRIORITY_QUEUE_FORCE_CPP03 1 + //***************************************************************************** ///\defgroup queue queue /// A priority queue with the capacity defined at compile time, @@ -168,6 +170,24 @@ namespace etl std::push_heap(container.begin(), container.end(), compare); } +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) && !ETL_PRIORITY_QUEUE_FORCE_CPP03 + //************************************************************************* + /// Emplaces a value to the queue. + /// If asserts or exceptions are enabled, throws an etl::priority_queue_full + /// is the priority queue is already full. + ///\param value The value to push to the queue. + //************************************************************************* + template + void emplace(Args && ... args) + { + ETL_ASSERT(!full(), ETL_ERROR(etl::priority_queue_full)); + + // Put element at end + container.emplace_back(std::forward(args)...); + // Make elements in container into heap + std::push_heap(container.begin(), container.end(), compare); + } +#else //************************************************************************* /// Emplaces a value to the queue. /// If asserts or exceptions are enabled, throws an etl::priority_queue_full @@ -235,6 +255,7 @@ namespace etl // Make elements in container into heap std::push_heap(container.begin(), container.end(), compare); } +#endif // ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) //************************************************************************* /// Assigns values to the priority queue. diff --git a/include/etl/queue.h b/include/etl/queue.h index c57ca47d..ecd7ef0d 100644 --- a/include/etl/queue.h +++ b/include/etl/queue.h @@ -49,6 +49,8 @@ SOFTWARE. #undef ETL_FILE #define ETL_FILE "13" +#define ETL_QUEUE_FORCE_CPP03 1 + //***************************************************************************** ///\defgroup queue queue /// A First-in / first-out queue with the capacity defined at compile time, @@ -316,6 +318,22 @@ namespace etl add_in(); } +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) && !ETL_QUEUE_FORCE_CPP03 + //************************************************************************* + /// Constructs a value in the queue 'in place'. + /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full. + ///\param value The value to use to construct the item to push to the queue. + //************************************************************************* + template + void emplace(Args && ... args) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(queue_full)); +#endif + ::new (&p_buffer[in]) T(std::forward(args)...); + add_in(); + } +#else //************************************************************************* /// Constructs a value in the queue 'in place'. /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full. @@ -375,6 +393,7 @@ namespace etl ::new (&p_buffer[in]) T(value1, value2, value3, value4); add_in(); } +#endif // ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) //************************************************************************* /// Clears the queue to the empty state. diff --git a/include/etl/queue_mpmc_mutex.h b/include/etl/queue_mpmc_mutex.h index 35279d11..2b10cf83 100644 --- a/include/etl/queue_mpmc_mutex.h +++ b/include/etl/queue_mpmc_mutex.h @@ -44,6 +44,8 @@ SOFTWARE. #undef ETL_FILE #define ETL_FILE "48" +#define ETL_QUEUE_MPMC_MUTEX_FORCE_CPP03 0 + namespace etl { template @@ -162,6 +164,88 @@ namespace etl return result; } +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) && !ETL_QUEUE_MPMC_MUTEX_FORCE_CPP03 + //************************************************************************* + /// Constructs a value in the queue 'in place'. + /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full. + //************************************************************************* + template + bool emplace(Args&&... args) + { + access.lock(); + + bool result = emplace_implementation(std::forward(args)...); + + access.unlock(); + + return result; + } +#else + //************************************************************************* + /// Constructs a value in the queue 'in place'. + /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full. + //************************************************************************* + template + bool emplace(const T1& value1) + { + access.lock(); + + bool result = emplace_implementation(value1); + + access.unlock(); + + return result; + } + + //************************************************************************* + /// Constructs a value in the queue 'in place'. + /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full. + //************************************************************************* + template + bool emplace(const T1& value1, const T2& value2) + { + access.lock(); + + bool result = emplace_implementation(value1, value2); + + access.unlock(); + + return result; + } + + //************************************************************************* + /// Constructs a value in the queue 'in place'. + /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full. + //************************************************************************* + template + bool emplace(const T1& value1, const T2& value2, const T3& value3) + { + access.lock(); + + bool result = emplace_implementation(value1, value2, value3); + + access.unlock(); + + return result; + } + + //************************************************************************* + /// Constructs a value in the queue 'in place'. + /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full. + //************************************************************************* + template + bool emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4) + { + access.lock(); + + bool result = emplace_implementation(value1, value2, value3, value4); + + access.unlock(); + + return result; + } +#endif + //************************************************************************* /// Pop a value from the queue. //************************************************************************* @@ -294,6 +378,113 @@ namespace etl return false; } +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) && !ETL_QUEUE_MPMC_MUTEX_FORCE_CPP03 + //************************************************************************* + /// Constructs a value in the queue 'in place'. + //************************************************************************* + template + bool emplace_implementation(Args&&... args) + { + if (current_size != MAX_SIZE) + { + ::new (&p_buffer[write_index]) T(std::forward(args)...); + + write_index = get_next_index(write_index, MAX_SIZE); + + ++current_size; + + return true; + } + + // Queue is full. + return false; + } +#else + //************************************************************************* + /// Constructs a value in the queue 'in place'. + //************************************************************************* + template + bool emplace_implementation(const T1& value1) + { + if (current_size != MAX_SIZE) + { + ::new (&p_buffer[write_index]) T(value1); + + write_index = get_next_index(write_index, MAX_SIZE); + + ++current_size; + + return true; + } + + // Queue is full. + return false; + } + + //************************************************************************* + /// Constructs a value in the queue 'in place'. + //************************************************************************* + template + bool emplace_implementation(const T1& value1, const T2& value2) + { + if (current_size != MAX_SIZE) + { + ::new (&p_buffer[write_index]) T(value1, value2); + + write_index = get_next_index(write_index, MAX_SIZE); + + ++current_size; + + return true; + } + + // Queue is full. + return false; + } + + //************************************************************************* + /// Constructs a value in the queue 'in place'. + //************************************************************************* + template + bool emplace_implementation(const T1& value1, const T2& value2, const T3& value3) + { + if (current_size != MAX_SIZE) + { + ::new (&p_buffer[write_index]) T(value1, value2, value3); + + write_index = get_next_index(write_index, MAX_SIZE); + + ++current_size; + + return true; + } + + // Queue is full. + return false; + } + + //************************************************************************* + /// Constructs a value in the queue 'in place'. + //************************************************************************* + template + bool emplace_implementation(const T1& value1, const T2& value2, const T3& value3, const T4& value4) + { + if (current_size != MAX_SIZE) + { + ::new (&p_buffer[write_index]) T(value1, value2, value3, value4); + + write_index = get_next_index(write_index, MAX_SIZE); + + ++current_size; + + return true; + } + + // Queue is full. + return false; + } +#endif + //************************************************************************* /// Pop a value from the queue. //************************************************************************* diff --git a/include/etl/queue_spsc_atomic.h b/include/etl/queue_spsc_atomic.h index 44eeb918..925a4672 100644 --- a/include/etl/queue_spsc_atomic.h +++ b/include/etl/queue_spsc_atomic.h @@ -44,6 +44,8 @@ SOFTWARE. #undef ETL_FILE #define ETL_FILE "47" +#define ETL_QUEUE_ATOMIC_FORCE_CPP03 0 + namespace etl { template @@ -222,6 +224,123 @@ namespace etl return false; } +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) && !ETL_QUEUE_ATOMIC_FORCE_CPP03 + //************************************************************************* + /// Constructs a value in the queue 'in place'. + /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full. + //************************************************************************* + template + bool emplace(Args&&... args) + { + size_type write_index = write.load(etl::memory_order_relaxed); + size_type next_index = get_next_index(write_index, RESERVED); + + if (next_index != read.load(etl::memory_order_acquire)) + { + ::new (&p_buffer[write_index]) T(std::forward(args)...); + + write.store(next_index, etl::memory_order_release); + + return true; + } + + // Queue is full. + return false; + } +#else + //************************************************************************* + /// Constructs a value in the queue 'in place'. + /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full. + //************************************************************************* + template + bool emplace(const T1& value1) + { + size_type write_index = write.load(etl::memory_order_relaxed); + size_type next_index = get_next_index(write_index, RESERVED); + + if (next_index != read.load(etl::memory_order_acquire)) + { + ::new (&p_buffer[write_index]) T(value1); + + write.store(next_index, etl::memory_order_release); + + return true; + } + + // Queue is full. + return false; + } + + //************************************************************************* + /// Constructs a value in the queue 'in place'. + /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full. + //************************************************************************* + template + bool emplace(const T1& value1, const T2& value2) + { + size_type write_index = write.load(etl::memory_order_relaxed); + size_type next_index = get_next_index(write_index, RESERVED); + + if (next_index != read.load(etl::memory_order_acquire)) + { + ::new (&p_buffer[write_index]) T(value1, value2); + + write.store(next_index, etl::memory_order_release); + + return true; + } + + // Queue is full. + return false; + } + + //************************************************************************* + /// Constructs a value in the queue 'in place'. + /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full. + //************************************************************************* + template + bool emplace(const T1& value1, const T2& value2, const T3& value3) + { + size_type write_index = write.load(etl::memory_order_relaxed); + size_type next_index = get_next_index(write_index, RESERVED); + + if (next_index != read.load(etl::memory_order_acquire)) + { + ::new (&p_buffer[write_index]) T(value1, value2, value3); + + write.store(next_index, etl::memory_order_release); + + return true; + } + + // Queue is full. + return false; + } + + //************************************************************************* + /// Constructs a value in the queue 'in place'. + /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full. + //************************************************************************* + template + bool emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4) + { + size_type write_index = write.load(etl::memory_order_relaxed); + size_type next_index = get_next_index(write_index, RESERVED); + + if (next_index != read.load(etl::memory_order_acquire)) + { + ::new (&p_buffer[write_index]) T(value1, value2, value3, value4); + + write.store(next_index, etl::memory_order_release); + + return true; + } + + // Queue is full. + return false; + } +#endif + //************************************************************************* /// Pop a value from the queue. //************************************************************************* diff --git a/include/etl/queue_spsc_isr.h b/include/etl/queue_spsc_isr.h index d09f6c37..2ff961d3 100644 --- a/include/etl/queue_spsc_isr.h +++ b/include/etl/queue_spsc_isr.h @@ -43,6 +43,8 @@ SOFTWARE. #undef ETL_FILE #define ETL_FILE "46" +#define ETL_QUEUE_ISR_FORCE_CPP03 0 + namespace etl { template @@ -69,6 +71,19 @@ namespace etl return push_implementation(value); } + //************************************************************************* + /// Constructs a value in the queue 'in place'. + /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full. + ///\param value The value to use to construct the item to push to the queue. + //************************************************************************* +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) && !ETL_QUEUE_ISR_FORCE_CPP03 + template + bool emplace_from_isr(Args&&... args) + { + return emplace_implementation(std::forward(args)...); + } +#endif + //************************************************************************* /// Pop a value from the queue from an ISR //************************************************************************* @@ -179,6 +194,120 @@ namespace etl return false; } +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) && !ETL_QUEUE_ISR_FORCE_CPP03 + //************************************************************************* + /// Constructs a value in the queue 'in place'. + /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full. + ///\param value The value to use to construct the item to push to the queue. + //************************************************************************* + template + bool emplace_implementation(Args&&... args) + { + if (current_size != MAX_SIZE) + { + ::new (&p_buffer[write_index]) T(std::forward(args)...); + + write_index = get_next_index(write_index, MAX_SIZE); + + ++current_size; + + return true; + } + + // Queue is full. + return false; + } +#else + //************************************************************************* + /// Constructs a value in the queue 'in place'. + /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full. + //************************************************************************* + template + bool emplace_implementation(const T1& value1) + { + if (current_size != MAX_SIZE) + { + ::new (&p_buffer[write_index]) T(value1); + + write_index = get_next_index(write_index, MAX_SIZE); + + ++current_size; + + return true; + } + + // Queue is full. + return false; + } + + //************************************************************************* + /// Constructs a value in the queue 'in place'. + /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full. + //************************************************************************* + template + bool emplace_implementation(const T1& value1, const T2& value2) + { + if (current_size != MAX_SIZE) + { + ::new (&p_buffer[write_index]) T(value1, value2); + + write_index = get_next_index(write_index, MAX_SIZE); + + ++current_size; + + return true; + } + + // Queue is full. + return false; + } + + //************************************************************************* + /// Constructs a value in the queue 'in place'. + /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full. + //************************************************************************* + template + bool emplace_implementation(const T1& value1, const T2& value2, const T3& value3) + { + if (current_size != MAX_SIZE) + { + ::new (&p_buffer[write_index]) T(value1, value2, value3); + + write_index = get_next_index(write_index, MAX_SIZE); + + ++current_size; + + return true; + } + + // Queue is full. + return false; + } + + //************************************************************************* + /// Constructs a value in the queue 'in place'. + /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full. + //************************************************************************* + template + bool emplace_implementation(const T1& value1, const T2& value2, const T3& value3, const T4& value4) + { + if (current_size != MAX_SIZE) + { + ::new (&p_buffer[write_index]) T(value1, value2, value3, value4); + + write_index = get_next_index(write_index, MAX_SIZE); + + ++current_size; + + return true; + } + + // Queue is full. + return false; + } + +#endif + //************************************************************************* /// Pop a value from the queue. //************************************************************************* @@ -299,6 +428,88 @@ namespace etl return result; } + //************************************************************************* + /// Constructs a value in the queue 'in place'. + /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full. + //************************************************************************* +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) && !ETL_QUEUE_ISR_FORCE_CPP03 + template + bool emplace(Args&&... args) + { + TAccess::lock(); + + bool result = this->emplace_implementation(std::forward(args)...); + + TAccess::unlock(); + + return result; + } +#else + //************************************************************************* + /// Constructs a value in the queue 'in place'. + /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full. + //************************************************************************* + template + bool emplace(const T1& value1) + { + TAccess::lock(); + + bool result = this->emplace_implementation(value1); + + TAccess::unlock(); + + return result; + } + + //************************************************************************* + /// Constructs a value in the queue 'in place'. + /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full. + //************************************************************************* + template + bool emplace(const T1& value1, const T2& value2) + { + TAccess::lock(); + + bool result = this->emplace_implementation(value1, value2); + + TAccess::unlock(); + + return result; + } + + //************************************************************************* + /// Constructs a value in the queue 'in place'. + /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full. + //************************************************************************* + template + bool emplace(const T1& value1, const T2& value2, const T3& value3) + { + TAccess::lock(); + + bool result = this->emplace_implementation(value1, value2, value3); + + TAccess::unlock(); + + return result; + } + + //************************************************************************* + /// Constructs a value in the queue 'in place'. + /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full. + //************************************************************************* + template + bool emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4) + { + TAccess::lock(); + + bool result = this->emplace_implementation(value1, value2, value3, value4); + + TAccess::unlock(); + + return result; + } +#endif + //************************************************************************* /// Pop a value from the queue. //************************************************************************* diff --git a/include/etl/stack.h b/include/etl/stack.h index dfe0fa04..ee372178 100644 --- a/include/etl/stack.h +++ b/include/etl/stack.h @@ -262,6 +262,22 @@ namespace etl ::new (&p_buffer[top_index]) T(value); } +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) + //************************************************************************* + /// Constructs a value in the stack place'. + /// If asserts or exceptions are enabled, throws an etl::stack_full if the stack is already full. + ///\param value The value to push to the stack. + //************************************************************************* + template + void emplace(Args && ... args) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(stack_full)); +#endif + base_t::add_in(); + ::new (&p_buffer[top_index]) T(std::forward(args)...); + } +#else //************************************************************************* /// Constructs a value in the stack place'. /// If asserts or exceptions are enabled, throws an etl::stack_full if the stack is already full. @@ -321,6 +337,7 @@ namespace etl base_t::add_in(); ::new (&p_buffer[top_index]) T(value1, value2, value3, value4); } +#endif // ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) //************************************************************************* /// Gets a const reference to the value at the top of the stack.
diff --git a/include/etl/variant.h b/include/etl/variant.h index 26e9c124..8c5e404a 100644 --- a/include/etl/variant.h +++ b/include/etl/variant.h @@ -51,6 +51,8 @@ SOFTWARE. #undef ETL_FILE #define ETL_FILE "24" +#define ETL_VARIANT_FORCE_CPP03 1 + //***************************************************************************** ///\defgroup variant variant /// A class that can contain one a several specified types in a type safe manner. @@ -711,7 +713,22 @@ namespace etl type_id = other.type_id; } -#if !ETL_CPP11_SUPPORTED || defined(ETL_STLPORT) +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) && !ETL_VARIANT_FORCE_CPP03 + //************************************************************************* + /// Emplace with variadic constructor parameters. + //************************************************************************* + template + T& emplace(Args&&... args) + { + ETL_STATIC_ASSERT(Type_Is_Supported::value, "Unsupported type"); + + destruct_current(); + ::new (static_cast(data)) T(std::forward(args)...); + type_id = Type_Id_Lookup::type_id; + + return *static_cast(data); + } +#else //*************************************************************************** /// Emplace with one constructor parameter. //*************************************************************************** @@ -769,22 +786,6 @@ namespace etl ::new (static_cast(data)) T(value1, value2, value3, value4); type_id = Type_Id_Lookup::type_id; - return *static_cast(data); - } - -#else - //************************************************************************* - /// Emplace with variadic constructor parameters. - //************************************************************************* - template - T& emplace(Args&&... args) - { - ETL_STATIC_ASSERT(Type_Is_Supported::value, "Unsupported type"); - - destruct_current(); - ::new (static_cast(data)) T(std::forward(args)...); - type_id = Type_Id_Lookup::type_id; - return *static_cast(data); } #endif diff --git a/include/etl/vector.h b/include/etl/vector.h index 3e0f9a2d..724712e8 100644 --- a/include/etl/vector.h +++ b/include/etl/vector.h @@ -63,6 +63,8 @@ SOFTWARE. #pragma GCC diagnostic ignored "-Wunused-variable" #endif +#define ETL_VECTOR_FORCE_CPP03 1 + //***************************************************************************** ///\defgroup vector vector /// A vector with the capacity defined at compile time. @@ -411,6 +413,23 @@ namespace etl create_back(value); } +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) && !ETL_VECTOR_FORCE_CPP03 + //********************************************************************* + /// Constructs a value at the end of the vector. + /// If asserts or exceptions are enabled, emits vector_full if the vector is already full. + ///\param value The value to add. + //********************************************************************* + template + void emplace_back(Args && ... args) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(size() != CAPACITY, ETL_ERROR(vector_full)); +#endif + ::new (p_end) T(std::forward(args)...); + ++p_end; + ETL_INCREMENT_DEBUG_COUNT + } +#else //********************************************************************* /// Constructs a value at the end of the vector. /// If asserts or exceptions are enabled, emits vector_full if the vector is already full. @@ -474,6 +493,7 @@ namespace etl ++p_end; ETL_INCREMENT_DEBUG_COUNT } +#endif // ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) && !ETL_VECTOR_FORCE_CPP03 //************************************************************************* /// Removes an element from the end of the vector. @@ -514,6 +534,32 @@ namespace etl //************************************************************************* /// Emplaces a value to the vextor at the specified position. //************************************************************************* +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) + template + iterator emplace(iterator position, Args && ... args) + { + ETL_ASSERT(!full(), ETL_ERROR(vector_full)); + + void* p; + + if (position == end()) + { + p = p_end++; + ETL_INCREMENT_DEBUG_COUNT + } + else + { + p = etl::addressof(*position); + create_back(back()); + std::copy_backward(position, p_end - 1, p_end); + (*position).~T(); + } + + ::new (p) T(std::forward(args)...); + + return position; + } +#else template iterator emplace(iterator position, const T1& value1) { @@ -539,9 +585,6 @@ namespace etl return position; } - //************************************************************************* - /// Emplaces a value to the vextor at the specified position. - //************************************************************************* template iterator emplace(iterator position, const T1& value1, const T2& value2) { @@ -567,9 +610,6 @@ namespace etl return position; } - //************************************************************************* - /// Emplaces a value to the vextor at the specified position. - //************************************************************************* template iterator emplace(iterator position, const T1& value1, const T2& value2, const T3& value3) { @@ -595,9 +635,6 @@ namespace etl return position; } - //************************************************************************* - /// Emplaces a value to the vextor at the specified position. - //************************************************************************* template iterator emplace(iterator position, const T1& value1, const T2& value2, const T3& value3, const T4& value4) { @@ -622,6 +659,7 @@ namespace etl return position; } +#endif // ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) //********************************************************************* /// Inserts 'n' values to the vector. diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index eea884ba..05f96eaf 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -46,7 +46,6 @@ set(TEST_SOURCE_FILES test_enum_type.cpp test_error_handler.cpp test_exception.cpp -# test_factory.cpp test_fixed_iterator.cpp test_flat_map.cpp test_flat_multimap.cpp @@ -119,6 +118,8 @@ set(TEST_SOURCE_FILES test_xor_checksum.cpp test_xor_rotate_checksum.cpp + ${CMAKE_SOURCE_DIR}/src/crc16_modbus.cpp + # Compile the source level ecl_timer here as test has provided a ecl_user.h file ${PROJECT_SOURCE_DIR}/../src/c/ecl_timer.c ) diff --git a/test/test_queue_memory_model_small.cpp b/test/test_queue_memory_model_small.cpp index ab6adfbe..d4ac3dbe 100644 --- a/test/test_queue_memory_model_small.cpp +++ b/test/test_queue_memory_model_small.cpp @@ -349,6 +349,8 @@ namespace queue.emplace('c', 3, 5.6); queue.emplace('d', 4, 7.8); + CHECK_EQUAL(4U, queue.size()); + CHECK(queue.front() == Item('a', 1, 1.2)); queue.pop(); CHECK(queue.front() == Item('b', 2, 3.4)); diff --git a/test/test_queue_mpmc_mutex.cpp b/test/test_queue_mpmc_mutex.cpp index 75c1be5c..9b907476 100644 --- a/test/test_queue_mpmc_mutex.cpp +++ b/test/test_queue_mpmc_mutex.cpp @@ -69,10 +69,10 @@ namespace int d; }; -// bool operator ==(const Data& lhs, const Data& rhs) -// { -// return (lhs.a == rhs.a) && (lhs.b == rhs.b) && (lhs.c == rhs.c) && (lhs.d == rhs.d); -// } + bool operator ==(const Data& lhs, const Data& rhs) + { + return (lhs.a == rhs.a) && (lhs.b == rhs.b) && (lhs.c == rhs.c) && (lhs.d == rhs.d); + } // std::ostream& operator <<(std::ostream& os, const Data& data) // { @@ -143,6 +143,30 @@ namespace CHECK(!queue.pop(i)); } + //************************************************************************* + TEST(test_multiple_emplace) + { + etl::queue_mpmc_mutex queue; + + queue.emplace(1); + queue.emplace(1, 2); + queue.emplace(1, 2, 3); + queue.emplace(1, 2, 3, 4); + + CHECK_EQUAL(4U, queue.size()); + + Data popped; + + queue.pop(popped); + CHECK(popped == Data(1, 2, 3, 4)); + queue.pop(popped); + CHECK(popped == Data(1, 2, 3, 4)); + queue.pop(popped); + CHECK(popped == Data(1, 2, 3, 4)); + queue.pop(popped); + CHECK(popped == Data(1, 2, 3, 4)); + } + //************************************************************************* TEST(test_size_push_pop_iqueue) { diff --git a/test/test_queue_mpmc_mutex_small.cpp b/test/test_queue_mpmc_mutex_small.cpp index 0c57c332..fdc44f70 100644 --- a/test/test_queue_mpmc_mutex_small.cpp +++ b/test/test_queue_mpmc_mutex_small.cpp @@ -74,10 +74,10 @@ namespace typedef etl::queue_mpmc_mutex QueueInt255; -// bool operator ==(const Data& lhs, const Data& rhs) -// { -// return (lhs.a == rhs.a) && (lhs.b == rhs.b) && (lhs.c == rhs.c) && (lhs.d == rhs.d); -// } + bool operator ==(const Data& lhs, const Data& rhs) + { + return (lhs.a == rhs.a) && (lhs.b == rhs.b) && (lhs.c == rhs.c) && (lhs.d == rhs.d); + } // std::ostream& operator <<(std::ostream& os, const Data& data) // { @@ -148,6 +148,30 @@ namespace CHECK(!queue.pop(i)); } + //************************************************************************* + TEST(test_multiple_emplace) + { + etl::queue_mpmc_mutex queue; + + queue.emplace(1); + queue.emplace(1, 2); + queue.emplace(1, 2, 3); + queue.emplace(1, 2, 3, 4); + + Data popped; + + CHECK_EQUAL(4U, queue.size()); + + queue.pop(popped); + CHECK(popped == Data(1, 2, 3, 4)); + queue.pop(popped); + CHECK(popped == Data(1, 2, 3, 4)); + queue.pop(popped); + CHECK(popped == Data(1, 2, 3, 4)); + queue.pop(popped); + CHECK(popped == Data(1, 2, 3, 4)); + } + //************************************************************************* TEST(test_size_push_pop_iqueue) { diff --git a/test/test_queue_spsc_atomic.cpp b/test/test_queue_spsc_atomic.cpp index 1d49cca4..074ac7e2 100644 --- a/test/test_queue_spsc_atomic.cpp +++ b/test/test_queue_spsc_atomic.cpp @@ -42,6 +42,35 @@ SOFTWARE. namespace { + struct Data + { + Data(int a_, int b_ = 2, int c_ = 3, int d_ = 4) + : a(a_), + b(b_), + c(c_), + d(d_) + { + } + + Data() + : a(0), + b(0), + c(0), + d(0) + { + } + + int a; + int b; + int c; + int d; + }; + + bool operator ==(const Data& lhs, const Data& rhs) + { + return (lhs.a == rhs.a) && (lhs.b == rhs.b) && (lhs.c == rhs.c) && (lhs.d == rhs.d); + } + SUITE(test_queue_atomic) { //************************************************************************* @@ -188,6 +217,30 @@ namespace CHECK(!queue.pop()); } + //************************************************************************* + TEST(test_multiple_emplace) + { + etl::queue_spsc_atomic queue; + + queue.emplace(1); + queue.emplace(1, 2); + queue.emplace(1, 2, 3); + queue.emplace(1, 2, 3, 4); + + CHECK_EQUAL(4U, queue.size()); + + Data popped; + + queue.pop(popped); + CHECK(popped == Data(1, 2, 3, 4)); + queue.pop(popped); + CHECK(popped == Data(1, 2, 3, 4)); + queue.pop(popped); + CHECK(popped == Data(1, 2, 3, 4)); + queue.pop(popped); + CHECK(popped == Data(1, 2, 3, 4)); + } + //************************************************************************* TEST(test_clear) { diff --git a/test/test_queue_spsc_atomic_small.cpp b/test/test_queue_spsc_atomic_small.cpp index fd8a5274..c6e6e7a3 100644 --- a/test/test_queue_spsc_atomic_small.cpp +++ b/test/test_queue_spsc_atomic_small.cpp @@ -42,6 +42,35 @@ SOFTWARE. namespace { + struct Data + { + Data(int a_, int b_ = 2, int c_ = 3, int d_ = 4) + : a(a_), + b(b_), + c(c_), + d(d_) + { + } + + Data() + : a(0), + b(0), + c(0), + d(0) + { + } + + int a; + int b; + int c; + int d; + }; + + bool operator ==(const Data& lhs, const Data& rhs) + { + return (lhs.a == rhs.a) && (lhs.b == rhs.b) && (lhs.c == rhs.c) && (lhs.d == rhs.d); + } + typedef etl::queue_spsc_atomic QueueInt; typedef etl::iqueue_spsc_atomic IQueueInt; @@ -206,6 +235,30 @@ namespace CHECK_EQUAL(254U, queue.size()); } + //************************************************************************* + TEST(test_multiple_emplace) + { + etl::queue_spsc_atomic queue; + + queue.emplace(1); + queue.emplace(1, 2); + queue.emplace(1, 2, 3); + queue.emplace(1, 2, 3, 4); + + CHECK_EQUAL(4U, queue.size()); + + Data popped; + + queue.pop(popped); + CHECK(popped == Data(1, 2, 3, 4)); + queue.pop(popped); + CHECK(popped == Data(1, 2, 3, 4)); + queue.pop(popped); + CHECK(popped == Data(1, 2, 3, 4)); + queue.pop(popped); + CHECK(popped == Data(1, 2, 3, 4)); + } + //************************************************************************* TEST(test_clear) { diff --git a/test/test_queue_spsc_isr.cpp b/test/test_queue_spsc_isr.cpp index 00623103..56516beb 100644 --- a/test/test_queue_spsc_isr.cpp +++ b/test/test_queue_spsc_isr.cpp @@ -69,6 +69,35 @@ namespace bool Access::called_lock; bool Access::called_unlock; + struct Data + { + Data(int a_, int b_ = 2, int c_ = 3, int d_ = 4) + : a(a_), + b(b_), + c(c_), + d(d_) + { + } + + Data() + : a(0), + b(0), + c(0), + d(0) + { + } + + int a; + int b; + int c; + int d; + }; + + bool operator ==(const Data& lhs, const Data& rhs) + { + return (lhs.a == rhs.a) && (lhs.b == rhs.b) && (lhs.c == rhs.c) && (lhs.d == rhs.d); + } + SUITE(test_queue_isr) { //************************************************************************* @@ -374,6 +403,30 @@ namespace CHECK(!queue.pop_from_isr()); } + //************************************************************************* + TEST(test_multiple_emplace) + { + etl::queue_spsc_isr queue; + + queue.emplace(1); + queue.emplace(1, 2); + queue.emplace(1, 2, 3); + queue.emplace(1, 2, 3, 4); + + CHECK_EQUAL(4U, queue.size()); + + Data popped; + + queue.pop(popped); + CHECK(popped == Data(1, 2, 3, 4)); + queue.pop(popped); + CHECK(popped == Data(1, 2, 3, 4)); + queue.pop(popped); + CHECK(popped == Data(1, 2, 3, 4)); + queue.pop(popped); + CHECK(popped == Data(1, 2, 3, 4)); + } + //************************************************************************* TEST(test_clear) { diff --git a/test/test_queue_spsc_isr_small.cpp b/test/test_queue_spsc_isr_small.cpp index 3895b3d0..ca5f4f22 100644 --- a/test/test_queue_spsc_isr_small.cpp +++ b/test/test_queue_spsc_isr_small.cpp @@ -69,6 +69,35 @@ namespace bool Access::called_lock; bool Access::called_unlock; + struct Data + { + Data(int a_, int b_ = 2, int c_ = 3, int d_ = 4) + : a(a_), + b(b_), + c(c_), + d(d_) + { + } + + Data() + : a(0), + b(0), + c(0), + d(0) + { + } + + int a; + int b; + int c; + int d; + }; + + bool operator ==(const Data& lhs, const Data& rhs) + { + return (lhs.a == rhs.a) && (lhs.b == rhs.b) && (lhs.c == rhs.c) && (lhs.d == rhs.d); + } + typedef etl::queue_spsc_isr QueueInt; typedef etl::iqueue_spsc_isr IQueueInt; @@ -392,6 +421,30 @@ namespace CHECK_EQUAL(255U, queue.size()); } + //************************************************************************* + TEST(test_multiple_emplace) + { + etl::queue_spsc_isr queue; + + queue.emplace(1); + queue.emplace(1, 2); + queue.emplace(1, 2, 3); + queue.emplace(1, 2, 3, 4); + + CHECK_EQUAL(4U, queue.size()); + + Data popped; + + queue.pop(popped); + CHECK(popped == Data(1, 2, 3, 4)); + queue.pop(popped); + CHECK(popped == Data(1, 2, 3, 4)); + queue.pop(popped); + CHECK(popped == Data(1, 2, 3, 4)); + queue.pop(popped); + CHECK(popped == Data(1, 2, 3, 4)); + } + //************************************************************************* TEST(test_clear) { diff --git a/test/test_vector_non_trivial.cpp b/test/test_vector_non_trivial.cpp index 2c6d3b2c..ab87b66e 100644 --- a/test/test_vector_non_trivial.cpp +++ b/test/test_vector_non_trivial.cpp @@ -571,6 +571,107 @@ namespace CHECK(is_equal); } + //************************************************************************* + // To test the CPP03 versions then ETL_TEST_VECTOR_CPP11 must be set to 0 in vector.h + TEST_FIXTURE(SetupFixture, test_emplace_back_multiple) + { + class Data + { + public: + std::string a; + size_t b; + double c; + const char *d; + Data(std::string w) : a(w), b(0), c(0.0), d(0){} + Data(std::string w, size_t x) : a(w), b(x), c(0.0), d(0){} + Data(std::string w, size_t x, double y) : a(w), b(x), c(y), d(0){} + Data(std::string w, size_t x, double y, const char *z) : a(w), b(x), c(y), d(z){} + bool operator == (const Data &other) const + { + return (a == other.a) && (b == other.b) && (c == other.c) && (d == other.d); + } + }; + + std::vector compare_data; + etl::vector data; + + std::string s; + for (size_t i = 0; i < SIZE; ++i) + { + s += "x"; + + // 4 arguments + compare_data.emplace_back(s, i, static_cast(i) + 0.1234, "emplace_back"); + data.emplace_back(s, i, static_cast(i) + 0.1234, "emplace_back"); + + // 3 arguments + compare_data.emplace_back(s, i, static_cast(i) + 0.1234); + data.emplace_back(s, i, static_cast(i) + 0.1234); + + // 2 arguments + compare_data.emplace_back(s, i); + data.emplace_back(s, i); + + // 1 argument + compare_data.emplace_back(s); + data.emplace_back(s); + } + + CHECK_EQUAL(compare_data.size(), data.size()); + + const bool is_equal = std::equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(is_equal); + } + + //************************************************************************* + // The C++11 variadic version uses non-const rvalue references so has the ability + // to emplace non-const reference members, the pre-C++11 const reference overloads + // does not have the ability to pass const reference parameters to non-const + // constructor parameters (like the members in Data below) + // So this is only tested on C++11 onwards + TEST_FIXTURE(SetupFixture, test_emplace_back_non_const_references) + { +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) && !ETL_VECTOR_FORCE_CPP03 + class Data + { + public: + std::string &a; + size_t &b; + double &c; + const char *d; + Data(std::string &w, size_t &x, double &y, const char *z) : a(w), b(x), c(y), d(z){} + bool operator == (const Data &other) const + { + return (a == other.a) && (b == other.b) && (c == other.c) && (d == other.d); + } + }; + + std::vector compare_data; + etl::vector data; + + std::string a = "test_test_test"; + size_t b = 9999; + double c = 123.456; + const char *d = "abcdefghijklmnopqrstuvwxyz"; + for (size_t i = 0; i < SIZE; ++i) + { + data.emplace_back(a, b, c, d); + compare_data.emplace_back(a, b, c, d); + } + + CHECK_EQUAL(compare_data.size(), data.size()); + + const bool is_equal = std::equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(is_equal); +#endif // ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_pop_back) {