From aa148ac4244fb886027bbd4d9676849a1264b0a3 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 27 Dec 2020 11:59:14 +0000 Subject: [PATCH] Latest implementation --- include/etl/functional.h | 217 ++++++++++++++++++++++++++++++++++++++- include/etl/multi_loop.h | 51 ++++++--- test/test_functional.cpp | 138 +++++++++++++++++++++++-- test/test_multi_loop.cpp | 122 +++++++++++++--------- 4 files changed, 458 insertions(+), 70 deletions(-) diff --git a/include/etl/functional.h b/include/etl/functional.h index d9258262..11d613eb 100644 --- a/include/etl/functional.h +++ b/include/etl/functional.h @@ -118,6 +118,18 @@ namespace etl } }; + //*************************************************************************** + template + struct less_equal + { + typedef T value_type; + + ETL_CONSTEXPR bool operator()(const T& lhs, const T& rhs) const + { + return lhs <= rhs; + } + }; + //*************************************************************************** template struct greater @@ -130,6 +142,18 @@ namespace etl } }; + //*************************************************************************** + template + struct greater_equal + { + typedef T value_type; + + ETL_CONSTEXPR bool operator()(const T& lhs, const T& rhs) const + { + return lhs >= rhs; + } + }; + //*************************************************************************** template struct equal_to @@ -238,6 +262,187 @@ namespace etl return binder2nd(f, x); } + //*************************************************************************** + template + struct plus + { + typedef T first_argument_type; + typedef T second_argument_type; + typedef T result_type; + + ETL_CONSTEXPR T operator()(const T& lhs, const T& rhs) const + { + return lhs + rhs; + } + }; + + //*************************************************************************** + template + struct minus + { + typedef T first_argument_type; + typedef T second_argument_type; + typedef T result_type; + + ETL_CONSTEXPR T operator()(const T& lhs, const T& rhs) const + { + return lhs - rhs; + } + }; + + //*************************************************************************** + template + struct negate + { + typedef T argument_type; + typedef T result_type; + + ETL_CONSTEXPR T operator()(const T& lhs) const + { + return -lhs; + } + }; + + //*************************************************************************** + template + struct multiplies + { + typedef T first_argument_type; + typedef T second_argument_type; + typedef T result_type; + + ETL_CONSTEXPR T operator()(const T& lhs, const T& rhs) const + { + return lhs * rhs; + } + }; + + //*************************************************************************** + template + struct divides + { + typedef T first_argument_type; + typedef T second_argument_type; + typedef T result_type; + + ETL_CONSTEXPR T operator()(const T& lhs, const T& rhs) const + { + return lhs / rhs; + } + }; + + //*************************************************************************** + template + struct modulus + { + typedef T first_argument_type; + typedef T second_argument_type; + typedef T result_type; + + ETL_CONSTEXPR T operator()(const T& lhs, const T& rhs) const + { + return lhs % rhs; + } + }; + + //*************************************************************************** + template + struct logical_and + { + typedef T first_argument_type; + typedef T second_argument_type; + typedef T result_type; + + ETL_CONSTEXPR T operator()(const T& lhs, const T& rhs) const + { + return lhs && rhs; + } + }; + + //*************************************************************************** + template + struct logical_or + { + typedef T first_argument_type; + typedef T second_argument_type; + typedef T result_type; + + ETL_CONSTEXPR T operator()(const T& lhs, const T& rhs) const + { + return lhs || rhs; + } + }; + + //*************************************************************************** + template + struct logical_not + { + typedef T first_argument_type; + typedef T second_argument_type; + typedef T result_type; + + ETL_CONSTEXPR T operator()(const T& lhs) const + { + return !lhs; + } + }; + + //*************************************************************************** + template + struct bit_and + { + typedef T first_argument_type; + typedef T second_argument_type; + typedef T result_type; + + ETL_CONSTEXPR T operator()(const T& lhs, const T& rhs) const + { + return lhs & rhs; + } + }; + + //*************************************************************************** + template + struct bit_or + { + typedef T first_argument_type; + typedef T second_argument_type; + typedef T result_type; + + ETL_CONSTEXPR T operator()(const T& lhs, const T& rhs) const + { + return lhs | rhs; + } + }; + + //*************************************************************************** + template + struct bit_xor + { + typedef T first_argument_type; + typedef T second_argument_type; + typedef T result_type; + + ETL_CONSTEXPR T operator()(const T& lhs, const T& rhs) const + { + return lhs ^ rhs; + } + }; + + //*************************************************************************** + template + struct bit_not + { + typedef T first_argument_type; + typedef T second_argument_type; + typedef T result_type; + + ETL_CONSTEXPR T operator()(const T& lhs) const + { + return ~lhs; + } + }; + //*************************************************************************** template @@ -246,11 +451,12 @@ namespace etl T operator()(T& value) { ++value; - return value; } }; + //*************************************************************************** + template struct post_increment { @@ -262,22 +468,27 @@ namespace etl } }; + //*************************************************************************** + template struct increment : etl::pre_increment { }; + //*************************************************************************** + template struct pre_decrement { T operator()(T& value) { --value; - return value; } }; + //*************************************************************************** + template struct post_decrement { @@ -289,6 +500,8 @@ namespace etl } }; + //*************************************************************************** + template struct decrement : etl::pre_decrement { diff --git a/include/etl/multi_loop.h b/include/etl/multi_loop.h index 1bf82fad..d652fc9c 100644 --- a/include/etl/multi_loop.h +++ b/include/etl/multi_loop.h @@ -115,12 +115,23 @@ namespace etl //*************************************************************************** /// Unlinks this loop from its inner. - /// Re-starts the loop. //*************************************************************************** - void clear() + void detach() { inner = ETL_NULLPTR; - start(); + } + + //*************************************************************************** + /// Unlinks this and all inner loops. + //*************************************************************************** + void detach_all() + { + if (inner != ETL_NULLPTR) + { + inner->detach_all(); + } + + detach(); } //*************************************************************************** @@ -225,10 +236,14 @@ namespace etl //*************************************************************************** /// multi_loop /// \tparam T The type to loop over. - /// \tparam TIncrementor The incrementor type that implements operator() to increment. + /// \tparam TStepper The type that implements operator() to step. /// Default = etl::increment, which calls operator ++() for the type. + /// \tparam TContinue The type that implements operator() to test for loop continuation. + /// Default = etl::not_equal_to, which calls operator !=() for the type. //*************************************************************************** - template class TIncrementor = etl::increment> + template , + typename TContinue = etl::not_equal_to > class multi_loop : public imulti_loop { public: @@ -241,10 +256,15 @@ namespace etl /// \param first The starting value of the loop. /// \param last The terminating value of the loop. Equal to the last required value + 1. //*************************************************************************** - multi_loop(value_type first_, value_type last_) + multi_loop(value_type first_, + value_type last_, + TStepper stepper_ = TStepper(), + TContinue continue_loop_ = TContinue()) : first(first_) , last(last_) , current(first_) + , stepper(stepper_) + , continue_loop(continue_loop_) { } @@ -276,7 +296,7 @@ namespace etl } current = first; - has_completed = false; + has_completed = !continue_loop(current, last); // Check for null loop. } //*************************************************************************** @@ -292,12 +312,12 @@ namespace etl if (inner->completed()) { - has_completed = increment(); + has_completed = step(); } } else { - has_completed = increment(); + has_completed = step(); } } @@ -314,11 +334,11 @@ namespace etl //*************************************************************************** /// Increments the current loop value. //*************************************************************************** - bool increment() + bool step() { - incrementor(current); + current = stepper(current); - const bool has_rolled_over = (current == last); + const bool has_rolled_over = !continue_loop(current, last); if (has_rolled_over) { @@ -327,12 +347,13 @@ namespace etl return has_rolled_over; } - - TIncrementor incrementor; ///< The incrementor type. - + value_type first; ///< The first value of the loop. value_type last; ///< The terminating value of the loop. value_type current; ///< The current value of the loop. + + TStepper stepper; ///< The type to step the value to the next. + TContinue continue_loop; ///< The type to determine if the loop should continue. }; } diff --git a/test/test_functional.cpp b/test/test_functional.cpp index 3e9856db..a6709760 100644 --- a/test/test_functional.cpp +++ b/test/test_functional.cpp @@ -60,6 +60,14 @@ namespace CHECK(!(compare>(1, 1))); } + //************************************************************************* + TEST(test_less_equal) + { + CHECK((compare>(1, 2))); + CHECK(!(compare>(2, 1))); + CHECK((compare>(1, 1))); + } + //************************************************************************* TEST(test_greater) { @@ -68,6 +76,14 @@ namespace CHECK(!(compare>(1, 1))); } + //************************************************************************* + TEST(test_greater_equal) + { + CHECK(!(compare>(1, 2))); + CHECK((compare>(2, 1))); + CHECK((compare>(1, 1))); + } + //************************************************************************* TEST(test_equal_to) { @@ -186,13 +202,13 @@ namespace //************************************************************************* TEST(test_pre_decrement) { - etl::pre_decrement pi; + etl::pre_decrement pd; int i = 0; int j = 0; - pi(i); - j = pi(i); + pd(i); + j = pd(i); CHECK_EQUAL(-2, i); CHECK_EQUAL(-2, j); @@ -201,16 +217,126 @@ namespace //************************************************************************* TEST(test_post_decrement) { - etl::post_decrement pi; + etl::post_decrement pd; int i = 0; int j = 0; - pi(i); - j = pi(i); + pd(i); + j = pd(i); CHECK_EQUAL(-2, i); CHECK_EQUAL(-1, j); } + + //************************************************************************* + TEST(test_plus) + { + auto f = etl::plus(); + CHECK_EQUAL(2 + 4, f(2, 4)); + } + + //************************************************************************* + TEST(test_minus) + { + auto f = etl::minus(); + CHECK_EQUAL(2 - 4, f(2, 4)); + } + + //************************************************************************* + TEST(test_negate) + { + auto f = etl::negate(); + CHECK_EQUAL(-2, f(2)); + } + + //************************************************************************* + TEST(test_multiplies) + { + auto f = etl::multiplies(); + CHECK_EQUAL(2 * 4, f(2, 4)); + } + + //************************************************************************* + TEST(test_divides) + { + auto f = etl::divides(); + CHECK_EQUAL(4 / 2, f(4, 2)); + } + + //************************************************************************* + TEST(test_modulus) + { + auto f = etl::modulus(); + CHECK_EQUAL(5 % 2, f(5, 2)); + } + + //************************************************************************* + TEST(test_logical_and) + { + auto f = etl::logical_and(); + CHECK_EQUAL(false && false, f(false, false)); + CHECK_EQUAL(false && true, f(false, true)); + CHECK_EQUAL(true && false, f(true, false)); + CHECK_EQUAL(true && true, f(true, true)); + } + + //************************************************************************* + TEST(test_logical_or) + { + auto f = etl::logical_or(); + CHECK_EQUAL(false || false, f(false, false)); + CHECK_EQUAL(false || true, f(false, true)); + CHECK_EQUAL(true || false, f(true, false)); + CHECK_EQUAL(true || true, f(true, true)); + } + + //************************************************************************* + TEST(test_logical_not) + { + auto f = etl::logical_not(); + CHECK_EQUAL(!false, f(false)); + CHECK_EQUAL(!true, f(true)); + } + + //************************************************************************* + TEST(test_bit_and) + { + auto f = etl::bit_and(); + CHECK_EQUAL(0x00 & 0xFF, f(0x00, 0xFF)); + CHECK_EQUAL(0xAA & 0xFF, f(0xAA, 0xFF)); + CHECK_EQUAL(0x55 & 0xFF, f(0x55, 0xFF)); + CHECK_EQUAL(0xFF & 0xFF, f(0xFF, 0xFF)); + } + + //************************************************************************* + TEST(test_bit_or) + { + auto f = etl::bit_or(); + CHECK_EQUAL(0xFF | 0x00, f(0xFF, 0x00)); + CHECK_EQUAL(0xAA | 0x00, f(0xAA, 0x00)); + CHECK_EQUAL(0x55 | 0x00, f(0x55, 0x00)); + CHECK_EQUAL(0x55 | 0xAA, f(0x55, 0xAA)); + } + + //************************************************************************* + TEST(test_bit_xor) + { + auto f = etl::bit_xor(); + CHECK_EQUAL(0xFF ^ 0x00, f(0xFF, 0x00)); + CHECK_EQUAL(0xAA ^ 0x00, f(0xAA, 0x00)); + CHECK_EQUAL(0x55 ^ 0x00, f(0x55, 0x00)); + CHECK_EQUAL(0x55 ^ 0xAA, f(0x55, 0xAA)); + } + + //************************************************************************* + TEST(test_bit_not) + { + auto f = etl::bit_not(); + CHECK_EQUAL(uint8_t(~0x00), f(0x00)); + CHECK_EQUAL(uint8_t(~0x55), f(0x55)); + CHECK_EQUAL(uint8_t(~0xAA), f(0xAA)); + CHECK_EQUAL(uint8_t(~0xFF), f(0xFF)); + } }; } diff --git a/test/test_multi_loop.cpp b/test/test_multi_loop.cpp index b6c5f231..edea4f6d 100644 --- a/test/test_multi_loop.cpp +++ b/test/test_multi_loop.cpp @@ -29,11 +29,13 @@ SOFTWARE. #include "UnitTest++/UnitTest++.h" #include "etl/multi_loop.h" +#include "etl/functional.h" #include #include #include #include +#include namespace { @@ -107,8 +109,28 @@ namespace using Iterator = std::forward_list::const_iterator; - using Outer = etl::multi_loop; - using Middle = etl::multi_loop; + struct Adder + { + Adder() + : value(0) + { + } + + Adder(int value_) + : value(value_) + { + } + + int operator()(int i) + { + return i + value; + } + + int value; + }; + + using Outer = etl::multi_loop; + using Middle = etl::multi_loop, etl::greater>; using Inner = etl::multi_loop; std::forward_list strings = @@ -116,7 +138,7 @@ namespace "zero", "one", "two", "three" }; - Outer outer(0, 4); + Outer outer(0, 8, Adder(2)); Middle middle(Index(2), Index(-2)); Inner inner(strings.begin(), strings.end()); @@ -125,16 +147,12 @@ namespace //************************************************************************* TEST(create_three_loops) { - outer.clear(); - middle.clear(); - inner.clear(); - outer.append(middle); middle.insert(inner); - CHECK(!outer.completed()); - CHECK(!middle.completed()); - CHECK(!inner.completed()); + CHECK(outer.completed()); + CHECK(middle.completed()); + CHECK(inner.completed()); CHECK_EQUAL(3U, outer.number_of_loops()); CHECK_EQUAL(2U, middle.number_of_loops()); @@ -145,7 +163,7 @@ namespace CHECK_EQUAL(4U, inner.number_of_iterations()); CHECK_EQUAL(0, outer.begin()); - CHECK_EQUAL(4, outer.end()); + CHECK_EQUAL(8, outer.end()); CHECK_EQUAL(outer.begin(), outer.value()); CHECK_EQUAL(Index(2), middle.begin()); @@ -155,21 +173,19 @@ namespace CHECK(strings.begin() == inner.begin()); CHECK(strings.end() == inner.end()); CHECK(inner.begin() == inner.value()); + + outer.detach_all(); } //************************************************************************* TEST(create_three_loops_different_order) { - outer.clear(); - middle.clear(); - inner.clear(); - middle.append(inner); outer.insert(middle); - CHECK(!outer.completed()); - CHECK(!middle.completed()); - CHECK(!inner.completed()); + CHECK(outer.completed()); + CHECK(middle.completed()); + CHECK(inner.completed()); CHECK_EQUAL(3U, outer.number_of_loops()); CHECK_EQUAL(2U, middle.number_of_loops()); @@ -180,7 +196,7 @@ namespace CHECK_EQUAL(4U, inner.number_of_iterations()); CHECK_EQUAL(0, outer.begin()); - CHECK_EQUAL(4, outer.end()); + CHECK_EQUAL(8, outer.end()); CHECK_EQUAL(outer.begin(), outer.value()); CHECK_EQUAL(Index(2), middle.begin()); @@ -190,20 +206,18 @@ namespace CHECK(strings.begin() == inner.begin()); CHECK(strings.end() == inner.end()); CHECK(inner.begin() == inner.value()); + + outer.detach_all(); } //************************************************************************* TEST(create_three_loops_functional_style) { - outer.clear(); - middle.clear(); - inner.clear(); - outer.append(inner).insert(middle); - CHECK(!outer.completed()); - CHECK(!middle.completed()); - CHECK(!inner.completed()); + CHECK(outer.completed()); + CHECK(middle.completed()); + CHECK(inner.completed()); CHECK_EQUAL(3U, outer.number_of_loops()); CHECK_EQUAL(2U, middle.number_of_loops()); @@ -214,7 +228,7 @@ namespace CHECK_EQUAL(4U, inner.number_of_iterations()); CHECK_EQUAL(0, outer.begin()); - CHECK_EQUAL(4, outer.end()); + CHECK_EQUAL(8, outer.end()); CHECK_EQUAL(outer.begin(), outer.value()); CHECK_EQUAL(Index(2), middle.begin()); @@ -224,28 +238,42 @@ namespace CHECK(strings.begin() == inner.begin()); CHECK(strings.end() == inner.end()); CHECK(inner.begin() == inner.value()); + + outer.detach_all(); } //************************************************************************* TEST(create_three_loops_circular_links) { - outer.clear(); - middle.clear(); - inner.clear(); - middle.append(outer); CHECK_THROW(outer.append(middle), etl::multi_loop_circular_reference); CHECK_THROW(inner.append(inner), etl::multi_loop_circular_reference); + + outer.detach(); + middle.detach(); + inner.detach(); + } + + //************************************************************************* + TEST(null_loop) + { + Outer null_loop(2, 2); + + CHECK(null_loop.completed()); + + CHECK_EQUAL(1U, null_loop.number_of_loops()); + + CHECK_EQUAL(0U, null_loop.number_of_iterations()); + + CHECK_EQUAL(2, null_loop.begin()); + CHECK_EQUAL(2, null_loop.end()); + CHECK_EQUAL(null_loop.begin(), null_loop.value()); } //************************************************************************* TEST(run_three_loops) { - outer.clear(); - middle.clear(); - inner.clear(); - outer.append(middle).append(inner); struct result @@ -261,18 +289,18 @@ namespace result{ 0, 1, "zero" }, result{ 0, 1, "one" }, result{ 0, 1, "two" }, result{ 0, 1, "three" }, result{ 0, 0, "zero" }, result{ 0, 0, "one" }, result{ 0, 0, "two" }, result{ 0, 0, "three" }, result{ 0, -1, "zero" }, result{ 0, -1, "one" }, result{ 0, -1, "two" }, result{ 0, -1, "three" }, - result{ 1, 2, "zero" }, result{ 1, 2, "one" }, result{ 1, 2, "two" }, result{ 1, 2, "three" }, - result{ 1, 1, "zero" }, result{ 1, 1, "one" }, result{ 1, 1, "two" }, result{ 1, 1, "three" }, - result{ 1, 0, "zero" }, result{ 1, 0, "one" }, result{ 1, 0, "two" }, result{ 1, 0, "three" }, - result{ 1, -1, "zero" }, result{ 1, -1, "one" }, result{ 1, -1, "two" }, result{ 1, -1, "three" }, result{ 2, 2, "zero" }, result{ 2, 2, "one" }, result{ 2, 2, "two" }, result{ 2, 2, "three" }, result{ 2, 1, "zero" }, result{ 2, 1, "one" }, result{ 2, 1, "two" }, result{ 2, 1, "three" }, result{ 2, 0, "zero" }, result{ 2, 0, "one" }, result{ 2, 0, "two" }, result{ 2, 0, "three" }, result{ 2, -1, "zero" }, result{ 2, -1, "one" }, result{ 2, -1, "two" }, result{ 2, -1, "three" }, - result{ 3, 2, "zero" }, result{ 3, 2, "one" }, result{ 3, 2, "two" }, result{ 3, 2, "three" }, - result{ 3, 1, "zero" }, result{ 3, 1, "one" }, result{ 3, 1, "two" }, result{ 3, 1, "three" }, - result{ 3, 0, "zero" }, result{ 3, 0, "one" }, result{ 3, 0, "two" }, result{ 3, 0, "three" }, - result{ 3, -1, "zero" }, result{ 3, -1, "one" }, result{ 3, -1, "two" }, result{ 3, -1, "three" } + result{ 4, 2, "zero" }, result{ 4, 2, "one" }, result{ 4, 2, "two" }, result{ 4, 2, "three" }, + result{ 4, 1, "zero" }, result{ 4, 1, "one" }, result{ 4, 1, "two" }, result{ 4, 1, "three" }, + result{ 4, 0, "zero" }, result{ 4, 0, "one" }, result{ 4, 0, "two" }, result{ 4, 0, "three" }, + result{ 4, -1, "zero" }, result{ 4, -1, "one" }, result{ 4, -1, "two" }, result{ 4, -1, "three" }, + result{ 6, 2, "zero" }, result{ 6, 2, "one" }, result{ 6, 2, "two" }, result{ 6, 2, "three" }, + result{ 6, 1, "zero" }, result{ 6, 1, "one" }, result{ 6, 1, "two" }, result{ 6, 1, "three" }, + result{ 6, 0, "zero" }, result{ 6, 0, "one" }, result{ 6, 0, "two" }, result{ 6, 0, "three" }, + result{ 6, -1, "zero" }, result{ 6, -1, "one" }, result{ 6, -1, "two" }, result{ 6, -1, "three" } }; size_t i = 0U; @@ -322,15 +350,13 @@ namespace } CHECK(outer.completed()); + + outer.detach_all(); } //************************************************************************* TEST(create_three_loops_but_just_run_the_inner_two) { - outer.clear(); - middle.clear(); - inner.clear(); - outer.append(middle).append(inner); struct result @@ -395,6 +421,8 @@ namespace } CHECK(middle.completed()); + + outer.detach_all(); } }; }