From 1527e9781f65222f22c1ad77b5743c0e6fa0c752 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sat, 4 Feb 2017 17:19:05 +0000 Subject: [PATCH] Added assign, insert and erase member functions. --- src/array.h | 390 +++++++++++++++++++++++++++++++++----------- test/test_array.cpp | 226 +++++++++++++++++++++++++ 2 files changed, 519 insertions(+), 97 deletions(-) diff --git a/src/array.h b/src/array.h index f6c64a80..1e514c98 100644 --- a/src/array.h +++ b/src/array.h @@ -41,6 +41,7 @@ SOFTWARE. #include "parameter_type.h" #include "static_assert.h" #include "error_handler.h" +#include "algorithm.h" ///\defgroup array array /// A replacement for std::array if you haven't got C++0x11. @@ -76,18 +77,18 @@ namespace etl } }; - //*************************************************************************** + //*************************************************************************** ///\ingroup array /// A replacement for std::array if you haven't got C++0x11. - //*************************************************************************** + //*************************************************************************** template class array - { + { private: typedef typename parameter_type::type parameter_t; - public: + public: enum { @@ -102,9 +103,9 @@ namespace etl typedef T* pointer; typedef const T* const_pointer; typedef T* iterator; - typedef const T* const_iterator; - typedef std::reverse_iterator reverse_iterator; - typedef std::reverse_iterator const_reverse_iterator; + typedef const T* const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; //************************************************************************* // Element access @@ -204,29 +205,29 @@ namespace etl // Iterators //************************************************************************* - //************************************************************************* - /// Returns an iterator to the beginning of the array. - //************************************************************************* - iterator begin() - { - return &_buffer[0]; - } - - //************************************************************************* - /// Returns a const iterator to the beginning of the array. - //************************************************************************* - const_iterator begin() const - { - return &_buffer[0]; - } + //************************************************************************* + /// Returns an iterator to the beginning of the array. + //************************************************************************* + iterator begin() + { + return &_buffer[0]; + } - //************************************************************************* - /// Returns a const iterator to the beginning of the array. - //************************************************************************* - const_iterator cbegin() const - { - return begin(); - } + //************************************************************************* + /// Returns a const iterator to the beginning of the array. + //************************************************************************* + const_iterator begin() const + { + return &_buffer[0]; + } + + //************************************************************************* + /// Returns a const iterator to the beginning of the array. + //************************************************************************* + const_iterator cbegin() const + { + return begin(); + } //************************************************************************* /// Returns an iterator to the end of the array. @@ -252,53 +253,53 @@ namespace etl return &_buffer[SIZE]; } - //************************************************************************* - // Returns an reverse iterator to the reverse beginning of the array. - //************************************************************************* - reverse_iterator rbegin() - { - return reverse_iterator(end()); - } - - //************************************************************************* - /// Returns a const reverse iterator to the reverse beginning of the array. - //************************************************************************* - const_reverse_iterator rbegin() const - { - return const_reverse_iterator(end()); - } + //************************************************************************* + // Returns an reverse iterator to the reverse beginning of the array. + //************************************************************************* + reverse_iterator rbegin() + { + return reverse_iterator(end()); + } - //************************************************************************* - /// Returns a const reverse iterator to the reverse beginning of the array. - //************************************************************************* - const_reverse_iterator crbegin() const - { - return const_reverse_iterator(end()); - } + //************************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the array. + //************************************************************************* + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(end()); + } - //************************************************************************* - /// Returns a reverse iterator to the end of the array. - //************************************************************************* - reverse_iterator rend() - { - return reverse_iterator(begin()); - } - - //************************************************************************* - /// Returns a const reverse iterator to the end of the array. - //************************************************************************* - const_reverse_iterator rend() const - { - return const_reverse_iterator(begin()); - } + //************************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the array. + //************************************************************************* + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(end()); + } - //************************************************************************* - /// Returns a const reverse iterator to the end of the array. - //************************************************************************* - const_reverse_iterator crend() const - { - return const_reverse_iterator(begin()); - } + //************************************************************************* + /// Returns a reverse iterator to the end of the array. + //************************************************************************* + reverse_iterator rend() + { + return reverse_iterator(begin()); + } + + //************************************************************************* + /// Returns a const reverse iterator to the end of the array. + //************************************************************************* + const_reverse_iterator rend() const + { + return const_reverse_iterator(begin()); + } + + //************************************************************************* + /// Returns a const reverse iterator to the end of the array. + //************************************************************************* + const_reverse_iterator crend() const + { + return const_reverse_iterator(begin()); + } //************************************************************************* // Capacity @@ -312,21 +313,21 @@ namespace etl return (SIZE == 0); } - //************************************************************************* - /// Returns the size of the array. - //************************************************************************* - size_t size() const - { - return SIZE; - } + //************************************************************************* + /// Returns the size of the array. + //************************************************************************* + size_t size() const + { + return SIZE; + } - //************************************************************************* - /// Returns the maximum possible size of the array. - //************************************************************************* - size_t max_size() const - { - return SIZE; - } + //************************************************************************* + /// Returns the maximum possible size of the array. + //************************************************************************* + size_t max_size() const + { + return SIZE; + } //************************************************************************* // Operations @@ -353,20 +354,215 @@ namespace etl } } + //************************************************************************* + /// Fills the array from the range. + /// If the range is larger than the array then the extra data is ignored. + /// If the range is smaller than the array then the unused array elements are left unmodified. + ///\param first The iterator to the first item in the ramge. + ///\param last The iterator to one past the final item in the range. + //************************************************************************* + template + void assign(TIterator first, const TIterator last) + { + iterator itr = begin(); + + etl::copy(first, last, begin(), end()); + } + + //************************************************************************* + /// Fills the array from the range. + /// If the range is larger than the array then the extra data is ignored. + /// If the range is smaller than the array then the unused array elements are initialised with the supplied value. + ///\param first The iterator to the first item in the ramge. + ///\param last The iterator to one past the final item in the range. + //************************************************************************* + template + void assign(TIterator first, const TIterator last, parameter_t value) + { + // Copy from the range. + iterator p = etl::copy(first, last, begin(), end()); + + // Default initialise any that are left. + std::fill(p, end(), value); + } + + //************************************************************************* + /// Inserts a value into the array. + ///\param position The index of the position to insert at. + ///\param value The value to insert. + //************************************************************************* + inline iterator insert_at(size_t position, parameter_t value) + { + return insert(begin() + position, value); + } + + //************************************************************************* + /// Inserts a value into the array. + ///\param position The iterator to the position to insert at. + ///\param value The value to insert. + //************************************************************************* + iterator insert(const_iterator position, parameter_t value) + { + iterator p = const_cast(position); + + std::copy_backward(p, end() - 1, end()); + *p = value; + + return p; + } + + //************************************************************************* + /// Insert into the array from the range. + ///\param position The position to insert at. + ///\param first The iterator to the first item in the range. + ///\param last The iterator to one past the final item in the range. + //************************************************************************* + template + inline iterator insert_at(size_t position, TIterator first, const TIterator last) + { + return insert(begin() + position, first, last); + } + + //************************************************************************* + /// Insert into the array from the range. + ///\param position The position to insert at. + ///\param first The iterator to the first item in the range. + ///\param last The iterator to one past the final item in the range. + //************************************************************************* + template + iterator insert(const_iterator position, TIterator first, const TIterator last) + { + iterator p = const_cast(position); + iterator result(p); + + size_t source_size = std::distance(first, last); + size_t destination_space = std::distance(position, cend()); + + // Do we need to move anything? + if (source_size < destination_space) + { + size_t length = SIZE - (std::distance(begin(), p) + source_size); + std::copy_backward(p, p + length, end()); + } + + // Copy from the range. + etl::copy(first, last, p, end()); + + return result; + } + + //************************************************************************* + /// Erases a value from the array. + /// The after erase, the last value in the array will be unmodified. + ///\param position The index of the position to erase at. + //************************************************************************* + inline iterator erase_at(size_t position) + { + return erase(begin() + position); + } + + //************************************************************************* + /// Inserts a value into the array. + /// The after erase, the last value in the array will be unmodified. + ///\param position The iterator to the position to erase at. + //************************************************************************* + iterator erase(const_iterator position) + { + iterator p = const_cast(position); + std::copy(p + 1, end(), p); + + return p; + } + + //************************************************************************* + /// Erases a range of values from the array. + /// The after erase, the last values in the array will be unmodified. + ///\param first The first item to erase. + ///\param last The one past the last item to erase. + //************************************************************************* + iterator erase_range(size_t first, size_t last) + { + return erase(begin() + first, begin() + last); + } + + //************************************************************************* + /// Erases a range of values from the array. + /// The after erase, the last values in the array will be unmodified. + ///\param first The first item to erase. + ///\param last The one past the last item to erase. + //************************************************************************* + iterator erase(const_iterator first, const_iterator last) + { + iterator p = const_cast(first); + std::copy(last, cend(), p); + return p; + } + + //************************************************************************* + /// Erases a value from the array. + ///\param position The index of the position to erase at. + ///\param value The value to use to overwrite the last element in the array. + //************************************************************************* + inline iterator erase_at(size_t position, parameter_t value) + { + return erase(begin() + position, value); + } + + //************************************************************************* + /// Inserts a value into the array. + ///\param position The iterator to the position to erase at. + ///\param value The value to use to overwrite the last element in the array. + //************************************************************************* + iterator erase(const_iterator position, parameter_t value) + { + iterator p = const_cast(position); + + std::copy(p + 1, end(), p); + back() = value; + + return p; + } + + //************************************************************************* + /// Erases a range of values from the array. + ///\param first The first item to erase. + ///\param last The one past the last item to erase. + ///\param value The value to use to overwrite the last elements in the array. + //************************************************************************* + iterator erase_range(size_t first, size_t last, parameter_t value) + { + return erase(begin() + first, begin() + last, value); + } + + //************************************************************************* + /// Erases a range of values from the array. + ///\param position The iterator to the position to erase at. + ///\param value The value to use to overwrite the last elements in the array. + //************************************************************************* + iterator erase(const_iterator first, const_iterator last, parameter_t value) + { + iterator p = const_cast(first); + + p = std::copy(last, cend(), p); + std::fill(p, end(), value); + + return const_cast(first); + } + /// The array data. T _buffer[SIZE]; }; //************************************************************************* - /// Overloaded swap for etl::array - ///\param lhs The first array. - ///\param rhs The second array. - //************************************************************************* + /// Overloaded swap for etl::array + ///\param lhs The first array. + ///\param rhs The second array. + //************************************************************************* template void swap(etl::array &lhs, etl::array &rhs) - { - lhs.swap(rhs); - } + { + lhs.swap(rhs); + } //************************************************************************* /// Equal operator. @@ -391,7 +587,7 @@ namespace etl { return !(lhs == rhs); } - + //************************************************************************* /// Less than operator. ///\param lhs The first array. @@ -402,8 +598,8 @@ namespace etl bool operator <(const etl::array& lhs, const etl::array& rhs) { return std::lexicographical_compare(lhs.cbegin(), - lhs.cend(), - rhs.cbegin(), + lhs.cend(), + rhs.cbegin(), rhs.cend()); } diff --git a/test/test_array.cpp b/test/test_array.cpp index 527e8343..69073e35 100644 --- a/test/test_array.cpp +++ b/test/test_array.cpp @@ -348,6 +348,232 @@ namespace //int i = etl::get<11>(data2); } + //************************************************************************* + TEST(test_assign) + { + int initial[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; + int source[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; + int check1[] = { 0, 1, 2, 3, 4, -1, -1, -1, -1, -1 }; + int check2[] = { 0, 1, 2, 3, 4, 99, 99, 99, 99, 99 }; + int check3[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + Data data; + + // Initial data. + data.assign(std::begin(initial), std::end(initial)); + bool isEqual = std::equal(data.begin(), data.end(), std::begin(initial)); + CHECK(isEqual); + + // Assign smaller. + data.assign(std::begin(initial), std::end(initial)); + data.assign(&source[0], &source[5]); + isEqual = std::equal(data.begin(), data.end(), std::begin(check1)); + CHECK(isEqual); + + // Assign smaller + default. + data.assign(std::begin(initial), std::end(initial)); + data.assign(&source[0], &source[5], 99); + isEqual = std::equal(data.begin(), data.end(), std::begin(check2)); + CHECK(isEqual); + + // Assign larger. + data.assign(std::begin(initial), std::end(initial)); + data.assign(&source[0], &source[13]); + isEqual = std::equal(data.begin(), data.end(), std::begin(check3)); + CHECK(isEqual); + } + + //************************************************************************* + TEST(test_insert_value) + { + int initial[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + int check1[] = { 99, 0, 1, 2, 3, 4, 5, 6, 7, 8 }; + int check2[] = { 0, 1, 2, 3, 4, 99, 5, 6, 7, 8 }; + int check3[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 99 }; + + Data data; + Data::iterator result; + + // Insert beginning. + data.assign(std::begin(initial), std::end(initial)); + result = data.insert_at(0, 99); + CHECK_EQUAL(data[0], *result); + bool isEqual = std::equal(data.begin(), data.end(), std::begin(check1)); + CHECK(isEqual); + + // Insert middle. + data.assign(std::begin(initial), std::end(initial)); + result = data.insert_at(5, 99); + CHECK_EQUAL(data[5], *result); + isEqual = std::equal(data.begin(), data.end(), std::begin(check2)); + CHECK(isEqual); + + // Insert end. + data.assign(std::begin(initial), std::end(initial)); + result = data.insert_at(9, 99); + CHECK_EQUAL(data[9], *result); + isEqual = std::equal(data.begin(), data.end(), std::begin(check3)); + CHECK(isEqual); + } + + //************************************************************************* + TEST(test_insert_range) + { + int source1[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; + int source2[] = { 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; + int check1[] = { 12, 11, 10, 0, 1, 2, 3, 4, 5, 6 }; + int check2[] = { 0, 1, 2, 3, 12, 11, 10, 4, 5, 6 }; + int check3[] = { 0, 1, 2, 3, 4, 5, 6, 12, 11, 10 }; + int check4[] = { 12, 11, 10, 9, 8, 7, 6, 5, 4, 3 }; + int check5[] = { 0, 1, 2, 3, 12, 11, 10, 9, 8, 7, 6 }; + + Data data; + Data::iterator result; + + // Insert smaller, beginning. + data.assign(std::begin(source1), std::end(source1)); + result = data.insert_at(0, &source2[0], &source2[3]); + CHECK_EQUAL(data[0], *result); + bool isEqual = std::equal(data.begin(), data.end(), std::begin(check1)); + CHECK(isEqual); + + // Insert smaller, middle. + data.assign(std::begin(source1), std::end(source1)); + result = data.insert_at(4, &source2[0], &source2[3]); + CHECK_EQUAL(data[4], *result); + isEqual = std::equal(data.begin(), data.end(), std::begin(check2)); + CHECK(isEqual); + + // Insert smaller, end. + data.assign(std::begin(source1), std::end(source1)); + result = data.insert_at(7, &source2[0], &source2[3]); + CHECK_EQUAL(data[7], *result); + isEqual = std::equal(data.begin(), data.end(), std::begin(check3)); + CHECK(isEqual); + + // Insert larger, beginning. + data.assign(std::begin(source1), std::end(source1)); + result = data.insert_at(0, &source2[0], &source2[13]); + CHECK_EQUAL(data[0], *result); + isEqual = std::equal(data.begin(), data.end(), std::begin(check4)); + CHECK(isEqual); + + // Insert larger, middle. + data.assign(std::begin(source1), std::end(source1)); + result = data.insert_at(4, &source2[0], &source2[13]); + CHECK_EQUAL(data[4], *result); + isEqual = std::equal(data.begin(), data.end(), std::begin(check5)); + CHECK(isEqual); + } + + //************************************************************************* + TEST(test_erase_single) + { + int initial[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + int check1a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 9 }; + int check1b[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 99 }; + int check2a[] = { 0, 1, 2, 3, 4, 6, 7, 8, 9, 9 }; + int check2b[] = { 0, 1, 2, 3, 4, 6, 7, 8, 9, 99 }; + int check3a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + int check3b[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 99 }; + + Data data; + Data::iterator result; + + // Erase beginning. + data.assign(std::begin(initial), std::end(initial)); + result = data.erase_at(0); + CHECK_EQUAL(data[0], *result); + bool isEqual = std::equal(data.begin(), data.end(), std::begin(check1a)); + CHECK(isEqual); + + data.assign(std::begin(initial), std::end(initial)); + result = data.erase_at(0, 99); + CHECK_EQUAL(data[0], *result); + isEqual = std::equal(data.begin(), data.end(), std::begin(check1b)); + CHECK(isEqual); + + // Erase middle. + data.assign(std::begin(initial), std::end(initial)); + result = data.erase_at(5); + CHECK_EQUAL(data[5], *result); + isEqual = std::equal(data.begin(), data.end(), std::begin(check2a)); + CHECK(isEqual); + + data.assign(std::begin(initial), std::end(initial)); + result = data.erase_at(5, 99); + CHECK_EQUAL(data[5], *result); + isEqual = std::equal(data.begin(), data.end(), std::begin(check2b)); + CHECK(isEqual); + + // Erase last. + data.assign(std::begin(initial), std::end(initial)); + result = data.erase_at(9); + CHECK_EQUAL(data[9], *result); + isEqual = std::equal(data.begin(), data.end(), std::begin(check3a)); + CHECK(isEqual); + + data.assign(std::begin(initial), std::end(initial)); + result = data.erase_at(9, 99); + CHECK_EQUAL(data[9], *result); + isEqual = std::equal(data.begin(), data.end(), std::begin(check3b)); + CHECK(isEqual); + } + + //************************************************************************* + TEST(test_erase_range) + { + int initial[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + int check1a[] = { 5, 6, 7, 8, 9, 5, 6, 7, 8, 9 }; + int check1b[] = { 5, 6, 7, 8, 9, 99, 99, 99, 99, 99 }; + int check2a[] = { 0, 1, 7, 8, 9, 5, 6, 7, 8, 9 }; + int check2b[] = { 0, 1, 7, 8, 9, 99, 99, 99, 99, 99 }; + int check3a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + int check3b[] = { 0, 1, 2, 3, 4, 99, 99, 99, 99, 99 }; + + Data data; + Data::iterator result; + + // Erase beginning. + data.assign(std::begin(initial), std::end(initial)); + result = data.erase_range(0, 5); + CHECK_EQUAL(data[0], *result); + bool isEqual = std::equal(data.begin(), data.end(), std::begin(check1a)); + CHECK(isEqual); + + data.assign(std::begin(initial), std::end(initial)); + result = data.erase_range(0, 5, 99); + CHECK_EQUAL(data[0], *result); + isEqual = std::equal(data.begin(), data.end(), std::begin(check1b)); + CHECK(isEqual); + + // Erase middle. + data.assign(std::begin(initial), std::end(initial)); + result = data.erase_range(2, 7); + CHECK_EQUAL(data[2], *result); + isEqual = std::equal(data.begin(), data.end(), std::begin(check2a)); + CHECK(isEqual); + + data.assign(std::begin(initial), std::end(initial)); + result = data.erase_range(2, 7, 99); + CHECK_EQUAL(data[2], *result); + isEqual = std::equal(data.begin(), data.end(), std::begin(check2b)); + CHECK(isEqual); + + // Erase last. + data.assign(std::begin(initial), std::end(initial)); + result = data.erase_range(5, 10); + CHECK_EQUAL(data[5], *result); + isEqual = std::equal(data.begin(), data.end(), std::begin(check3a)); + CHECK(isEqual); + + data.assign(std::begin(initial), std::end(initial)); + result = data.erase_range(5, 10, 99); + CHECK_EQUAL(data[5], *result); + isEqual = std::equal(data.begin(), data.end(), std::begin(check3b)); + CHECK(isEqual); + } + //************************************************************************* TEST(test_equal) {