From 14074ade05cce3d2882c4cd5d2e3ffcbb0b0fada Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 28 Jun 2017 19:13:12 +0100 Subject: [PATCH] Additional algorithms. --- src/algorithm.h | 76 ++++++++++++++++++++------ test/test_algorithm.cpp | 118 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 175 insertions(+), 19 deletions(-) diff --git a/src/algorithm.h b/src/algorithm.h index ec4c6420..36318578 100644 --- a/src/algorithm.h +++ b/src/algorithm.h @@ -258,21 +258,40 @@ namespace etl } //*************************************************************************** - /// copy_n + /// copy_n (Random input iterators) ///\ingroup algorithm /// //*************************************************************************** template - TOutputIterator copy_n(TInputIterator i_begin, - TSize n, - TOutputIterator o_begin) + typename etl::enable_if::value, TOutputIterator>::type + copy_n(TInputIterator i_begin, + TSize n, + TOutputIterator o_begin) { - TInputIterator i_end(i_begin); - std::advance(i_end, n); + return std::copy(i_begin, i_begin + n, o_begin); + } - return std::copy(i_begin, i_end, o_begin); + //*************************************************************************** + /// copy_n (Non-random input iterators) + ///\ingroup algorithm + /// + //*************************************************************************** + template + typename etl::enable_if::value, TOutputIterator>::type + copy_n(TInputIterator i_begin, + TSize n, + TOutputIterator o_begin) + { + while (n-- > 0) + { + *o_begin++ = *i_begin++; + } + + return o_begin; } //*************************************************************************** @@ -288,10 +307,34 @@ namespace etl TOutputIterator o_begin, TOutputIterator o_end) { - TInputIterator i_end(i_begin); - std::advance(i_end, n); + while ((n-- > 0) && (o_begin != o_end)) + { + *o_begin++ = *i_begin++; + } - return etl::copy(i_begin, i_end, o_begin, o_end);; + return o_begin; + } + + //*************************************************************************** + /// copy_n + /// A form of copy_n where the smallest of the two ranges is used. + ///\ingroup algorithm + //*************************************************************************** + template + TOutputIterator copy_n(TInputIterator i_begin, + TSize1 n1, + TOutputIterator o_begin, + TSize2 n2) + { + while ((n1-- > 0) && (n2-- > 0)) + { + *o_begin++ = *i_begin++; + } + + return o_begin; } //*************************************************************************** @@ -357,12 +400,12 @@ namespace etl typename TSize, typename TOutputIterator, typename TUnaryPredicate> - TOutputIterator copy_n_if(TInputIterator begin, + TOutputIterator copy_n_if(TInputIterator i_begin, TSize n, - TOutputIterator result, + TOutputIterator o_begin, TUnaryPredicate predicate) { - while (n > 0) + while (n-- > 0) { if (predicate(*i_begin)) { @@ -370,7 +413,6 @@ namespace etl } ++i_begin; - --n; } return o_begin; @@ -697,10 +739,9 @@ namespace etl TSize n, TUnaryFunction function) { - while (n > 0) + while (n-- > 0) { function(*begin++); - --n; } return begin; @@ -719,7 +760,7 @@ namespace etl TUnaryFunction function, TUnaryPredicate predicate) { - while (n > 0) + while (n-- > 0) { if (predicate(*begin)) { @@ -727,7 +768,6 @@ namespace etl } ++begin; - --n; } return begin; diff --git a/test/test_algorithm.cpp b/test/test_algorithm.cpp index 47814012..1bfc59c3 100644 --- a/test/test_algorithm.cpp +++ b/test/test_algorithm.cpp @@ -219,7 +219,7 @@ namespace } //========================================================================= - TEST(copy_n) + TEST(copy_n_random_iterator) { int data1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; int data2[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; @@ -236,6 +236,24 @@ namespace CHECK(is_same); } + //========================================================================= + TEST(copy_n_non_random_iterator) + { + std::list data1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + int data2[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + int data3[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + int* result; + + std::copy_n(std::begin(data1), 4, std::begin(data2)); + result = etl::copy_n(std::begin(data1), 4, std::begin(data3)); + + CHECK_EQUAL(std::begin(data3) + 4, result); + + bool is_same = std::equal(std::begin(data2), std::end(data2), std::begin(data3)); + CHECK(is_same); + } + //========================================================================= TEST(copy_n_4_parameter) { @@ -272,6 +290,42 @@ namespace CHECK(is_same); } + //========================================================================= + TEST(copy_2n_4_parameter) + { + int data1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + 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::copy_n(std::begin(data1), 10, std::begin(out1), 10); + 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::copy_n(std::begin(data1), 10, std::begin(out2), 5); + 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::copy_n(std::begin(data1), 5, std::begin(out1), 10); + CHECK_EQUAL(std::begin(out1) + 5, result); + is_same = std::equal(std::begin(out1), std::end(out1), std::begin(check3)); + CHECK(is_same); + } + //========================================================================= TEST(copy_if) { @@ -287,6 +341,28 @@ namespace CHECK(is_same); } + //========================================================================= + TEST(copy_n_if) + { + int data1[] = { 1, 8, 2, 7, 3, 6, 4, 5, 10, 9 }; + int data2[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + int data3[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + // Copy everything less than 5. + int *pout = data2; + for (int* pin = std::begin(data1); pin != std::begin(data1) + 6; ++pin) + { + if (*pin < 5) + { + *pout++ = *pin; + } + } + etl::copy_n_if(std::begin(data1), 6, std::begin(data3), std::bind2nd(std::less(), 5)); + + bool is_same = std::equal(std::begin(data2), std::end(data2), std::begin(data3)); + CHECK(is_same); + } + //========================================================================= TEST(copy_if_4_parameter) { @@ -499,6 +575,46 @@ namespace CHECK_EQUAL(10, accumulator.sum); } + //========================================================================= + TEST(for_each_n) + { + int data1[] = { 1, 8, 2, 7, 3, 6, 4, 5, 10, 9 }; + int data2[] = { 2, 16, 4, 14, 6, 6, 4, 5, 10, 9 }; + + struct Multiply + { + void operator()(int& i) + { + i *= 2; + } + } multiplier; + + etl::for_each_n(std::begin(data1), 5, multiplier); + + bool are_equal = std::equal(std::begin(data1), std::end(data1), std::begin(data2)); + CHECK(are_equal); + } + + //========================================================================= + TEST(for_each_n_if) + { + int data1[] = { 1, 8, 2, 7, 3, 6, 4, 5, 10, 9 }; + int data2[] = { 2, 8, 4, 7, 6, 6, 4, 5, 10, 9 }; + + struct Multiply + { + void operator()(int& i) + { + i *= 2; + } + } multiplier; + + etl::for_each_n_if(std::begin(data1), 5, multiplier, std::bind2nd(std::less(), 5)); + + bool are_equal = std::equal(std::begin(data1), std::end(data1), std::begin(data2)); + CHECK(are_equal); + } + //========================================================================= TEST(transform_4_parameter) {