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)
{