From 4a8c167a31ad612693f0ef79f4ee925bc527bca5 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Tue, 10 Mar 2026 21:39:13 +0100 Subject: [PATCH] Changes from review of algorithm.h on development branch (#1340) * Add missing constexpr in algorithm.h * Fix call of nth_element 2nd argument (nth) was missing * Replace partition point with O(log(N)) algorithm The C++ standard defines O(log(N)) calls of predicate as the complexity of partition_point(). The old algorithm was linear. * Use predicate in calculation of is_permutation consistently In case of predicate not equal_to, the calculation previously returned wron results * Omit swap in selection_sort if iterators are equal * Use difference_type in rotate_general() instead of int * Typo fix in algorithm.h * Simplifications in algorithm.h Application of plain refactoring by keeping semantics * Guard against past-end iterator in etl::rotate() And fix scope of rotate_right_by_one for etl::rotate() * Support empty ranges in selection_sort * Add tests for swap_ranges * Add tests for binary_search * Add tests for find_end * Add tests for accumulate * Add tests for move_s * Added tests for is_heap and sort_heap * Remove early exit for empty input * Add adjacent_find * Add unique * Add unique_copy * Add merge * Add inplace_merge * Add partial_sort * Add partial_sort_copy --- include/etl/algorithm.h | 682 +++++++++--- test/test_algorithm.cpp | 2222 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 2735 insertions(+), 169 deletions(-) diff --git a/include/etl/algorithm.h b/include/etl/algorithm.h index 7317889c..cb38f8c3 100644 --- a/include/etl/algorithm.h +++ b/include/etl/algorithm.h @@ -507,6 +507,7 @@ namespace etl //*************************************************************************** template ETL_NODISCARD + ETL_CONSTEXPR14 bool binary_search(TIterator first, TIterator last, const T& value, Compare compare) { first = etl::lower_bound(first, last, value, compare); @@ -516,6 +517,7 @@ namespace etl template ETL_NODISCARD + ETL_CONSTEXPR14 bool binary_search(TIterator first, TIterator last, const T& value) { typedef etl::less::value_type> compare; @@ -949,7 +951,7 @@ namespace etl { // Push Heap Helper template - void push_heap(TIterator first, TDistance value_index, TDistance top_index, TValue value, TCompare compare) + ETL_CONSTEXPR14 void push_heap(TIterator first, TDistance value_index, TDistance top_index, TValue value, TCompare compare) { TDistance parent = (value_index - 1) / 2; @@ -965,7 +967,7 @@ namespace etl // Adjust Heap Helper template - void adjust_heap(TIterator first, TDistance value_index, TDistance length, TValue value, TCompare compare) + ETL_CONSTEXPR14 void adjust_heap(TIterator first, TDistance value_index, TDistance length, TValue value, TCompare compare) { TDistance top_index = value_index; TDistance child2nd = (2 * value_index) + 2; @@ -993,7 +995,7 @@ namespace etl // Is Heap Helper template - bool is_heap(const TIterator first, const TDistance n, TCompare compare) + ETL_CONSTEXPR14 bool is_heap(const TIterator first, const TDistance n, TCompare compare) { TDistance parent = 0; @@ -1016,6 +1018,7 @@ namespace etl // Pop Heap template + ETL_CONSTEXPR14 void pop_heap(TIterator first, TIterator last, TCompare compare) { typedef typename etl::iterator_traits::value_type value_t; @@ -1029,6 +1032,7 @@ namespace etl // Pop Heap template + ETL_CONSTEXPR14 void pop_heap(TIterator first, TIterator last) { typedef etl::less::value_type> compare; @@ -1038,6 +1042,7 @@ namespace etl // Push Heap template + ETL_CONSTEXPR14 void push_heap(TIterator first, TIterator last, TCompare compare) { typedef typename etl::iterator_traits::difference_type difference_t; @@ -1048,6 +1053,7 @@ namespace etl // Push Heap template + ETL_CONSTEXPR14 void push_heap(TIterator first, TIterator last) { typedef etl::less::value_type> compare; @@ -1057,6 +1063,7 @@ namespace etl // Make Heap template + ETL_CONSTEXPR14 void make_heap(TIterator first, TIterator last, TCompare compare) { typedef typename etl::iterator_traits::difference_type difference_t; @@ -1084,6 +1091,7 @@ namespace etl // Make Heap template + ETL_CONSTEXPR14 void make_heap(TIterator first, TIterator last) { typedef etl::less::value_type> compare; @@ -1094,6 +1102,7 @@ namespace etl // Is Heap template ETL_NODISCARD + ETL_CONSTEXPR14 bool is_heap(TIterator first, TIterator last) { typedef etl::less::value_type> compare; @@ -1104,6 +1113,7 @@ namespace etl // Is Heap template ETL_NODISCARD + ETL_CONSTEXPR14 bool is_heap(TIterator first, TIterator last, TCompare compare) { return private_heap::is_heap(first, last - first, compare); @@ -1111,6 +1121,7 @@ namespace etl // Sort Heap template + ETL_CONSTEXPR14 void sort_heap(TIterator first, TIterator last) { while (first != last) @@ -1122,6 +1133,7 @@ namespace etl // Sort Heap template + ETL_CONSTEXPR14 void sort_heap(TIterator first, TIterator last, TCompare compare) { while (first != last) @@ -1131,6 +1143,119 @@ namespace etl } } + //*************************************************************************** + /// partial_sort + ///\ingroup algorithm + /// + //*************************************************************************** + template + ETL_CONSTEXPR14 + void partial_sort(TIterator first, TIterator middle, TIterator last, TCompare compare) + { + if (first == middle) + { + return; + } + + typedef typename etl::iterator_traits::value_type value_t; + typedef typename etl::iterator_traits::difference_type difference_t; + + etl::make_heap(first, middle, compare); + + for (TIterator i = middle; i != last; ++i) + { + if (compare(*i, *first)) + { + value_t value = ETL_MOVE(*i); + *i = ETL_MOVE(*first); + + private_heap::adjust_heap(first, difference_t(0), difference_t(middle - first), ETL_MOVE(value), compare); + } + } + + etl::sort_heap(first, middle, compare); + } + + //*************************************************************************** + /// partial_sort + ///\ingroup algorithm + /// + //*************************************************************************** + template + ETL_CONSTEXPR14 + void partial_sort(TIterator first, TIterator middle, TIterator last) + { + typedef etl::less::value_type> compare; + + etl::partial_sort(first, middle, last, compare()); + } + + //*************************************************************************** + /// partial_sort_copy + ///\ingroup algorithm + /// + //*************************************************************************** + template + ETL_CONSTEXPR14 + TRandomAccessIterator partial_sort_copy(TInputIterator first, + TInputIterator last, + TRandomAccessIterator d_first, + TRandomAccessIterator d_last, + TCompare compare) + { + typedef typename etl::iterator_traits::value_type value_t; + typedef typename etl::iterator_traits::difference_type difference_t; + + TRandomAccessIterator result = d_first; + + // Fill the destination range + while ((first != last) && (result != d_last)) + { + *result = *first; + ++result; + ++first; + } + + if (result == d_first) + { + return result; + } + + // Build a max-heap over the destination range + etl::make_heap(d_first, result, compare); + + // Process remaining input elements + for (TInputIterator i = first; i != last; ++i) + { + if (compare(*i, *d_first)) + { + value_t value = *i; + private_heap::adjust_heap(d_first, difference_t(0), difference_t(result - d_first), ETL_MOVE(value), compare); + } + } + + etl::sort_heap(d_first, result, compare); + + return result; + } + + //*************************************************************************** + /// partial_sort_copy + ///\ingroup algorithm + /// + //*************************************************************************** + template + ETL_CONSTEXPR14 + TRandomAccessIterator partial_sort_copy(TInputIterator first, + TInputIterator last, + TRandomAccessIterator d_first, + TRandomAccessIterator d_last) + { + typedef etl::less::value_type> compare; + + return etl::partial_sort_copy(first, last, d_first, d_last, compare()); + } + //*************************************************************************** // Search //*************************************************************************** @@ -1185,7 +1310,6 @@ namespace etl //*************************************************************************** namespace private_algorithm { -#if ETL_USING_CPP11 //********************************* // For random access iterators template @@ -1204,21 +1328,21 @@ namespace etl } typedef typename etl::iterator_traits::value_type value_type; + typedef typename etl::iterator_traits::difference_type difference_type; - int n = last - first; - int m = middle - first; - int gcd_nm = (n == 0 || m == 0) ? n + m : etl::gcd(n, m); - + difference_type n = last - first; + difference_type m = middle - first; + difference_type gcd_nm = (n == 0 || m == 0) ? n + m : etl::gcd(n, m); TIterator result = first + (last - middle); - for (int i = 0; i < gcd_nm; i++) + for (difference_type i = 0; i < gcd_nm; i++) { value_type temp = ETL_MOVE(*(first + i)); - int j = i; + difference_type j = i; while (true) { - int k = j + m; + difference_type k = j + m; if (k >= n) { @@ -1239,61 +1363,6 @@ namespace etl return result; } -#else - //********************************* - // For random access iterators - template - ETL_CONSTEXPR14 - typename etl::enable_if::value, TIterator>::type - rotate_general(TIterator first, TIterator middle, TIterator last) - { - if (first == middle) - { - return last; - } - - if (middle == last) - { - return first; - } - - typedef typename etl::iterator_traits::value_type value_type; - - int n = last - first; - int m = middle - first; - int gcd_nm = (n == 0 || m == 0) ? n + m : etl::gcd(n, m); - - TIterator result = first + (last - middle); - - for (int i = 0; i < gcd_nm; i++) - { - value_type temp = *(first + i); - int j = i; - - while (true) - { - int k = j + m; - - if (k >= n) - { - k = k - n; - } - - if (k == i) - { - break; - } - - *(first + j) = *(first + k); - j = k; - } - - *(first + j) = temp; - } - - return result; - } -#endif //********************************* // For bidirectional iterators @@ -1410,26 +1479,29 @@ namespace etl ETL_CONSTEXPR14 TIterator rotate(TIterator first, TIterator middle, TIterator last) { + if (first == middle) + { + return last; + } + if (middle == last) + { + return first; + } + if (etl::next(first) == middle) { return private_algorithm::rotate_left_by_one(first, last); } +#if ETL_USING_CPP20 if (etl::next(middle) == last) { -#if ETL_USING_CPP20 - if ETL_IF_CONSTEXPR(etl::is_forward_iterator::value) - { - return private_algorithm::rotate_general(first, middle, last); - } - else + if ETL_IF_CONSTEXPR(etl::is_bidirectional_iterator_concept::value) { return private_algorithm::rotate_right_by_one(first, last); } -#else - return private_algorithm::rotate_general(first, middle, last); -#endif } +#endif return private_algorithm::rotate_general(first, middle, last); } @@ -1661,35 +1733,6 @@ namespace etl return compare(b, a) ? ETL_OR_STD::pair(b, a) : ETL_OR_STD::pair(a, b); } - //*************************************************************************** - /// is_sorted_until - ///\ingroup algorithm - /// - //*************************************************************************** - template - ETL_NODISCARD - ETL_CONSTEXPR14 - TIterator is_sorted_until(TIterator begin, - TIterator end) - { - if (begin != end) - { - TIterator next = begin; - - while (++next != end) - { - if (*next < *begin) - { - return next; - } - - ++begin; - } - } - - return end; - } - //*************************************************************************** /// is_sorted_until ///\ingroup algorithm @@ -1720,6 +1763,22 @@ namespace etl return end; } + //*************************************************************************** + /// is_sorted_until + ///\ingroup algorithm + /// + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + TIterator is_sorted_until(TIterator begin, + TIterator end) + { + typedef etl::less::value_type> compare; + + return etl::is_sorted_until(begin, end, compare()); + } + //*************************************************************************** /// is_sorted ///\ingroup algorithm @@ -1788,22 +1847,9 @@ namespace etl TIterator is_unique_sorted_until(TIterator begin, TIterator end) { - if (begin != end) - { - TIterator next = begin; + typedef etl::less::value_type> compare; - while (++next != end) - { - if (!(*begin < *next)) - { - return next; - } - - ++begin; - } - } - - return end; + return etl::is_unique_sorted_until(begin, end, compare()); } //*************************************************************************** @@ -1858,6 +1904,51 @@ namespace etl return end; } + //*************************************************************************** + /// adjacent_find + ///\ingroup algorithm + /// + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + TIterator adjacent_find(TIterator first, TIterator last, TBinaryPredicate predicate) + { + if (first != last) + { + TIterator next = first; + ++next; + + while (next != last) + { + if (predicate(*first, *next)) + { + return first; + } + + ++first; + ++next; + } + } + + return last; + } + + //*************************************************************************** + /// adjacent_find + ///\ingroup algorithm + /// + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + TIterator adjacent_find(TIterator first, TIterator last) + { + typedef etl::equal_to::value_type> predicate; + + return etl::adjacent_find(first, last, predicate()); + } + //*************************************************************************** /// is_permutation ///\ingroup algorithm @@ -1916,9 +2007,9 @@ namespace etl { if (i == etl::find_if(begin1, i, etl::bind1st(predicate, *i))) { - size_t n = etl::count(begin2, end2, *i); + size_t n = etl::count_if(begin2, end2, etl::bind1st(predicate, *i)); - if (n == 0 || size_t(etl::count(i, end1, *i)) != n) + if (n == 0 || size_t(etl::count_if(i, end1, etl::bind1st(predicate, *i))) != n) { return false; } @@ -1942,18 +2033,20 @@ namespace etl TIterator2 begin2, TIterator2 end2) { - if (begin1 != end1) + if (etl::distance(begin1, end1) != etl::distance(begin2, end2)) { - for (TIterator1 i = begin1; i != end1; ++i) - { - if (i == etl::find(begin1, i, *i)) - { - size_t n = etl::count(begin2, end2, *i); + return false; + } - if (n == 0 || size_t(etl::count(i, end1, *i)) != n) - { - return false; - } + for (TIterator1 i = begin1; i != end1; ++i) + { + if (i == etl::find(begin1, i, *i)) + { + size_t n = etl::count(begin2, end2, *i); + + if (n == 0 || size_t(etl::count(i, end1, *i)) != n) + { + return false; } } } @@ -1968,24 +2061,27 @@ namespace etl //*************************************************************************** template ETL_NODISCARD + ETL_CONSTEXPR14 bool is_permutation(TIterator1 begin1, TIterator1 end1, TIterator2 begin2, TIterator2 end2, TBinaryPredicate predicate) { - if (begin1 != end1) + if (etl::distance(begin1, end1) != etl::distance(begin2, end2)) { - for (TIterator1 i = begin1; i != end1; ++i) - { - if (i == etl::find_if(begin1, i, etl::bind1st(predicate, *i))) - { - size_t n = etl::count(begin2, end2, *i); + return false; + } - if (n == 0 || size_t(etl::count(i, end1, *i)) != n) - { - return false; - } + for (TIterator1 i = begin1; i != end1; ++i) + { + if (i == etl::find_if(begin1, i, etl::bind1st(predicate, *i))) + { + size_t n = etl::count_if(begin2, end2, etl::bind1st(predicate, *i)); + + if (n == 0 || size_t(etl::count_if(i, end1, etl::bind1st(predicate, *i))) != n) + { + return false; } } } @@ -2040,14 +2136,22 @@ namespace etl TIterator end, TUnaryPredicate predicate) { - while (begin != end) - { - if (!predicate(*begin)) - { - return begin; - } + typedef typename etl::iterator_traits::difference_type difference_t; - ++begin; + // binary search on a partitioned range + for (difference_t length = etl::distance(begin, end); 0 < length; ) + { + difference_t half = length / 2; + TIterator middle = etl::next(begin, half); + if (predicate(*middle)) + { + begin = etl::next(middle); + length -= (half + 1); + } + else + { + length = half; + } } return begin; @@ -2364,6 +2468,253 @@ namespace etl return first; } + + //*************************************************************************** + /// unique + /// see https://en.cppreference.com/w/cpp/algorithm/unique + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + TIterator unique(TIterator first, TIterator last) + { + if (first == last) + { + return last; + } + + TIterator result = first; + + while (++first != last) + { + if (!(*result == *first) && (++result != first)) + { + *result = ETL_MOVE(*first); + } + } + + return ++result; + } + + //*************************************************************************** + /// unique + /// see https://en.cppreference.com/w/cpp/algorithm/unique + /// predicate overload to determine equality. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + TIterator unique(TIterator first, TIterator last, TBinaryPredicate predicate) + { + if (first == last) + { + return last; + } + + TIterator result = first; + + while (++first != last) + { + if (!predicate(*result, *first) && (++result != first)) + { + *result = ETL_MOVE(*first); + } + } + + return ++result; + } + + //*************************************************************************** + /// unique_copy + /// see https://en.cppreference.com/w/cpp/algorithm/unique_copy + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + TOutputIterator unique_copy(TInputIterator first, + TInputIterator last, + TOutputIterator d_first) + { + if (first == last) + { + return d_first; + } + + typename etl::iterator_traits::value_type prev = *first; + *d_first = prev; + + while (++first != last) + { + if (!(prev == *first)) + { + prev = *first; + *(++d_first) = prev; + } + } + + return ++d_first; + } + + //*************************************************************************** + /// unique_copy + /// see https://en.cppreference.com/w/cpp/algorithm/unique_copy + /// predicate overload to determine equality. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + TOutputIterator unique_copy(TInputIterator first, + TInputIterator last, + TOutputIterator d_first, + TBinaryPredicate predicate) + { + if (first == last) + { + return d_first; + } + + typename etl::iterator_traits::value_type prev = *first; + *d_first = prev; + + while (++first != last) + { + if (!predicate(prev, *first)) + { + prev = *first; + *(++d_first) = prev; + } + } + + return ++d_first; + } + + //*************************************************************************** + /// merge + /// Merges two sorted ranges into one sorted range. + /// see https://en.cppreference.com/w/cpp/algorithm/merge + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + TOutputIterator merge(TInputIterator1 first1, TInputIterator1 last1, + TInputIterator2 first2, TInputIterator2 last2, + TOutputIterator d_first, + TCompare compare) + { + while ((first1 != last1) && (first2 != last2)) + { + if (compare(*first2, *first1)) + { + *d_first = *first2; + ++first2; + } + else + { + *d_first = *first1; + ++first1; + } + ++d_first; + } + + d_first = etl::copy(first1, last1, d_first); + d_first = etl::copy(first2, last2, d_first); + + return d_first; + } + + //*************************************************************************** + /// merge + /// Merges two sorted ranges into one sorted range. + /// Uses operator< for comparison. + /// see https://en.cppreference.com/w/cpp/algorithm/merge + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + TOutputIterator merge(TInputIterator1 first1, TInputIterator1 last1, + TInputIterator2 first2, TInputIterator2 last2, + TOutputIterator d_first) + { + typedef etl::less::value_type> compare; + + return etl::merge(first1, last1, first2, last2, d_first, compare()); + } + + //*************************************************************************** + /// inplace_merge + /// Merges two consecutive sorted ranges [first, middle) and [middle, last) + /// into one sorted range [first, last) in-place. + /// Uses an iterative rotate-based algorithm that requires no additional + /// memory, no recursion and no explicit stack, making it safe for deeply + /// embedded targets with constrained stack sizes. + /// Complexity: O(N log N) comparisons, O(N log N) element moves. + /// see https://en.cppreference.com/w/cpp/algorithm/inplace_merge + ///\ingroup algorithm + //*************************************************************************** + template + void inplace_merge(TBidirectionalIterator first, + TBidirectionalIterator middle, + TBidirectionalIterator last, + TCompare compare) + { + typedef typename etl::iterator_traits::difference_type difference_type; + + difference_type len1 = etl::distance(first, middle); + difference_type len2 = etl::distance(middle, last); + + while ((len1 != 0) && (len2 != 0)) + { + // Find where the first element of the right half belongs in the left half. + // All elements in [first, cut1) are <= *middle, so they are already in place. + TBidirectionalIterator cut1 = etl::upper_bound(first, middle, *middle, compare); + difference_type prefix = etl::distance(first, cut1); + len1 -= prefix; + + // If the entire left half is <= *middle, we are done. + if (len1 == 0) + { + return; + } + + // Advance first past the already-placed prefix. + first = cut1; + + // Find where the first element of the (remaining) left half belongs in + // the right half. All elements in [middle, cut2) are < *first, so they + // need to be moved before *first. + TBidirectionalIterator cut2 = etl::lower_bound(middle, last, *first, compare); + difference_type run = etl::distance(middle, cut2); + len2 -= run; + + // Rotate the block [first, middle, cut2) so that [middle, cut2) moves + // before [first, middle). After the rotate the elements from + // [middle, cut2) (length = run) now occupy [first, first + run) and + // are in their final position. + etl::rotate(first, middle, cut2); + + // Advance past the block we just placed. + etl::advance(first, run); + middle = cut2; + } + } + + //*************************************************************************** + /// inplace_merge + /// Merges two consecutive sorted ranges [first, middle) and [middle, last) + /// into one sorted range [first, last) in-place. + /// Uses operator< for comparison. + /// see https://en.cppreference.com/w/cpp/algorithm/inplace_merge + ///\ingroup algorithm + //*************************************************************************** + template + void inplace_merge(TBidirectionalIterator first, + TBidirectionalIterator middle, + TBidirectionalIterator last) + { + typedef etl::less::value_type> compare; + + etl::inplace_merge(first, middle, last, compare()); + } } //***************************************************************************** @@ -3160,6 +3511,11 @@ namespace etl ETL_CONSTEXPR20 void selection_sort(TIterator first, TIterator last, TCompare compare) { + if (first == last) + { + return; + } + TIterator min; const TIterator ilast = private_algorithm::get_before_last(first, last); const TIterator jlast = last; @@ -3180,7 +3536,10 @@ namespace etl } using ETL_OR_STD::swap; // Allow ADL - swap(*i, *min); + if (min != i) + { + swap(*i, *min); + } } } @@ -3204,11 +3563,7 @@ namespace etl ETL_CONSTEXPR14 void heap_sort(TIterator first, TIterator last, TCompare compare) { - if (!etl::is_heap(first, last, compare)) - { - etl::make_heap(first, last, compare); - } - + etl::make_heap(first, last, compare); etl::sort_heap(first, last, compare); } @@ -3220,11 +3575,7 @@ namespace etl ETL_CONSTEXPR14 void heap_sort(TIterator first, TIterator last) { - if (!etl::is_heap(first, last)) - { - etl::make_heap(first, last); - } - + etl::make_heap(first, last); etl::sort_heap(first, last); } @@ -3268,7 +3619,7 @@ namespace etl #endif //*************************************************************************** - /// Returns the maximum value. + /// Returns the minimum value. //*************************************************************************** #if ETL_USING_CPP11 template @@ -3464,14 +3815,7 @@ namespace etl { typedef typename etl::iterator_traits::value_type value_type; - TIterator pivot = last; // Maybe find a better pivot choice? - value_type pivot_value = *pivot; - - // Swap the pivot with the last, if necessary. - if (pivot != last) - { - swap(*pivot, *last); - } + value_type pivot_value = ETL_MOVE(*last); TIterator i = first; @@ -3570,7 +3914,7 @@ namespace etl { typedef etl::less::value_type> compare_t; - nth_element(first, last, compare_t()); + nth_element(first, nth, last, compare_t()); } #endif } diff --git a/test/test_algorithm.cpp b/test/test_algorithm.cpp index 4dd01e9f..1429a977 100644 --- a/test/test_algorithm.cpp +++ b/test/test_algorithm.cpp @@ -747,6 +747,62 @@ namespace } } + //************************************************************************* + TEST(binary_search_random_iterator) + { + for (int i = 0; i < 11; ++i) + { + bool expected = std::binary_search(std::begin(dataS), std::end(dataS), i); + bool result = etl::binary_search(std::begin(dataS), std::end(dataS), i); + + CHECK_EQUAL(expected, result); + } + } + + //************************************************************************* + TEST(binary_search_with_compare) + { + for (int i = 0; i < 11; ++i) + { + bool expected = std::binary_search(std::begin(dataS), std::end(dataS), i, etl::less()); + bool result = etl::binary_search(std::begin(dataS), std::end(dataS), i, etl::less()); + + CHECK_EQUAL(expected, result); + } + } + + //************************************************************************* + TEST(binary_search_duplicates) + { + for (int i = 0; i < 11; ++i) + { + bool expected = std::binary_search(std::begin(dataEQ), std::end(dataEQ), i); + bool result = etl::binary_search(std::begin(dataEQ), std::end(dataEQ), i); + + CHECK_EQUAL(expected, result); + } + } + + //************************************************************************* + TEST(binary_search_empty_range) + { + int empty[] = { 0 }; + + bool result = etl::binary_search(std::begin(empty), std::begin(empty), 1); + + CHECK_EQUAL(false, result); + } + + //************************************************************************* + TEST(binary_search_single_element) + { + int single[] = { 5 }; + + CHECK_EQUAL(true, etl::binary_search(std::begin(single), std::end(single), 5)); + CHECK_EQUAL(false, etl::binary_search(std::begin(single), std::end(single), 3)); + CHECK_EQUAL(false, etl::binary_search(std::begin(single), std::end(single), 7)); + } + //************************************************************************* TEST(fill_non_char) { @@ -795,6 +851,144 @@ namespace CHECK_EQUAL(1, b); } + //************************************************************************* + TEST(swap_ranges_pod_pointer) + { + int data1[] = { 1, 2, 3, 4, 5 }; + int data2[] = { 6, 7, 8, 9, 10 }; + + int expected1[] = { 6, 7, 8, 9, 10 }; + int expected2[] = { 1, 2, 3, 4, 5 }; + + int* result = etl::swap_ranges(std::begin(data1), std::end(data1), std::begin(data2)); + + CHECK_EQUAL(std::end(data2), result); + + bool isEqual1 = std::equal(std::begin(data1), std::end(data1), std::begin(expected1)); + CHECK(isEqual1); + + bool isEqual2 = std::equal(std::begin(data2), std::end(data2), std::begin(expected2)); + CHECK(isEqual2); + } + + //************************************************************************* + TEST(swap_ranges_non_pod_pointer) + { + Data data1[] = { Data(1, 2), Data(3, 4), Data(5, 6) }; + Data data2[] = { Data(7, 8), Data(9, 10), Data(11, 12) }; + + Data expected1[] = { Data(7, 8), Data(9, 10), Data(11, 12) }; + Data expected2[] = { Data(1, 2), Data(3, 4), Data(5, 6) }; + + Data* result = etl::swap_ranges(std::begin(data1), std::end(data1), std::begin(data2)); + + CHECK_EQUAL(std::end(data2), result); + + bool isEqual1 = std::equal(std::begin(data1), std::end(data1), std::begin(expected1)); + CHECK(isEqual1); + + bool isEqual2 = std::equal(std::begin(data2), std::end(data2), std::begin(expected2)); + CHECK(isEqual2); + } + + //************************************************************************* + TEST(swap_ranges_non_random_iterator) + { + List data1 = { 1, 2, 3, 4, 5 }; + List data2 = { 6, 7, 8, 9, 10 }; + + List expected1 = { 6, 7, 8, 9, 10 }; + List expected2 = { 1, 2, 3, 4, 5 }; + + List::iterator result = etl::swap_ranges(data1.begin(), data1.end(), data2.begin()); + + CHECK(data2.end() == result); + + bool isEqual1 = std::equal(data1.begin(), data1.end(), expected1.begin()); + CHECK(isEqual1); + + bool isEqual2 = std::equal(data2.begin(), data2.end(), expected2.begin()); + CHECK(isEqual2); + } + + //************************************************************************* + TEST(swap_ranges_empty_range) + { + int data1[] = { 1, 2, 3 }; + int data2[] = { 4, 5, 6 }; + + int expected1[] = { 1, 2, 3 }; + int expected2[] = { 4, 5, 6 }; + + int* result = etl::swap_ranges(std::begin(data1), std::begin(data1), std::begin(data2)); + + CHECK_EQUAL(std::begin(data2), result); + + bool isEqual1 = std::equal(std::begin(data1), std::end(data1), std::begin(expected1)); + CHECK(isEqual1); + + bool isEqual2 = std::equal(std::begin(data2), std::end(data2), std::begin(expected2)); + CHECK(isEqual2); + } + + //************************************************************************* + TEST(swap_ranges_partial_range) + { + int data1[] = { 1, 2, 3, 4, 5 }; + int data2[] = { 6, 7, 8, 9, 10 }; + + int expected1[] = { 6, 7, 8, 4, 5 }; + int expected2[] = { 1, 2, 3, 9, 10 }; + + int* result = etl::swap_ranges(std::begin(data1), std::begin(data1) + 3, std::begin(data2)); + + CHECK_EQUAL(std::begin(data2) + 3, result); + + bool isEqual1 = std::equal(std::begin(data1), std::end(data1), std::begin(expected1)); + CHECK(isEqual1); + + bool isEqual2 = std::equal(std::begin(data2), std::end(data2), std::begin(expected2)); + CHECK(isEqual2); + } + + //************************************************************************* + TEST(swap_ranges_same_data) + { + int data1[] = { 1, 2, 3, 4, 5 }; + int expected[] = { 1, 2, 3, 4, 5 }; + + etl::swap_ranges(std::begin(data1), std::end(data1), std::begin(data1)); + + bool isEqual = std::equal(std::begin(data1), std::end(data1), std::begin(expected)); + CHECK(isEqual); + } + + //************************************************************************* + TEST(swap_ranges_matches_std) + { + int data1_std[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + int data2_std[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + + int data1_etl[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + int data2_etl[] = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + + int* pstl = std::swap_ranges(std::begin(data1_std), std::end(data1_std), std::begin(data2_std)); + int* petl = etl::swap_ranges(std::begin(data1_etl), std::end(data1_etl), std::begin(data2_etl)); + + using difference_type_t = std::iterator_traits::difference_type; + + difference_type_t dstl = std::distance(data2_std, pstl); + difference_type_t detl = std::distance(data2_etl, petl); + + CHECK_EQUAL(dstl, detl); + + bool isEqual1 = std::equal(std::begin(data1_std), std::end(data1_std), std::begin(data1_etl)); + CHECK(isEqual1); + + bool isEqual2 = std::equal(std::begin(data2_std), std::end(data2_std), std::begin(data2_etl)); + CHECK(isEqual2); + } + //************************************************************************* TEST(equal) { @@ -854,6 +1048,314 @@ namespace CHECK(itr1 == itr2); } + //************************************************************************* + TEST(find_end_default) + { + int data[] = { 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4 }; + int pattern[] = { 1, 2, 3 }; + + int* expected = std::find_end(std::begin(data), std::end(data), std::begin(pattern), std::end(pattern)); + int* result = etl::find_end(std::begin(data), std::end(data), std::begin(pattern), std::end(pattern)); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(find_end_predicate) + { + int data[] = { 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4 }; + int pattern[] = { 1, 2, 3 }; + + int* expected = std::find_end(std::begin(data), std::end(data), std::begin(pattern), std::end(pattern), std::equal_to()); + int* result = etl::find_end(std::begin(data), std::end(data), std::begin(pattern), std::end(pattern), std::equal_to()); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(find_end_single_occurrence) + { + int data[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + int pattern[] = { 5, 6, 7 }; + + int* expected = std::find_end(std::begin(data), std::end(data), std::begin(pattern), std::end(pattern)); + int* result = etl::find_end(std::begin(data), std::end(data), std::begin(pattern), std::end(pattern)); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(find_end_no_match) + { + int data[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + int pattern[] = { 11, 12 }; + + int* expected = std::find_end(std::begin(data), std::end(data), std::begin(pattern), std::end(pattern)); + int* result = etl::find_end(std::begin(data), std::end(data), std::begin(pattern), std::end(pattern)); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(find_end_empty_sequence) + { + int data[] = { 1, 2, 3, 4, 5 }; + int pattern[] = { 0 }; + + int* expected = std::find_end(std::begin(data), std::end(data), std::begin(pattern), std::begin(pattern)); + int* result = etl::find_end(std::begin(data), std::end(data), std::begin(pattern), std::begin(pattern)); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(find_end_pattern_at_end) + { + int data[] = { 1, 2, 3, 4, 5, 6, 7 }; + int pattern[] = { 5, 6, 7 }; + + int* expected = std::find_end(std::begin(data), std::end(data), std::begin(pattern), std::end(pattern)); + int* result = etl::find_end(std::begin(data), std::end(data), std::begin(pattern), std::end(pattern)); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(find_end_pattern_at_start) + { + int data[] = { 1, 2, 3, 4, 5, 6, 7 }; + int pattern[] = { 1, 2, 3 }; + + int* expected = std::find_end(std::begin(data), std::end(data), std::begin(pattern), std::end(pattern)); + int* result = etl::find_end(std::begin(data), std::end(data), std::begin(pattern), std::end(pattern)); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(find_end_entire_range_matches) + { + int data[] = { 1, 2, 3, 4, 5 }; + int pattern[] = { 1, 2, 3, 4, 5 }; + + int* expected = std::find_end(std::begin(data), std::end(data), std::begin(pattern), std::end(pattern)); + int* result = etl::find_end(std::begin(data), std::end(data), std::begin(pattern), std::end(pattern)); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(find_end_overlapping_occurrences) + { + int data[] = { 1, 1, 1, 1, 1 }; + int pattern[] = { 1, 1 }; + + int* expected = std::find_end(std::begin(data), std::end(data), std::begin(pattern), std::end(pattern)); + int* result = etl::find_end(std::begin(data), std::end(data), std::begin(pattern), std::end(pattern)); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(find_end_single_element_pattern) + { + int data[] = { 1, 2, 3, 2, 5, 2, 7 }; + int pattern[] = { 2 }; + + int* expected = std::find_end(std::begin(data), std::end(data), std::begin(pattern), std::end(pattern)); + int* result = etl::find_end(std::begin(data), std::end(data), std::begin(pattern), std::end(pattern)); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(find_end_non_random_iterator) + { + int data_array[] = { 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4 }; + int pattern_array[] = { 1, 2, 3 }; + + List data(std::begin(data_array), std::end(data_array)); + List pattern(std::begin(pattern_array), std::end(pattern_array)); + + List::iterator expected = std::find_end(data.begin(), data.end(), pattern.begin(), pattern.end(), std::equal_to()); + List::iterator result = etl::find_end(data.begin(), data.end(), pattern.begin(), pattern.end(), std::equal_to()); + + CHECK(expected == result); + } + + //************************************************************************* + TEST(find_end_non_random_iterator_predicate) + { + int data_array[] = { 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4 }; + int pattern_array[] = { 1, 2, 3 }; + + List data(std::begin(data_array), std::end(data_array)); + List pattern(std::begin(pattern_array), std::end(pattern_array)); + + List::iterator expected = std::find_end(data.begin(), data.end(), pattern.begin(), pattern.end(), std::equal_to()); + List::iterator result = etl::find_end(data.begin(), data.end(), pattern.begin(), pattern.end(), std::equal_to()); + + CHECK(expected == result); + } + + //************************************************************************* + TEST(find_end_pattern_longer_than_data) + { + int data[] = { 1, 2, 3 }; + int pattern[] = { 1, 2, 3, 4, 5 }; + + int* expected = std::find_end(std::begin(data), std::end(data), std::begin(pattern), std::end(pattern)); + int* result = etl::find_end(std::begin(data), std::end(data), std::begin(pattern), std::end(pattern)); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(adjacent_find_default) + { + int data[] = { 1, 2, 3, 3, 4, 5 }; + + int* expected = std::adjacent_find(std::begin(data), std::end(data)); + int* result = etl::adjacent_find(std::begin(data), std::end(data)); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(adjacent_find_predicate) + { + int data[] = { 1, 2, 3, 3, 4, 5 }; + + int* expected = std::adjacent_find(std::begin(data), std::end(data), std::equal_to()); + int* result = etl::adjacent_find(std::begin(data), std::end(data), std::equal_to()); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(adjacent_find_no_match) + { + int data[] = { 1, 2, 3, 4, 5, 6 }; + + int* expected = std::adjacent_find(std::begin(data), std::end(data)); + int* result = etl::adjacent_find(std::begin(data), std::end(data)); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(adjacent_find_at_beginning) + { + int data[] = { 1, 1, 2, 3, 4, 5 }; + + int* expected = std::adjacent_find(std::begin(data), std::end(data)); + int* result = etl::adjacent_find(std::begin(data), std::end(data)); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(adjacent_find_at_end) + { + int data[] = { 1, 2, 3, 4, 5, 5 }; + + int* expected = std::adjacent_find(std::begin(data), std::end(data)); + int* result = etl::adjacent_find(std::begin(data), std::end(data)); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(adjacent_find_multiple_pairs) + { + int data[] = { 1, 1, 2, 2, 3, 3 }; + + int* expected = std::adjacent_find(std::begin(data), std::end(data)); + int* result = etl::adjacent_find(std::begin(data), std::end(data)); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(adjacent_find_single_element) + { + int data[] = { 1 }; + + int* expected = std::adjacent_find(std::begin(data), std::end(data)); + int* result = etl::adjacent_find(std::begin(data), std::end(data)); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(adjacent_find_empty_range) + { + int data[] = { 1 }; + + int* expected = std::adjacent_find(std::begin(data), std::begin(data)); + int* result = etl::adjacent_find(std::begin(data), std::begin(data)); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(adjacent_find_all_same) + { + int data[] = { 5, 5, 5, 5, 5 }; + + int* expected = std::adjacent_find(std::begin(data), std::end(data)); + int* result = etl::adjacent_find(std::begin(data), std::end(data)); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(adjacent_find_predicate_less) + { + int data[] = { 5, 4, 3, 2, 1 }; + + int* expected = std::adjacent_find(std::begin(data), std::end(data), std::greater()); + int* result = etl::adjacent_find(std::begin(data), std::end(data), std::greater()); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(adjacent_find_non_random_iterator) + { + int data_array[] = { 1, 2, 3, 3, 4, 5 }; + List data(std::begin(data_array), std::end(data_array)); + + List::iterator expected = std::adjacent_find(data.begin(), data.end()); + List::iterator result = etl::adjacent_find(data.begin(), data.end()); + + CHECK(expected == result); + } + + //************************************************************************* + TEST(adjacent_find_non_random_iterator_predicate) + { + int data_array[] = { 1, 2, 3, 3, 4, 5 }; + List data(std::begin(data_array), std::end(data_array)); + + List::iterator expected = std::adjacent_find(data.begin(), data.end(), std::equal_to()); + List::iterator result = etl::adjacent_find(data.begin(), data.end(), std::equal_to()); + + CHECK(expected == result); + } + + //************************************************************************* + TEST(adjacent_find_non_random_iterator_no_match) + { + int data_array[] = { 1, 2, 3, 4, 5, 6 }; + List data(std::begin(data_array), std::end(data_array)); + + List::iterator expected = std::adjacent_find(data.begin(), data.end()); + List::iterator result = etl::adjacent_find(data.begin(), data.end()); + + CHECK(expected == result); + } + //************************************************************************* TEST(heap) { @@ -1021,6 +1523,663 @@ namespace CHECK(isEqual); } + //************************************************************************* + TEST(is_heap_default_true) + { + std::vector data = { 9, 8, 7, 6, 5, 4, 3, 2, 1 }; + std::make_heap(data.begin(), data.end()); + + bool expected = std::is_heap(data.begin(), data.end()); + bool result = etl::is_heap(data.begin(), data.end()); + + CHECK_EQUAL(expected, result); + CHECK(result); + } + + //************************************************************************* + TEST(is_heap_default_false) + { + std::vector data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + bool expected = std::is_heap(data.begin(), data.end()); + bool result = etl::is_heap(data.begin(), data.end()); + + CHECK_EQUAL(expected, result); + CHECK(!result); + } + + //************************************************************************* + TEST(is_heap_compare_true) + { + std::vector data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + std::make_heap(data.begin(), data.end(), Greater()); + + bool expected = std::is_heap(data.begin(), data.end(), Greater()); + bool result = etl::is_heap(data.begin(), data.end(), Greater()); + + CHECK_EQUAL(expected, result); + CHECK(result); + } + + //************************************************************************* + TEST(is_heap_compare_false) + { + std::vector data = { 9, 8, 7, 6, 5, 4, 3, 2, 1 }; + + bool expected = std::is_heap(data.begin(), data.end(), Greater()); + bool result = etl::is_heap(data.begin(), data.end(), Greater()); + + CHECK_EQUAL(expected, result); + CHECK(!result); + } + + //************************************************************************* + TEST(is_heap_empty) + { + std::vector data; + + bool expected = std::is_heap(data.begin(), data.end()); + bool result = etl::is_heap(data.begin(), data.end()); + + CHECK_EQUAL(expected, result); + CHECK(result); + } + + //************************************************************************* + TEST(is_heap_single_element) + { + std::vector data = { 42 }; + + bool expected = std::is_heap(data.begin(), data.end()); + bool result = etl::is_heap(data.begin(), data.end()); + + CHECK_EQUAL(expected, result); + CHECK(result); + } + + //************************************************************************* + TEST(is_heap_two_elements) + { + std::vector data1 = { 5, 3 }; + std::vector data2 = { 3, 5 }; + + CHECK_EQUAL(std::is_heap(data1.begin(), data1.end()), etl::is_heap(data1.begin(), data1.end())); + CHECK_EQUAL(std::is_heap(data2.begin(), data2.end()), etl::is_heap(data2.begin(), data2.end())); + } + + //************************************************************************* + TEST(is_heap_pointer) + { + int data[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }; + + bool expected = std::is_heap(std::begin(data), std::end(data)); + bool result = etl::is_heap(std::begin(data), std::end(data)); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(is_heap_after_make_heap) + { + // Test all permutations of a small dataset + std::vector data = { 1, 2, 3, 4, 5 }; + + do + { + std::vector test_data(data); + etl::make_heap(test_data.begin(), test_data.end()); + CHECK(etl::is_heap(test_data.begin(), test_data.end())); + } while (std::next_permutation(data.begin(), data.end())); + } + + //************************************************************************* + TEST(sort_heap_default) + { + std::vector data1 = { 5, 3, 8, 1, 9, 2, 7, 4, 6, 10 }; + std::vector data2(data1); + + std::make_heap(data1.begin(), data1.end()); + etl::make_heap(data2.begin(), data2.end()); + + std::sort_heap(data1.begin(), data1.end()); + etl::sort_heap(data2.begin(), data2.end()); + + bool isEqual = std::equal(data1.begin(), data1.end(), data2.begin()); + CHECK(isEqual); + + // Verify sorted ascending + CHECK(std::is_sorted(data2.begin(), data2.end())); + } + + //************************************************************************* + TEST(sort_heap_compare) + { + std::vector data1 = { 5, 3, 8, 1, 9, 2, 7, 4, 6, 10 }; + std::vector data2(data1); + + std::make_heap(data1.begin(), data1.end(), Greater()); + etl::make_heap(data2.begin(), data2.end(), Greater()); + + std::sort_heap(data1.begin(), data1.end(), Greater()); + etl::sort_heap(data2.begin(), data2.end(), Greater()); + + bool isEqual = std::equal(data1.begin(), data1.end(), data2.begin()); + CHECK(isEqual); + + // Verify sorted descending + CHECK(std::is_sorted(data2.begin(), data2.end(), Greater())); + } + + //************************************************************************* + TEST(sort_heap_empty) + { + std::vector data; + + etl::sort_heap(data.begin(), data.end()); + + CHECK(data.empty()); + } + + //************************************************************************* + TEST(sort_heap_single_element) + { + std::vector data = { 42 }; + + etl::sort_heap(data.begin(), data.end()); + + CHECK_EQUAL(1U, data.size()); + CHECK_EQUAL(42, data[0]); + } + + //************************************************************************* + TEST(sort_heap_pointer) + { + int data1[] = { 5, 3, 8, 1, 9, 2, 7, 4, 6, 10 }; + int data2[] = { 5, 3, 8, 1, 9, 2, 7, 4, 6, 10 }; + + std::make_heap(std::begin(data1), std::end(data1)); + etl::make_heap(std::begin(data2), std::end(data2)); + + std::sort_heap(std::begin(data1), std::end(data1)); + etl::sort_heap(std::begin(data2), std::end(data2)); + + bool isEqual = std::equal(std::begin(data1), std::end(data1), std::begin(data2)); + CHECK(isEqual); + } + + //************************************************************************* + TEST(sort_heap_all_permutations) + { + std::vector initial = { 1, 2, 3, 4, 5 }; + + do + { + std::vector data1(initial); + std::vector data2(initial); + + std::make_heap(data1.begin(), data1.end()); + etl::make_heap(data2.begin(), data2.end()); + + std::sort_heap(data1.begin(), data1.end()); + etl::sort_heap(data2.begin(), data2.end()); + + bool isEqual = std::equal(data1.begin(), data1.end(), data2.begin()); + CHECK(isEqual); + } while (std::next_permutation(initial.begin(), initial.end())); + } + + //************************************************************************* + TEST(sort_heap_duplicates) + { + std::vector data1 = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5 }; + std::vector data2(data1); + + std::make_heap(data1.begin(), data1.end()); + etl::make_heap(data2.begin(), data2.end()); + + std::sort_heap(data1.begin(), data1.end()); + etl::sort_heap(data2.begin(), data2.end()); + + bool isEqual = std::equal(data1.begin(), data1.end(), data2.begin()); + CHECK(isEqual); + } + + //************************************************************************* + TEST(partial_sort_default) + { + std::vector data1 = { 5, 3, 8, 1, 9, 2, 7, 4, 6, 10 }; + std::vector data2(data1); + + std::partial_sort(data1.begin(), data1.begin() + 5, data1.end()); + etl::partial_sort(data2.begin(), data2.begin() + 5, data2.end()); + + // The first 5 elements should be sorted and match std + bool isEqual = std::equal(data1.begin(), data1.begin() + 5, data2.begin()); + CHECK(isEqual); + + // Verify sorted range + CHECK(std::is_sorted(data2.begin(), data2.begin() + 5)); + } + + //************************************************************************* + TEST(partial_sort_compare) + { + std::vector data1 = { 5, 3, 8, 1, 9, 2, 7, 4, 6, 10 }; + std::vector data2(data1); + + std::partial_sort(data1.begin(), data1.begin() + 5, data1.end(), Greater()); + etl::partial_sort(data2.begin(), data2.begin() + 5, data2.end(), Greater()); + + // The first 5 elements should be sorted descending and match std + bool isEqual = std::equal(data1.begin(), data1.begin() + 5, data2.begin()); + CHECK(isEqual); + + // Verify sorted range (descending) + CHECK(std::is_sorted(data2.begin(), data2.begin() + 5, Greater())); + } + + //************************************************************************* + TEST(partial_sort_empty) + { + std::vector data; + + etl::partial_sort(data.begin(), data.begin(), data.end()); + + CHECK(data.empty()); + } + + //************************************************************************* + TEST(partial_sort_middle_equals_first) + { + std::vector data = { 5, 3, 8, 1, 9 }; + std::vector original(data); + + etl::partial_sort(data.begin(), data.begin(), data.end()); + + // Nothing should change when middle == first + bool isEqual = std::equal(data.begin(), data.end(), original.begin()); + CHECK(isEqual); + } + + //************************************************************************* + TEST(partial_sort_middle_equals_last) + { + std::vector data1 = { 5, 3, 8, 1, 9 }; + std::vector data2(data1); + + std::partial_sort(data1.begin(), data1.end(), data1.end()); + etl::partial_sort(data2.begin(), data2.end(), data2.end()); + + // Full sort + bool isEqual = std::equal(data1.begin(), data1.end(), data2.begin()); + CHECK(isEqual); + + CHECK(std::is_sorted(data2.begin(), data2.end())); + } + + //************************************************************************* + TEST(partial_sort_single_element) + { + std::vector data = { 42 }; + + etl::partial_sort(data.begin(), data.end(), data.end()); + + CHECK_EQUAL(1U, data.size()); + CHECK_EQUAL(42, data[0]); + } + + //************************************************************************* + TEST(partial_sort_first_one) + { + std::vector data1 = { 5, 3, 8, 1, 9, 2, 7, 4, 6, 10 }; + std::vector data2(data1); + + std::partial_sort(data1.begin(), data1.begin() + 1, data1.end()); + etl::partial_sort(data2.begin(), data2.begin() + 1, data2.end()); + + // The first element should be the minimum + CHECK_EQUAL(data1[0], data2[0]); + CHECK_EQUAL(1, data2[0]); + } + + //************************************************************************* + TEST(partial_sort_duplicates) + { + std::vector data1 = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5 }; + std::vector data2(data1); + + std::partial_sort(data1.begin(), data1.begin() + 6, data1.end()); + etl::partial_sort(data2.begin(), data2.begin() + 6, data2.end()); + + bool isEqual = std::equal(data1.begin(), data1.begin() + 6, data2.begin()); + CHECK(isEqual); + + CHECK(std::is_sorted(data2.begin(), data2.begin() + 6)); + } + + //************************************************************************* + TEST(partial_sort_already_sorted) + { + std::vector data1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + std::vector data2(data1); + + std::partial_sort(data1.begin(), data1.begin() + 5, data1.end()); + etl::partial_sort(data2.begin(), data2.begin() + 5, data2.end()); + + bool isEqual = std::equal(data1.begin(), data1.begin() + 5, data2.begin()); + CHECK(isEqual); + + CHECK(std::is_sorted(data2.begin(), data2.begin() + 5)); + } + + //************************************************************************* + TEST(partial_sort_reverse_sorted) + { + std::vector data1 = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }; + std::vector data2(data1); + + std::partial_sort(data1.begin(), data1.begin() + 5, data1.end()); + etl::partial_sort(data2.begin(), data2.begin() + 5, data2.end()); + + bool isEqual = std::equal(data1.begin(), data1.begin() + 5, data2.begin()); + CHECK(isEqual); + + CHECK(std::is_sorted(data2.begin(), data2.begin() + 5)); + } + + //************************************************************************* + TEST(partial_sort_pointer) + { + int data1[] = { 5, 3, 8, 1, 9, 2, 7, 4, 6, 10 }; + int data2[] = { 5, 3, 8, 1, 9, 2, 7, 4, 6, 10 }; + + std::partial_sort(std::begin(data1), std::begin(data1) + 5, std::end(data1)); + etl::partial_sort(std::begin(data2), std::begin(data2) + 5, std::end(data2)); + + bool isEqual = std::equal(std::begin(data1), std::begin(data1) + 5, std::begin(data2)); + CHECK(isEqual); + } + + //************************************************************************* + TEST(partial_sort_all_permutations) + { + std::vector initial = { 1, 2, 3, 4, 5 }; + + do + { + std::vector data1(initial); + std::vector data2(initial); + + std::partial_sort(data1.begin(), data1.begin() + 3, data1.end()); + etl::partial_sort(data2.begin(), data2.begin() + 3, data2.end()); + + bool isEqual = std::equal(data1.begin(), data1.begin() + 3, data2.begin()); + CHECK(isEqual); + } while (std::next_permutation(initial.begin(), initial.end())); + } + + //************************************************************************* + TEST(partial_sort_all_equal) + { + std::vector data = { 5, 5, 5, 5, 5, 5 }; + + etl::partial_sort(data.begin(), data.begin() + 3, data.end()); + + CHECK(std::is_sorted(data.begin(), data.begin() + 3)); + + for (size_t i = 0; i < data.size(); ++i) + { + CHECK_EQUAL(5, data[i]); + } + } + + //************************************************************************* + TEST(partial_sort_copy_default) + { + std::vector input = { 5, 3, 8, 1, 9, 2, 7, 4, 6, 10 }; + std::vector output1(5); + std::vector output2(5); + + std::partial_sort_copy(input.begin(), input.end(), output1.begin(), output1.end()); + etl::partial_sort_copy(input.begin(), input.end(), output2.begin(), output2.end()); + + bool isEqual = std::equal(output1.begin(), output1.end(), output2.begin()); + CHECK(isEqual); + + CHECK(std::is_sorted(output2.begin(), output2.end())); + } + + //************************************************************************* + TEST(partial_sort_copy_compare) + { + std::vector input = { 5, 3, 8, 1, 9, 2, 7, 4, 6, 10 }; + std::vector output1(5); + std::vector output2(5); + + std::partial_sort_copy(input.begin(), input.end(), output1.begin(), output1.end(), Greater()); + etl::partial_sort_copy(input.begin(), input.end(), output2.begin(), output2.end(), Greater()); + + bool isEqual = std::equal(output1.begin(), output1.end(), output2.begin()); + CHECK(isEqual); + + CHECK(std::is_sorted(output2.begin(), output2.end(), Greater())); + } + + //************************************************************************* + TEST(partial_sort_copy_empty_input) + { + std::vector input; + std::vector output(5, 99); + + auto result = etl::partial_sort_copy(input.begin(), input.end(), output.begin(), output.end()); + + CHECK(result == output.begin()); + + // Output should be unchanged + for (size_t i = 0; i < output.size(); ++i) + { + CHECK_EQUAL(99, output[i]); + } + } + + //************************************************************************* + TEST(partial_sort_copy_empty_output) + { + std::vector input = { 5, 3, 8, 1, 9 }; + std::vector output; + + auto result = etl::partial_sort_copy(input.begin(), input.end(), output.begin(), output.end()); + + CHECK(result == output.begin()); + } + + //************************************************************************* + TEST(partial_sort_copy_output_larger_than_input) + { + std::vector input = { 5, 3, 1 }; + std::vector output1(6, 99); + std::vector output2(6, 99); + + auto result1 = std::partial_sort_copy(input.begin(), input.end(), output1.begin(), output1.end()); + auto result2 = etl::partial_sort_copy(input.begin(), input.end(), output2.begin(), output2.end()); + + CHECK_EQUAL(std::distance(output1.begin(), result1), std::distance(output2.begin(), result2)); + + bool isEqual = std::equal(output1.begin(), result1, output2.begin()); + CHECK(isEqual); + + CHECK(std::is_sorted(output2.begin(), result2)); + } + + //************************************************************************* + TEST(partial_sort_copy_output_smaller_than_input) + { + std::vector input = { 5, 3, 8, 1, 9, 2, 7, 4, 6, 10 }; + std::vector output1(3); + std::vector output2(3); + + std::partial_sort_copy(input.begin(), input.end(), output1.begin(), output1.end()); + etl::partial_sort_copy(input.begin(), input.end(), output2.begin(), output2.end()); + + bool isEqual = std::equal(output1.begin(), output1.end(), output2.begin()); + CHECK(isEqual); + + CHECK(std::is_sorted(output2.begin(), output2.end())); + } + + //************************************************************************* + TEST(partial_sort_copy_output_same_size_as_input) + { + std::vector input = { 5, 3, 8, 1, 9 }; + std::vector output1(5); + std::vector output2(5); + + auto result1 = std::partial_sort_copy(input.begin(), input.end(), output1.begin(), output1.end()); + auto result2 = etl::partial_sort_copy(input.begin(), input.end(), output2.begin(), output2.end()); + + CHECK(result1 == output1.end()); + CHECK(result2 == output2.end()); + + bool isEqual = std::equal(output1.begin(), output1.end(), output2.begin()); + CHECK(isEqual); + + CHECK(std::is_sorted(output2.begin(), output2.end())); + } + + //************************************************************************* + TEST(partial_sort_copy_single_element_input) + { + std::vector input = { 42 }; + std::vector output(3, 0); + + auto result = etl::partial_sort_copy(input.begin(), input.end(), output.begin(), output.end()); + + CHECK(result == output.begin() + 1); + CHECK_EQUAL(42, output[0]); + } + + //************************************************************************* + TEST(partial_sort_copy_single_element_output) + { + std::vector input = { 5, 3, 8, 1, 9 }; + std::vector output1(1); + std::vector output2(1); + + std::partial_sort_copy(input.begin(), input.end(), output1.begin(), output1.end()); + etl::partial_sort_copy(input.begin(), input.end(), output2.begin(), output2.end()); + + CHECK_EQUAL(output1[0], output2[0]); + CHECK_EQUAL(1, output2[0]); + } + + //************************************************************************* + TEST(partial_sort_copy_duplicates) + { + std::vector input = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5 }; + std::vector output1(6); + std::vector output2(6); + + std::partial_sort_copy(input.begin(), input.end(), output1.begin(), output1.end()); + etl::partial_sort_copy(input.begin(), input.end(), output2.begin(), output2.end()); + + bool isEqual = std::equal(output1.begin(), output1.end(), output2.begin()); + CHECK(isEqual); + + CHECK(std::is_sorted(output2.begin(), output2.end())); + } + + //************************************************************************* + TEST(partial_sort_copy_already_sorted) + { + std::vector input = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + std::vector output1(5); + std::vector output2(5); + + std::partial_sort_copy(input.begin(), input.end(), output1.begin(), output1.end()); + etl::partial_sort_copy(input.begin(), input.end(), output2.begin(), output2.end()); + + bool isEqual = std::equal(output1.begin(), output1.end(), output2.begin()); + CHECK(isEqual); + + CHECK(std::is_sorted(output2.begin(), output2.end())); + } + + //************************************************************************* + TEST(partial_sort_copy_reverse_sorted) + { + std::vector input = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }; + std::vector output1(5); + std::vector output2(5); + + std::partial_sort_copy(input.begin(), input.end(), output1.begin(), output1.end()); + etl::partial_sort_copy(input.begin(), input.end(), output2.begin(), output2.end()); + + bool isEqual = std::equal(output1.begin(), output1.end(), output2.begin()); + CHECK(isEqual); + + CHECK(std::is_sorted(output2.begin(), output2.end())); + } + + //************************************************************************* + TEST(partial_sort_copy_pointer) + { + int input[] = { 5, 3, 8, 1, 9, 2, 7, 4, 6, 10 }; + int output1[5] = {}; + int output2[5] = {}; + + std::partial_sort_copy(std::begin(input), std::end(input), std::begin(output1), std::end(output1)); + etl::partial_sort_copy(std::begin(input), std::end(input), std::begin(output2), std::end(output2)); + + bool isEqual = std::equal(std::begin(output1), std::end(output1), std::begin(output2)); + CHECK(isEqual); + } + + //************************************************************************* + TEST(partial_sort_copy_all_equal) + { + std::vector input = { 5, 5, 5, 5, 5, 5 }; + std::vector output(3); + + etl::partial_sort_copy(input.begin(), input.end(), output.begin(), output.end()); + + CHECK(std::is_sorted(output.begin(), output.end())); + + for (size_t i = 0; i < output.size(); ++i) + { + CHECK_EQUAL(5, output[i]); + } + } + + //************************************************************************* + TEST(partial_sort_copy_input_not_modified) + { + std::vector input = { 5, 3, 8, 1, 9, 2, 7, 4, 6, 10 }; + std::vector original(input); + std::vector output(5); + + etl::partial_sort_copy(input.begin(), input.end(), output.begin(), output.end()); + + // Input should not be modified + bool isEqual = std::equal(input.begin(), input.end(), original.begin()); + CHECK(isEqual); + } + + //************************************************************************* + TEST(partial_sort_copy_from_list) + { + std::list input = { 5, 3, 8, 1, 9, 2, 7, 4, 6, 10 }; + std::vector output1(5); + std::vector output2(5); + + std::partial_sort_copy(input.begin(), input.end(), output1.begin(), output1.end()); + etl::partial_sort_copy(input.begin(), input.end(), output2.begin(), output2.end()); + + bool isEqual = std::equal(output1.begin(), output1.end(), output2.begin()); + CHECK(isEqual); + + CHECK(std::is_sorted(output2.begin(), output2.end())); + } + //************************************************************************* TEST(find) { @@ -1199,6 +2358,216 @@ namespace CHECK_EQUAL(5U, *(data2[4])); } + //************************************************************************* + TEST(move_s_random_iterator_same_size) + { + typedef std::vector> Data; + + Data data1; + data1.push_back(std::unique_ptr(new uint32_t(1U))); + data1.push_back(std::unique_ptr(new uint32_t(2U))); + data1.push_back(std::unique_ptr(new uint32_t(3U))); + data1.push_back(std::unique_ptr(new uint32_t(4U))); + data1.push_back(std::unique_ptr(new uint32_t(5U))); + + Data data2(5); + + Data::iterator result = etl::move_s(data1.begin(), data1.end(), data2.begin(), data2.end()); + + CHECK(data2.end() == result); + + 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_s_random_iterator_destination_smaller) + { + typedef std::vector> Data; + + Data data1; + data1.push_back(std::unique_ptr(new uint32_t(1U))); + data1.push_back(std::unique_ptr(new uint32_t(2U))); + data1.push_back(std::unique_ptr(new uint32_t(3U))); + data1.push_back(std::unique_ptr(new uint32_t(4U))); + data1.push_back(std::unique_ptr(new uint32_t(5U))); + + Data data2(3); + + Data::iterator result = etl::move_s(data1.begin(), data1.end(), data2.begin(), data2.end()); + + CHECK(data2.end() == result); + + CHECK_EQUAL(1U, *(data2[0])); + CHECK_EQUAL(2U, *(data2[1])); + CHECK_EQUAL(3U, *(data2[2])); + } + + //************************************************************************* + TEST(move_s_random_iterator_source_smaller) + { + typedef std::vector> Data; + + Data data1; + data1.push_back(std::unique_ptr(new uint32_t(1U))); + data1.push_back(std::unique_ptr(new uint32_t(2U))); + data1.push_back(std::unique_ptr(new uint32_t(3U))); + + Data data2(5); + + Data::iterator result = etl::move_s(data1.begin(), data1.end(), data2.begin(), data2.end()); + + CHECK(data2.begin() + 3 == result); + + CHECK_EQUAL(1U, *(data2[0])); + CHECK_EQUAL(2U, *(data2[1])); + CHECK_EQUAL(3U, *(data2[2])); + } + + //************************************************************************* + TEST(move_s_non_random_iterator_same_size) + { + typedef std::list> Data; + + Data data1; + data1.push_back(std::unique_ptr(new uint32_t(1U))); + data1.push_back(std::unique_ptr(new uint32_t(2U))); + data1.push_back(std::unique_ptr(new uint32_t(3U))); + data1.push_back(std::unique_ptr(new uint32_t(4U))); + data1.push_back(std::unique_ptr(new uint32_t(5U))); + + Data data2(5); + + Data::iterator result = etl::move_s(data1.begin(), data1.end(), data2.begin(), data2.end()); + + CHECK(data2.end() == result); + + Data::iterator itr = data2.begin(); + CHECK_EQUAL(1U, **(itr++)); + CHECK_EQUAL(2U, **(itr++)); + CHECK_EQUAL(3U, **(itr++)); + CHECK_EQUAL(4U, **(itr++)); + CHECK_EQUAL(5U, **(itr++)); + } + + //************************************************************************* + TEST(move_s_non_random_iterator_destination_smaller) + { + typedef std::list> Data; + + Data data1; + data1.push_back(std::unique_ptr(new uint32_t(1U))); + data1.push_back(std::unique_ptr(new uint32_t(2U))); + data1.push_back(std::unique_ptr(new uint32_t(3U))); + data1.push_back(std::unique_ptr(new uint32_t(4U))); + data1.push_back(std::unique_ptr(new uint32_t(5U))); + + Data data2(3); + + Data::iterator result = etl::move_s(data1.begin(), data1.end(), data2.begin(), data2.end()); + + CHECK(data2.end() == result); + + Data::iterator itr = data2.begin(); + CHECK_EQUAL(1U, **(itr++)); + CHECK_EQUAL(2U, **(itr++)); + CHECK_EQUAL(3U, **(itr++)); + } + + //************************************************************************* + TEST(move_s_non_random_iterator_source_smaller) + { + typedef std::list> Data; + + Data data1; + data1.push_back(std::unique_ptr(new uint32_t(1U))); + data1.push_back(std::unique_ptr(new uint32_t(2U))); + data1.push_back(std::unique_ptr(new uint32_t(3U))); + + Data data2(5); + + Data::iterator result = etl::move_s(data1.begin(), data1.end(), data2.begin(), data2.end()); + + Data::iterator expected_pos = data2.begin(); + std::advance(expected_pos, 3); + CHECK(expected_pos == result); + + Data::iterator itr = data2.begin(); + CHECK_EQUAL(1U, **(itr++)); + CHECK_EQUAL(2U, **(itr++)); + CHECK_EQUAL(3U, **(itr++)); + } + + //************************************************************************* + TEST(move_s_empty_source) + { + typedef std::vector> Data; + + Data data1; + Data data2(3); + + Data::iterator result = etl::move_s(data1.begin(), data1.end(), data2.begin(), data2.end()); + + CHECK(data2.begin() == result); + } + + //************************************************************************* + TEST(move_s_empty_destination) + { + typedef std::vector> Data; + + Data data1; + data1.push_back(std::unique_ptr(new uint32_t(1U))); + data1.push_back(std::unique_ptr(new uint32_t(2U))); + data1.push_back(std::unique_ptr(new uint32_t(3U))); + + Data data2; + + Data::iterator result = etl::move_s(data1.begin(), data1.end(), data2.begin(), data2.end()); + + CHECK(data2.begin() == result); + } + + //************************************************************************* + TEST(move_s_pod_random_iterator) + { + int data1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + int data2[] = { 1, 2, 3, 4, 5 }; + + int out1[10]; + int out2[5]; + + int check1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + int check2[] = { 1, 2, 3, 4, 5 }; + int check3[] = { 1, 2, 3, 4, 5, 0, 0, 0, 0, 0 }; + + int* result; + + // Same size. + std::fill(std::begin(out1), std::end(out1), 0); + result = etl::move_s(std::begin(data1), std::end(data1), std::begin(out1), std::end(out1)); + CHECK_EQUAL(std::end(out1), result); + bool is_same = std::equal(std::begin(out1), std::end(out1), std::begin(check1)); + CHECK(is_same); + + // Destination smaller. + std::fill(std::begin(out2), std::end(out2), 0); + result = etl::move_s(std::begin(data1), std::end(data1), std::begin(out2), std::end(out2)); + CHECK_EQUAL(std::end(out2), result); + is_same = std::equal(std::begin(out2), std::end(out2), std::begin(check2)); + CHECK(is_same); + + // Source smaller. + std::fill(std::begin(out1), std::end(out1), 0); + result = etl::move_s(std::begin(data2), std::end(data2), std::begin(out1), std::end(out1)); + CHECK_EQUAL(std::begin(out1) + 5, result); + is_same = std::equal(std::begin(out1), std::end(out1), std::begin(check3)); + CHECK(is_same); + } + //************************************************************************* TEST(rotate_pod) { @@ -1405,6 +2774,29 @@ namespace CHECK(!is_permutation); } + //************************************************************************* + TEST(is_permutation_different_lengths) + { + int shorter[] = { 1, 2 }; + int longer[] = { 1, 2, 3 }; + + // Four-iterator: range2 longer than range1 (extra elements only in range2) + bool result = etl::is_permutation(std::begin(shorter), std::end(shorter), std::begin(longer), std::end(longer)); + CHECK(!result); + + // Four-iterator: range1 longer than range2 + result = etl::is_permutation(std::begin(longer), std::end(longer), std::begin(shorter), std::end(shorter)); + CHECK(!result); + + // Four-iterator with predicate: range2 longer than range1 + result = etl::is_permutation(std::begin(shorter), std::end(shorter), std::begin(longer), std::end(longer), etl::equal_to()); + CHECK(!result); + + // Four-iterator with predicate: range1 longer than range2 + result = etl::is_permutation(std::begin(longer), std::end(longer), std::begin(shorter), std::end(shorter), etl::equal_to()); + CHECK(!result); + } + //************************************************************************* TEST(is_partitioned) { @@ -2227,6 +3619,30 @@ namespace } } + //************************************************************************* + TEST(selection_sort_empty_range) + { + // Forward iterators + std::forward_list fwd_data; + etl::selection_sort(fwd_data.begin(), fwd_data.end()); + CHECK(fwd_data.empty()); + + // Bidirectional iterators + std::list bidir_data; + etl::selection_sort(bidir_data.begin(), bidir_data.end()); + CHECK(bidir_data.empty()); + + // Random access iterators + std::vector ra_data; + etl::selection_sort(ra_data.begin(), ra_data.end()); + CHECK(ra_data.empty()); + + // With comparator + std::forward_list fwd_data2; + etl::selection_sort(fwd_data2.begin(), fwd_data2.end(), std::greater()); + CHECK(fwd_data2.empty()); + } + //************************************************************************* TEST(heap_sort_default) { @@ -2371,6 +3787,275 @@ namespace CHECK(is_same); } + //************************************************************************* + TEST(unique) + { + std::array data = { 1, 1, 2, 3, 3, 3, 4, 4, 5, 5 }; + std::array expected = { 1, 2, 3, 4, 5 }; + + auto end = etl::unique(data.begin(), data.end()); + + CHECK_EQUAL(5, std::distance(data.begin(), end)); + bool is_same = std::equal(expected.begin(), expected.end(), data.begin()); + CHECK(is_same); + } + + //************************************************************************* + TEST(unique_empty_range) + { + std::array data = {}; + + auto end = etl::unique(data.begin(), data.end()); + + CHECK(end == data.end()); + } + + //************************************************************************* + TEST(unique_single_element) + { + std::array data = { 42 }; + std::array expected = { 42 }; + + auto end = etl::unique(data.begin(), data.end()); + + CHECK_EQUAL(1, std::distance(data.begin(), end)); + bool is_same = std::equal(expected.begin(), expected.end(), data.begin()); + CHECK(is_same); + } + + //************************************************************************* + TEST(unique_no_duplicates) + { + std::array data = { 1, 2, 3, 4, 5 }; + std::array expected = { 1, 2, 3, 4, 5 }; + + auto end = etl::unique(data.begin(), data.end()); + + CHECK_EQUAL(5, std::distance(data.begin(), end)); + bool is_same = std::equal(expected.begin(), expected.end(), data.begin()); + CHECK(is_same); + } + + //************************************************************************* + TEST(unique_all_same) + { + std::array data = { 7, 7, 7, 7, 7 }; + std::array expected = { 7 }; + + auto end = etl::unique(data.begin(), data.end()); + + CHECK_EQUAL(1, std::distance(data.begin(), end)); + bool is_same = std::equal(expected.begin(), expected.end(), data.begin()); + CHECK(is_same); + } + + //************************************************************************* + TEST(unique_with_predicate) + { + std::array data = { 1, 1, 2, 3, 3, 3, 4, 4, 5, 5 }; + std::array expected = { 1, 2, 3, 4, 5 }; + + auto end = etl::unique(data.begin(), data.end(), std::equal_to()); + + CHECK_EQUAL(5, std::distance(data.begin(), end)); + bool is_same = std::equal(expected.begin(), expected.end(), data.begin()); + CHECK(is_same); + } + + //************************************************************************* + TEST(unique_with_predicate_custom) + { + // Group elements that are close to each other (differ by less than 3) + std::array data = { 1, 2, 3, 7, 8, 9, 20, 21 }; + std::array expected = { 1, 7, 20 }; + + auto end = etl::unique(data.begin(), data.end(), [](int a, int b) { return (b - a) < 3; }); + + CHECK_EQUAL(3, std::distance(data.begin(), end)); + bool is_same = std::equal(expected.begin(), expected.end(), data.begin()); + CHECK(is_same); + } + + //************************************************************************* + TEST(unique_matches_std) + { + std::array data1 = { 1, 1, 2, 2, 2, 3, 4, 4, 5, 5, 5, 5 }; + std::array data2 = data1; + + auto std_end = std::unique(data1.begin(), data1.end()); + auto etl_end = etl::unique(data2.begin(), data2.end()); + + size_t std_size = std::distance(data1.begin(), std_end); + size_t etl_size = std::distance(data2.begin(), etl_end); + + CHECK_EQUAL(std_size, etl_size); + bool is_same = std::equal(data1.begin(), std_end, data2.begin()); + CHECK(is_same); + } + + //************************************************************************* + TEST(unique_with_predicate_matches_std) + { + std::array data1 = { 1, 1, 2, 2, 2, 3, 4, 4, 5, 5, 5, 5 }; + std::array data2 = data1; + + auto std_end = std::unique(data1.begin(), data1.end(), std::equal_to()); + auto etl_end = etl::unique(data2.begin(), data2.end(), std::equal_to()); + + size_t std_size = std::distance(data1.begin(), std_end); + size_t etl_size = std::distance(data2.begin(), etl_end); + + CHECK_EQUAL(std_size, etl_size); + bool is_same = std::equal(data1.begin(), std_end, data2.begin()); + CHECK(is_same); + } + + //************************************************************************* + TEST(unique_copy) + { + std::array data = { 1, 1, 2, 3, 3, 3, 4, 4, 5, 5 }; + std::array expected = { 1, 2, 3, 4, 5 }; + std::array result = {}; + + auto end = etl::unique_copy(data.begin(), data.end(), result.begin()); + + CHECK_EQUAL(5, std::distance(result.begin(), end)); + bool is_same = std::equal(expected.begin(), expected.end(), result.begin()); + CHECK(is_same); + } + + //************************************************************************* + TEST(unique_copy_empty_range) + { + std::array data = {}; + std::array result = { 99 }; + + auto end = etl::unique_copy(data.begin(), data.end(), result.begin()); + + CHECK(end == result.begin()); + CHECK_EQUAL(99, result[0]); // output unchanged + } + + //************************************************************************* + TEST(unique_copy_single_element) + { + std::array data = { 42 }; + std::array expected = { 42 }; + std::array result = {}; + + auto end = etl::unique_copy(data.begin(), data.end(), result.begin()); + + CHECK_EQUAL(1, std::distance(result.begin(), end)); + bool is_same = std::equal(expected.begin(), expected.end(), result.begin()); + CHECK(is_same); + } + + //************************************************************************* + TEST(unique_copy_no_duplicates) + { + std::array data = { 1, 2, 3, 4, 5 }; + std::array expected = { 1, 2, 3, 4, 5 }; + std::array result = {}; + + auto end = etl::unique_copy(data.begin(), data.end(), result.begin()); + + CHECK_EQUAL(5, std::distance(result.begin(), end)); + bool is_same = std::equal(expected.begin(), expected.end(), result.begin()); + CHECK(is_same); + } + + //************************************************************************* + TEST(unique_copy_all_same) + { + std::array data = { 7, 7, 7, 7, 7 }; + std::array expected = { 7 }; + std::array result = {}; + + auto end = etl::unique_copy(data.begin(), data.end(), result.begin()); + + CHECK_EQUAL(1, std::distance(result.begin(), end)); + bool is_same = std::equal(expected.begin(), expected.end(), result.begin()); + CHECK(is_same); + } + + //************************************************************************* + TEST(unique_copy_source_unchanged) + { + std::array data = { 1, 1, 2, 3, 3, 3, 4, 4, 5, 5 }; + std::array original = data; + std::array result = {}; + + etl::unique_copy(data.begin(), data.end(), result.begin()); + + bool is_same = std::equal(original.begin(), original.end(), data.begin()); + CHECK(is_same); + } + + //************************************************************************* + TEST(unique_copy_with_predicate) + { + std::array data = { 1, 1, 2, 3, 3, 3, 4, 4, 5, 5 }; + std::array expected = { 1, 2, 3, 4, 5 }; + std::array result = {}; + + auto end = etl::unique_copy(data.begin(), data.end(), result.begin(), std::equal_to()); + + CHECK_EQUAL(5, std::distance(result.begin(), end)); + bool is_same = std::equal(expected.begin(), expected.end(), result.begin()); + CHECK(is_same); + } + + //************************************************************************* + TEST(unique_copy_with_predicate_custom) + { + // Group elements that are close to each other (differ by less than 3) + std::array data = { 1, 2, 3, 7, 8, 9, 20, 21 }; + std::array expected = { 1, 7, 20 }; + std::array result = {}; + + auto end = etl::unique_copy(data.begin(), data.end(), result.begin(), [](int a, int b) { return (b - a) < 3; }); + + CHECK_EQUAL(3, std::distance(result.begin(), end)); + bool is_same = std::equal(expected.begin(), expected.end(), result.begin()); + CHECK(is_same); + } + + //************************************************************************* + TEST(unique_copy_matches_std) + { + std::array data = { 1, 1, 2, 2, 2, 3, 4, 4, 5, 5, 5, 5 }; + std::array std_result = {}; + std::array etl_result = {}; + + auto std_end = std::unique_copy(data.begin(), data.end(), std_result.begin()); + auto etl_end = etl::unique_copy(data.begin(), data.end(), etl_result.begin()); + + size_t std_size = std::distance(std_result.begin(), std_end); + size_t etl_size = std::distance(etl_result.begin(), etl_end); + + CHECK_EQUAL(std_size, etl_size); + bool is_same = std::equal(std_result.begin(), std_end, etl_result.begin()); + CHECK(is_same); + } + + //************************************************************************* + TEST(unique_copy_with_predicate_matches_std) + { + std::array data = { 1, 1, 2, 2, 2, 3, 4, 4, 5, 5, 5, 5 }; + std::array std_result = {}; + std::array etl_result = {}; + + auto std_end = std::unique_copy(data.begin(), data.end(), std_result.begin(), std::equal_to()); + auto etl_end = etl::unique_copy(data.begin(), data.end(), etl_result.begin(), std::equal_to()); + + size_t std_size = std::distance(std_result.begin(), std_end); + size_t etl_size = std::distance(etl_result.begin(), etl_end); + + CHECK_EQUAL(std_size, etl_size); + bool is_same = std::equal(std_result.begin(), std_end, etl_result.begin()); + CHECK(is_same); + } + //************************************************************************* struct generator { @@ -2556,6 +4241,116 @@ namespace } } + //************************************************************************* + TEST(accumulate_default) + { + int data[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + int expected = std::accumulate(std::begin(data), std::end(data), 0); + int result = etl::accumulate(std::begin(data), std::end(data), 0); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(accumulate_with_initial_value) + { + int data[] = { 1, 2, 3, 4, 5 }; + + int expected = std::accumulate(std::begin(data), std::end(data), 100); + int result = etl::accumulate(std::begin(data), std::end(data), 100); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(accumulate_custom_operation) + { + int data[] = { 1, 2, 3, 4, 5 }; + + int expected = std::accumulate(std::begin(data), std::end(data), 1, std::multiplies()); + int result = etl::accumulate(std::begin(data), std::end(data), 1, std::multiplies()); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(accumulate_empty_range) + { + int data[] = { 1 }; + + int expected = std::accumulate(std::begin(data), std::begin(data), 42); + int result = etl::accumulate(std::begin(data), std::begin(data), 42); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(accumulate_single_element) + { + int data[] = { 7 }; + + int expected = std::accumulate(std::begin(data), std::end(data), 0); + int result = etl::accumulate(std::begin(data), std::end(data), 0); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(accumulate_negative_values) + { + int data[] = { -3, -2, -1, 0, 1, 2, 3 }; + + int expected = std::accumulate(std::begin(data), std::end(data), 0); + int result = etl::accumulate(std::begin(data), std::end(data), 0); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(accumulate_custom_operation_subtraction) + { + int data[] = { 1, 2, 3, 4, 5 }; + + int expected = std::accumulate(std::begin(data), std::end(data), 100, std::minus()); + int result = etl::accumulate(std::begin(data), std::end(data), 100, std::minus()); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(accumulate_non_random_iterator) + { + List data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + int expected = std::accumulate(data.begin(), data.end(), 0); + int result = etl::accumulate(data.begin(), data.end(), 0); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(accumulate_non_random_iterator_custom_operation) + { + List data = { 1, 2, 3, 4, 5 }; + + int expected = std::accumulate(data.begin(), data.end(), 1, std::multiplies()); + int result = etl::accumulate(data.begin(), data.end(), 1, std::multiplies()); + + CHECK_EQUAL(expected, result); + } + + //************************************************************************* + TEST(accumulate_double) + { + double data[] = { 1.5, 2.5, 3.5, 4.5, 5.5 }; + + double expected = std::accumulate(std::begin(data), std::end(data), 0.0); + double result = etl::accumulate(std::begin(data), std::end(data), 0.0); + + CHECK_CLOSE(expected, result, 1e-10); + } + //************************************************************************* TEST(clamp_run_time) { @@ -2591,5 +4386,432 @@ namespace CHECK_EQUAL(0, result5); CHECK_EQUAL(10, result6); } + + //************************************************************************* + TEST(merge_default_comparator) + { + int input1[] = { 1, 3, 5, 7, 9 }; + int input2[] = { 2, 4, 6, 8, 10 }; + int output[10]; + int expected[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + int* result = etl::merge(std::begin(input1), std::end(input1), + std::begin(input2), std::end(input2), + std::begin(output)); + + CHECK_EQUAL(std::end(output), result); + CHECK_ARRAY_EQUAL(expected, output, 10); + } + + //************************************************************************* + TEST(merge_custom_comparator) + { + int input1[] = { 9, 7, 5, 3, 1 }; + int input2[] = { 10, 8, 6, 4, 2 }; + int output[10]; + int expected[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }; + + int* result = etl::merge(std::begin(input1), std::end(input1), + std::begin(input2), std::end(input2), + std::begin(output), + Greater()); + + CHECK_EQUAL(std::end(output), result); + CHECK_ARRAY_EQUAL(expected, output, 10); + } + + //************************************************************************* + TEST(merge_first_range_empty) + { + int input1[] = { 0 }; // dummy, won't be used + int input2[] = { 1, 2, 3 }; + int output[3]; + int expected[] = { 1, 2, 3 }; + + int* result = etl::merge(input1, input1, // empty range + std::begin(input2), std::end(input2), + std::begin(output)); + + CHECK_EQUAL(std::end(output), result); + CHECK_ARRAY_EQUAL(expected, output, 3); + } + + //************************************************************************* + TEST(merge_second_range_empty) + { + int input1[] = { 1, 2, 3 }; + int input2[] = { 0 }; // dummy, won't be used + int output[3]; + int expected[] = { 1, 2, 3 }; + + int* result = etl::merge(std::begin(input1), std::end(input1), + input2, input2, // empty range + std::begin(output)); + + CHECK_EQUAL(std::end(output), result); + CHECK_ARRAY_EQUAL(expected, output, 3); + } + + //************************************************************************* + TEST(merge_both_ranges_empty) + { + int input1[] = { 0 }; + int output[] = { 99 }; + + int* result = etl::merge(input1, input1, + input1, input1, + std::begin(output)); + + CHECK_EQUAL(std::begin(output), result); + CHECK_EQUAL(99, output[0]); // output should be unchanged + } + + //************************************************************************* + TEST(merge_with_duplicates) + { + int input1[] = { 1, 3, 3, 5 }; + int input2[] = { 2, 3, 4, 5 }; + int output[8]; + int expected[] = { 1, 2, 3, 3, 3, 4, 5, 5 }; + + int* result = etl::merge(std::begin(input1), std::end(input1), + std::begin(input2), std::end(input2), + std::begin(output)); + + CHECK_EQUAL(std::end(output), result); + CHECK_ARRAY_EQUAL(expected, output, 8); + } + + //************************************************************************* + TEST(merge_different_sizes) + { + int input1[] = { 1, 5 }; + int input2[] = { 2, 3, 4, 6, 7, 8 }; + int output[8]; + int expected[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + + int* result = etl::merge(std::begin(input1), std::end(input1), + std::begin(input2), std::end(input2), + std::begin(output)); + + CHECK_EQUAL(std::end(output), result); + CHECK_ARRAY_EQUAL(expected, output, 8); + } + + //************************************************************************* + TEST(merge_single_elements) + { + int input1[] = { 1 }; + int input2[] = { 2 }; + int output[2]; + int expected[] = { 1, 2 }; + + int* result = etl::merge(std::begin(input1), std::end(input1), + std::begin(input2), std::end(input2), + std::begin(output)); + + CHECK_EQUAL(std::end(output), result); + CHECK_ARRAY_EQUAL(expected, output, 2); + } + + //************************************************************************* + TEST(merge_with_list_iterators) + { + std::list input1 = { 1, 3, 5, 7 }; + std::list input2 = { 2, 4, 6, 8 }; + std::vector output(8); + std::vector expected = { 1, 2, 3, 4, 5, 6, 7, 8 }; + + std::vector::iterator result = etl::merge(input1.begin(), input1.end(), + input2.begin(), input2.end(), + output.begin()); + + CHECK(output.end() == result); + CHECK_ARRAY_EQUAL(expected.data(), output.data(), 8); + } + + //************************************************************************* + TEST(merge_matches_std) + { + int input1[] = { 1, 4, 7, 8, 10 }; + int input2[] = { 2, 3, 5, 6, 9 }; + int etl_output[10]; + int std_output[10]; + + etl::merge(std::begin(input1), std::end(input1), + std::begin(input2), std::end(input2), + std::begin(etl_output)); + + std::merge(std::begin(input1), std::end(input1), + std::begin(input2), std::end(input2), + std::begin(std_output)); + + CHECK_ARRAY_EQUAL(std_output, etl_output, 10); + } + + //************************************************************************* + TEST(merge_matches_std_with_comparator) + { + int input1[] = { 10, 8, 7, 4, 1 }; + int input2[] = { 9, 6, 5, 3, 2 }; + int etl_output[10]; + int std_output[10]; + + etl::merge(std::begin(input1), std::end(input1), + std::begin(input2), std::end(input2), + std::begin(etl_output), + Greater()); + + std::merge(std::begin(input1), std::end(input1), + std::begin(input2), std::end(input2), + std::begin(std_output), + Greater()); + + CHECK_ARRAY_EQUAL(std_output, etl_output, 10); + } + + //************************************************************************* + TEST(merge_stability) + { + // Test that merge is stable: equivalent elements from the first range + // come before those from the second range. + Data input1[] = { Data(1, 1), Data(3, 1), Data(5, 1) }; + Data input2[] = { Data(1, 2), Data(3, 2), Data(5, 2) }; + Data output[6]; + + etl::merge(std::begin(input1), std::end(input1), + std::begin(input2), std::end(input2), + std::begin(output), + DataPredicate()); + + // Elements from input1 (b==1) should come before elements from input2 (b==2) + // for equivalent keys. + CHECK_EQUAL(1, output[0].a); CHECK_EQUAL(1, output[0].b); // from input1 + CHECK_EQUAL(1, output[1].a); CHECK_EQUAL(2, output[1].b); // from input2 + CHECK_EQUAL(3, output[2].a); CHECK_EQUAL(1, output[2].b); // from input1 + CHECK_EQUAL(3, output[3].a); CHECK_EQUAL(2, output[3].b); // from input2 + CHECK_EQUAL(5, output[4].a); CHECK_EQUAL(1, output[4].b); // from input1 + CHECK_EQUAL(5, output[5].a); CHECK_EQUAL(2, output[5].b); // from input2 + } + + //************************************************************************* + TEST(inplace_merge_default_comparator) + { + int data[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 10 }; + int expected[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + etl::inplace_merge(std::begin(data), std::begin(data) + 5, std::end(data)); + + CHECK_ARRAY_EQUAL(expected, data, 10); + } + + //************************************************************************* + TEST(inplace_merge_custom_comparator) + { + int data[] = { 9, 7, 5, 3, 1, 10, 8, 6, 4, 2 }; + int expected[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }; + + etl::inplace_merge(std::begin(data), std::begin(data) + 5, std::end(data), Greater()); + + CHECK_ARRAY_EQUAL(expected, data, 10); + } + + //************************************************************************* + TEST(inplace_merge_first_range_empty) + { + int data[] = { 1, 2, 3, 4, 5 }; + int expected[] = { 1, 2, 3, 4, 5 }; + + etl::inplace_merge(std::begin(data), std::begin(data), std::end(data)); + + CHECK_ARRAY_EQUAL(expected, data, 5); + } + + //************************************************************************* + TEST(inplace_merge_second_range_empty) + { + int data[] = { 1, 2, 3, 4, 5 }; + int expected[] = { 1, 2, 3, 4, 5 }; + + etl::inplace_merge(std::begin(data), std::end(data), std::end(data)); + + CHECK_ARRAY_EQUAL(expected, data, 5); + } + + //************************************************************************* + TEST(inplace_merge_both_ranges_empty) + { + int data[] = { 99 }; + + etl::inplace_merge(data, data, data); // empty range + + CHECK_EQUAL(99, data[0]); // unchanged + } + + //************************************************************************* + TEST(inplace_merge_with_duplicates) + { + int data[] = { 1, 3, 3, 5, 2, 3, 4, 5 }; + int expected[] = { 1, 2, 3, 3, 3, 4, 5, 5 }; + + etl::inplace_merge(std::begin(data), std::begin(data) + 4, std::end(data)); + + CHECK_ARRAY_EQUAL(expected, data, 8); + } + + //************************************************************************* + TEST(inplace_merge_different_sizes) + { + int data[] = { 1, 5, 2, 3, 4, 6, 7, 8 }; + int expected[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + + etl::inplace_merge(std::begin(data), std::begin(data) + 2, std::end(data)); + + CHECK_ARRAY_EQUAL(expected, data, 8); + } + + //************************************************************************* + TEST(inplace_merge_single_elements) + { + int data[] = { 2, 1 }; + int expected[] = { 1, 2 }; + + etl::inplace_merge(std::begin(data), std::begin(data) + 1, std::end(data)); + + CHECK_ARRAY_EQUAL(expected, data, 2); + } + + //************************************************************************* + TEST(inplace_merge_single_element_halves_already_sorted) + { + int data[] = { 1, 2 }; + int expected[] = { 1, 2 }; + + etl::inplace_merge(std::begin(data), std::begin(data) + 1, std::end(data)); + + CHECK_ARRAY_EQUAL(expected, data, 2); + } + + //************************************************************************* + TEST(inplace_merge_already_sorted) + { + int data[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + int expected[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + etl::inplace_merge(std::begin(data), std::begin(data) + 5, std::end(data)); + + CHECK_ARRAY_EQUAL(expected, data, 10); + } + + //************************************************************************* + TEST(inplace_merge_reverse_halves) + { + // Second half all less than first half + int data[] = { 6, 7, 8, 9, 10, 1, 2, 3, 4, 5 }; + int expected[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + etl::inplace_merge(std::begin(data), std::begin(data) + 5, std::end(data)); + + CHECK_ARRAY_EQUAL(expected, data, 10); + } + + //************************************************************************* + TEST(inplace_merge_with_list_iterators) + { + std::vector data = { 1, 3, 5, 7, 2, 4, 6, 8 }; + std::vector expected = { 1, 2, 3, 4, 5, 6, 7, 8 }; + + etl::inplace_merge(data.begin(), data.begin() + 4, data.end()); + + CHECK(expected == data); + } + + //************************************************************************* + TEST(inplace_merge_matches_std) + { + int etl_data[] = { 1, 4, 7, 8, 10, 2, 3, 5, 6, 9 }; + int std_data[] = { 1, 4, 7, 8, 10, 2, 3, 5, 6, 9 }; + + etl::inplace_merge(std::begin(etl_data), std::begin(etl_data) + 5, std::end(etl_data)); + std::inplace_merge(std::begin(std_data), std::begin(std_data) + 5, std::end(std_data)); + + CHECK_ARRAY_EQUAL(std_data, etl_data, 10); + } + + //************************************************************************* + TEST(inplace_merge_matches_std_with_comparator) + { + int etl_data[] = { 10, 8, 7, 4, 1, 9, 6, 5, 3, 2 }; + int std_data[] = { 10, 8, 7, 4, 1, 9, 6, 5, 3, 2 }; + + etl::inplace_merge(std::begin(etl_data), std::begin(etl_data) + 5, std::end(etl_data), Greater()); + std::inplace_merge(std::begin(std_data), std::begin(std_data) + 5, std::end(std_data), Greater()); + + CHECK_ARRAY_EQUAL(std_data, etl_data, 10); + } + + //************************************************************************* + TEST(inplace_merge_stability) + { + // Test that inplace_merge is stable: equivalent elements from the first + // range come before those from the second range. + Data data[] = { Data(1, 1), Data(3, 1), Data(5, 1), + Data(1, 2), Data(3, 2), Data(5, 2) }; + + etl::inplace_merge(std::begin(data), std::begin(data) + 3, std::end(data), DataPredicate()); + + // Elements from first half (b==1) should come before elements from second half (b==2) + // for equivalent keys. + CHECK_EQUAL(1, data[0].a); CHECK_EQUAL(1, data[0].b); // from first half + CHECK_EQUAL(1, data[1].a); CHECK_EQUAL(2, data[1].b); // from second half + CHECK_EQUAL(3, data[2].a); CHECK_EQUAL(1, data[2].b); // from first half + CHECK_EQUAL(3, data[3].a); CHECK_EQUAL(2, data[3].b); // from second half + CHECK_EQUAL(5, data[4].a); CHECK_EQUAL(1, data[4].b); // from first half + CHECK_EQUAL(5, data[5].a); CHECK_EQUAL(2, data[5].b); // from second half + } + + //************************************************************************* + TEST(inplace_merge_single_element_first_half) + { + int data[] = { 5, 1, 2, 3, 4 }; + int expected[] = { 1, 2, 3, 4, 5 }; + + etl::inplace_merge(std::begin(data), std::begin(data) + 1, std::end(data)); + + CHECK_ARRAY_EQUAL(expected, data, 5); + } + + //************************************************************************* + TEST(inplace_merge_single_element_second_half) + { + int data[] = { 1, 2, 3, 4, 5, 3 }; + int expected[] = { 1, 2, 3, 3, 4, 5 }; + + etl::inplace_merge(std::begin(data), std::begin(data) + 5, std::end(data)); + + CHECK_ARRAY_EQUAL(expected, data, 6); + } + + //************************************************************************* + TEST(inplace_merge_all_equal) + { + int data[] = { 5, 5, 5, 5, 5, 5 }; + int expected[] = { 5, 5, 5, 5, 5, 5 }; + + etl::inplace_merge(std::begin(data), std::begin(data) + 3, std::end(data)); + + CHECK_ARRAY_EQUAL(expected, data, 6); + } + + //************************************************************************* + TEST(inplace_merge_interleaved) + { + int data[] = { 1, 3, 5, 7, 9, 11, 2, 4, 6, 8, 10, 12 }; + int expected[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; + + etl::inplace_merge(std::begin(data), std::begin(data) + 6, std::end(data)); + + CHECK_ARRAY_EQUAL(expected, data, 12); + } } }