diff --git a/include/etl/deque.h b/include/etl/deque.h index 49b783ece..fa9d657a8 100644 --- a/include/etl/deque.h +++ b/include/etl/deque.h @@ -38,6 +38,7 @@ SOFTWARE. #include "stl/algorithm.h" #include "stl/iterator.h" +#include "stl/utility.h" #include "container.h" #include "alignment.h" @@ -916,6 +917,60 @@ namespace etl return position; } +#if ETL_CPP11_SUPPORTED + //************************************************************************* + /// Inserts 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. + ///\param value>The value to insert. + //************************************************************************* + iterator insert(const_iterator insert_position, value_type&& value) + { + iterator position(insert_position.index, *this, p_buffer); + + ETL_ASSERT(!full(), ETL_ERROR(deque_full)); + + if (insert_position == begin()) + { + create_element_front(std::move(value)); + position = _begin; + } + else if (insert_position == end()) + { + create_element_back(std::move(value)); + 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(std::move(*_begin)); + + // Move the values. + std::move(_begin + 1, position, _begin); + + // Write the new value. + *--position = std::move(value); + } + else + { + // Construct the _end. + create_element_back(std::move(*(_end - 1))); + + // Move the values. + std::move_backward(position, _end - 2, _end - 1); + + // Write the new value. + *position = std::move(value); + } + } + + return position; + } +#endif + //************************************************************************* /// Emplaces data into the deque. /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is full. @@ -1577,6 +1632,21 @@ namespace etl create_element_back(item); } +#if ETL_CPP11_SUPPORTED + //************************************************************************* + /// Adds 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. + ///\param item The item to push to the deque. + //************************************************************************* + void push_back(T&& item) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(deque_full)); +#endif + create_element_back(std::move(item)); + } +#endif + #if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) //************************************************************************* /// Emplaces an item to the back of the deque. @@ -1690,6 +1760,21 @@ namespace etl create_element_front(item); } +#if ETL_CPP11_SUPPORTED + //************************************************************************* + /// Adds 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. + ///\param item The item to push to the deque. + //************************************************************************* + void push_front(T&& item) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(deque_full)); +#endif + create_element_front(std::move(item)); + } +#endif + #if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) //************************************************************************* /// Emplaces an item to the front of the deque. @@ -1999,6 +2084,30 @@ namespace etl ETL_INCREMENT_DEBUG_COUNT } +#if ETL_CPP11_SUPPORTED + //********************************************************************* + /// Create a new element with a default value at the front. + //********************************************************************* + void create_element_front(T&& value) + { + --_begin; + ::new (&(*_begin)) T(std::move(value)); + ++current_size; + ETL_INCREMENT_DEBUG_COUNT + } + + //********************************************************************* + /// Create a new element with a value at the back + //********************************************************************* + void create_element_back(T&& value) + { + ::new (&(*_end)) T(std::move(value)); + ++_end; + ++current_size; + ETL_INCREMENT_DEBUG_COUNT + } +#endif + //********************************************************************* /// Destroy an element at the front. //********************************************************************* @@ -2129,6 +2238,29 @@ namespace etl } } +#if ETL_CPP11_SUPPORTED + //************************************************************************* + /// Move constructor. + //************************************************************************* + deque(deque&& other) + : etl::ideque(reinterpret_cast(&buffer[0]), MAX_SIZE, BUFFER_SIZE) + { + if (this != &other) + { + this->initialise(); + + typename etl::ideque::iterator itr = other.begin(); + while (itr != other.end()) + { + this->push_back(std::move(*itr)); + ++itr; + } + + other.initialise(); + } + } +#endif + //************************************************************************* /// Assigns data to the deque. //************************************************************************* @@ -2172,6 +2304,29 @@ namespace etl return *this; } +#if ETL_CPP11_SUPPORTED + //************************************************************************* + /// Move assignment operator. + //************************************************************************* + deque& operator =(deque&& rhs) + { + if (&rhs != this) + { + this->clear(); + typename etl::ideque::iterator itr = rhs.begin(); + while (itr != rhs.end()) + { + this->push_back(std::move(*itr)); + ++itr; + } + + rhs.initialise(); + } + + return *this; + } +#endif + //************************************************************************* /// Fix the internal pointers after a low level memory copy. //************************************************************************* diff --git a/include/etl/stl/alternate/algorithm.h b/include/etl/stl/alternate/algorithm.h index 7bb6ebce7..c0e1dba9a 100644 --- a/include/etl/stl/alternate/algorithm.h +++ b/include/etl/stl/alternate/algorithm.h @@ -162,6 +162,32 @@ namespace std return de; } + //*************************************************************************** + // move + template + TIterator2 move(TIterator1 sb, TIterator1 se, TIterator2 db) + { + while (sb != se) + { + *db++ = std::move(*sb++); + } + + return db; + } + + //*************************************************************************** + // move_backward + template + TIterator2 move_backward(TIterator1 sb, TIterator1 se, TIterator2 de) + { + while (sb != se) + { + *(--de) = std::move(*(--se)); + } + + return de; + } + //*************************************************************************** // lower_bound template diff --git a/include/etl/stl/alternate/utility.h b/include/etl/stl/alternate/utility.h index 41cf3dec7..5bdce60bb 100644 --- a/include/etl/stl/alternate/utility.h +++ b/include/etl/stl/alternate/utility.h @@ -1,4 +1,4 @@ -///\file + ///\file /****************************************************************************** The MIT License(MIT) @@ -32,6 +32,7 @@ SOFTWARE. #define ETL_STL_ALTERNATE_UTILITY_INCLUDED #include "../../platform.h" +#include "../../type_traits.h" #if defined(ETL_IN_UNIT_TEST) #if !defined(ETLSTD) @@ -48,7 +49,7 @@ SOFTWARE. #if !defined(ETL_COMPILER_ARM6) //****************************************************************************** template - struct pair + struct pair { typedef T1 first_type; typedef T2 second_type; @@ -57,27 +58,27 @@ SOFTWARE. T2 second; pair() - : first(T1()), - second(T2()) + : first(T1()), + second(T2()) { } - pair(const T1& a, const T2& b) - : first(a), + pair(const T1& a, const T2& b) + : first(a), second(b) { } template - pair(const pair& other) - : first(other.first), - second(other.second) + pair(const pair& other) + : first(other.first), + second(other.second) { } - pair(const pair& other) - : first(other.first), - second(other.second) + pair(const pair& other) + : first(other.first), + second(other.second) { } @@ -99,7 +100,7 @@ SOFTWARE. return pair(a, b); } -#if !defined(ETL_COMPILER_ARM6) +#if !defined(ETL_COMPILER_ARM6) //****************************************************************************** template inline void swap(pair& a, pair& b) @@ -121,7 +122,7 @@ SOFTWARE. } template - inline bool operator <(const pair& a, const pair& b) + inline bool operator <(const pair& a, const pair& b) { return (a.first < b.first) || (!(b.first < a.first) && (a.second < b.second)); @@ -145,6 +146,14 @@ SOFTWARE. return !(a < b); } #endif + +#if ETL_CPP11_SUPPORTED + template + constexpr typename etl::remove_reference::type&& move(T&& t) noexcept + { + return static_cast::type&&>(t); + } +#endif } #endif diff --git a/include/etl/version.h b/include/etl/version.h index f80f9f29b..8cf86d59b 100644 --- a/include/etl/version.h +++ b/include/etl/version.h @@ -38,7 +38,7 @@ SOFTWARE. ///\ingroup utilities #define ETL_VERSION_MAJOR 14 -#define ETL_VERSION_MINOR 4 +#define ETL_VERSION_MINOR 5 #define ETL_VERSION_PATCH 0 #define ETL_VERSION ETL_STRINGIFY(ETL_VERSION_MAJOR) ETL_STRINGIFY(ETL_VERSION_MINOR) ETL_STRINGIFY(ETL_VERSION_PATCH) diff --git a/support/Release notes.txt b/support/Release notes.txt index a7aaf553f..263b614f6 100644 --- a/support/Release notes.txt +++ b/support/Release notes.txt @@ -1,3 +1,8 @@ +=============================================================================== +14.5.0 +Added move algorithms and utility to 'alternate' STL. +Added rvalue reference API to etl::deque. + =============================================================================== 14.4.0 Added C++03/C++11 emplace for deque, priority_queue, queues, stack, variant & vector. diff --git a/test/test_deque.cpp b/test/test_deque.cpp index 5e344a305..bd57e81f2 100644 --- a/test/test_deque.cpp +++ b/test/test_deque.cpp @@ -39,6 +39,7 @@ SOFTWARE. #include #include #include +#include namespace { @@ -88,7 +89,6 @@ namespace std::vector int_data1 = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 }; std::vector int_data2 = { 15, 16, 17, 18 }; - //************************************************************************* TEST(test_constructor) { @@ -145,7 +145,7 @@ namespace CHECK_EQUAL(compare_data.size(), data.size()); CHECK(std::equal(compare_data.begin(), compare_data.end(), data.begin())); } - + //************************************************************************* TEST(test_copy_constructor) { @@ -1688,5 +1688,66 @@ namespace CHECK(!is_equal); } + + //************************************************************************* + TEST(test_move) + { + const size_t SIZE = 10U; + typedef etl::deque, SIZE> Data; + + Data data1; + + std::unique_ptr p1(new uint32_t(1U)); + std::unique_ptr p2(new uint32_t(2U)); + std::unique_ptr p3(new uint32_t(3U)); + std::unique_ptr p4(new uint32_t(4U)); + std::unique_ptr p5(new uint32_t(5U)); + + // Move items to data1. + data1.push_front(std::move(p1)); + data1.push_back(std::move(p2)); + data1.insert(data1.begin(), std::move(p3)); + data1.insert(data1.begin() + 1, std::move(p4)); + data1.insert(data1.end(), std::move(p5)); + + const size_t ACTUAL_SIZE = data1.size(); + + CHECK(!bool(p1)); + CHECK(!bool(p2)); + CHECK(!bool(p3)); + CHECK(!bool(p4)); + CHECK(!bool(p5)); + + CHECK_EQUAL(3U, *(*(data1.begin() + 0))); + CHECK_EQUAL(4U, *(*(data1.begin() + 1))); + CHECK_EQUAL(1U, *(*(data1.begin() + 2))); + CHECK_EQUAL(2U, *(*(data1.begin() + 3))); + CHECK_EQUAL(5U, *(*(data1.begin() + 4))); + + // Move constructor. + Data data2(std::move(data1)); + + CHECK_EQUAL(3U, *(*(data2.begin() + 0))); + CHECK_EQUAL(4U, *(*(data2.begin() + 1))); + CHECK_EQUAL(1U, *(*(data2.begin() + 2))); + CHECK_EQUAL(2U, *(*(data2.begin() + 3))); + CHECK_EQUAL(5U, *(*(data2.begin() + 4))); + + CHECK(data1.empty()); + CHECK_EQUAL(ACTUAL_SIZE, data2.size()); + + // Move assignment. + Data data3; + data3 = std::move(data2); + + CHECK_EQUAL(3U, *(*(data3.begin() + 0))); + CHECK_EQUAL(4U, *(*(data3.begin() + 1))); + CHECK_EQUAL(1U, *(*(data3.begin() + 2))); + CHECK_EQUAL(2U, *(*(data3.begin() + 3))); + CHECK_EQUAL(5U, *(*(data3.begin() + 4))); + + CHECK(data2.empty()); + CHECK_EQUAL(ACTUAL_SIZE, data3.size()); + } }; } diff --git a/test/test_no_stl_algorithm.cpp b/test/test_no_stl_algorithm.cpp index a41096d21..b6a3ed1f6 100644 --- a/test/test_no_stl_algorithm.cpp +++ b/test/test_no_stl_algorithm.cpp @@ -36,6 +36,7 @@ SOFTWARE. #include #include #include +#include #include "no_stl_test_iterators.h" @@ -646,5 +647,99 @@ namespace bool isEqual = std::equal(std::begin(dataD1), std::end(dataD1), std::begin(dataD2)); CHECK(isEqual); } + + //************************************************************************* + TEST(move) + { + typedef std::vector> Data; + + Data data1; + + // Create some data. + std::unique_ptr p1(new uint32_t(1U)); + std::unique_ptr p2(new uint32_t(2U)); + std::unique_ptr p3(new uint32_t(3U)); + std::unique_ptr p4(new uint32_t(4U)); + std::unique_ptr p5(new uint32_t(5U)); + + // Fill data1. + data1.push_back(std::move(p1)); + data1.push_back(std::move(p2)); + data1.push_back(std::move(p3)); + data1.push_back(std::move(p4)); + data1.push_back(std::move(p5)); + + Data data2; + + // Move to data2. + etlstd::move(data1.begin(), data1.end(), std::back_inserter(data2)); + + // Old data now empty. + CHECK(!bool(p1)); + CHECK(!bool(p2)); + CHECK(!bool(p3)); + CHECK(!bool(p4)); + CHECK(!bool(p5)); + + CHECK_EQUAL(1U, *(data2[0])); + CHECK_EQUAL(2U, *(data2[1])); + CHECK_EQUAL(3U, *(data2[2])); + CHECK_EQUAL(4U, *(data2[3])); + CHECK_EQUAL(5U, *(data2[4])); + } + + //************************************************************************* + TEST(move_backward) + { + typedef std::vector> Data; + + Data data1; + + // Create some data. + std::unique_ptr p1(new uint32_t(1U)); + std::unique_ptr p2(new uint32_t(2U)); + std::unique_ptr p3(new uint32_t(3U)); + std::unique_ptr p4(new uint32_t(4U)); + std::unique_ptr p5(new uint32_t(5U)); + + // Fill data1. + data1.push_back(std::move(p1)); + data1.push_back(std::move(p2)); + data1.push_back(std::move(p3)); + data1.push_back(std::move(p4)); + data1.push_back(std::move(p5)); + + Data data2; + + // Create some data. + std::unique_ptr p6(new uint32_t(6U)); + std::unique_ptr p7(new uint32_t(7U)); + std::unique_ptr p8(new uint32_t(8U)); + std::unique_ptr p9(new uint32_t(9U)); + std::unique_ptr p10(new uint32_t(10U)); + + // Fill data2. + data2.push_back(std::move(p6)); + data2.push_back(std::move(p7)); + data2.push_back(std::move(p8)); + data2.push_back(std::move(p9)); + data2.push_back(std::move(p10)); + + // Overwrite data2 with data1. + etlstd::move_backward(data1.begin(), data1.end(), data2.end()); + + // Old data now empty. + CHECK(!bool(p1)); + CHECK(!bool(p2)); + CHECK(!bool(p3)); + CHECK(!bool(p4)); + CHECK(!bool(p5)); + + CHECK_EQUAL(1U, *(data2[0])); + CHECK_EQUAL(2U, *(data2[1])); + CHECK_EQUAL(3U, *(data2[2])); + CHECK_EQUAL(4U, *(data2[3])); + CHECK_EQUAL(5U, *(data2[4])); + } }; }