diff --git a/include/etl/cyclic_value.h b/include/etl/cyclic_value.h index 392c7a14..2d129993 100644 --- a/include/etl/cyclic_value.h +++ b/include/etl/cyclic_value.h @@ -46,6 +46,36 @@ SOFTWARE. namespace etl { + namespace detail + { + //Helper: only performs the v < F check when has_lower == true –– + template + struct lower_bound_impl; + + // Specialisation for First != 0: enforce v >= First + template + struct lower_bound_impl + { + static ETL_CONSTEXPR auto apply(U& v) ETL_NOEXCEPT -> void + { + if (v < F) + { + v = F; + } + } + }; + + // Specialisation for First == 0: no-op + template + struct lower_bound_impl + { + static ETL_CONSTEXPR auto apply(U&) ETL_NOEXCEPT -> void + { + // nothing + } + }; + } // namespace detail + //*************************************************************************** /// Provides a value that cycles between two limits. //*************************************************************************** @@ -113,10 +143,9 @@ namespace etl { value_ = Last; } - else if (value_ < First) - { - value_ = First; - } + + // lower-bound clamp only if First != 0 + detail::lower_bound_impl<(First != 0), T, First>::apply(value_); value = value_; } @@ -351,7 +380,7 @@ namespace etl cyclic_value(T first_, T last_) : value(first_) , first_value(first_) - , last_value(last_) + , last_value(last_) { } diff --git a/include/etl/string_utilities.h b/include/etl/string_utilities.h index 459c5cb0..46ead0bf 100644 --- a/include/etl/string_utilities.h +++ b/include/etl/string_utilities.h @@ -756,6 +756,45 @@ namespace etl return etl::optional(view); } + //*************************************************************************** + /// get_token_list + ///\brief Splits a string of tokens to a set of views, according to a set of delimiters. + /// The tokenisation stops if: + /// 1. The end of the input text is reached. + /// 2. The max_size() of the output container is reached. + /// 3. The number of tokens found reaches max_n_tokens. + /// The input container must define const_pointer. + /// The output container must define value_type. + /// The output container must define the member function max_size that returns the maximum size of the container. + /// The output container must define the member function push_back that pushes the view on to the back of the container. + ///\param input The input string. + ///\param output A reference to an output container of string views. + ///\param delimiters A pointer to a string of valid delimiters. + ///\param ignore_empty_tokens If true then empty tokens are ignored. + ///\param max_n_tokens The maximum number of tokens to collect. Default tokenise everything. + ///\return Returns true if all tokens were added to the list, otherwise false. + //*************************************************************************** + template + bool get_token_list(const TInput& input, TOutput& output, typename TInput::const_pointer delimiters, bool ignore_empty_tokens, size_t max_n_tokens = etl::integral_limits::max) + { + typedef typename TOutput::value_type string_view_t; + + etl::optional token; + + size_t count = 0; + while ((count != output.max_size()) && + (count != max_n_tokens) && + (token = etl::get_token(input, delimiters, token, ignore_empty_tokens))) + { + output.push_back(token.value()); + ++count; + } + + bool all_tokens_found = (token.has_value() == false); + + return all_tokens_found; + } + //*************************************************************************** /// pad_left //*************************************************************************** diff --git a/support/Release notes.txt b/support/Release notes.txt index 3d8b4ca7..e16a0e24 100644 --- a/support/Release notes.txt +++ b/support/Release notes.txt @@ -3,6 +3,7 @@ Updates: Added etl::tuple +Added get_token_list to string_utilities to retrieve multiple tokens #757 Add etl::chrono time/date classes #1085 Add The Remaining Math Operators To ETL_TYPEDEF #1084 Add 'type' Alias to Strong Types @@ -29,6 +30,7 @@ Fixes: #1041 Incorrect rounding of scaled natural numbers in scaled_rounding #1041 Pull Requests: +#1088 Fix numeric overflow in bip buffer's get_write_reserve #1090 Fix copy_s() for C++03 #1089 Cleanup fixes for C++03 #1083 Add take() to etl::span diff --git a/test/test_string_utilities.cpp b/test/test_string_utilities.cpp index 6b2006a9..2b661322 100644 --- a/test/test_string_utilities.cpp +++ b/test/test_string_utilities.cpp @@ -34,6 +34,9 @@ SOFTWARE. #include "etl/vector.h" #include +#include +#include +#include #undef STR #define STR(x) x @@ -54,6 +57,9 @@ namespace using Vector = etl::vector; using SizeType = etl::istring::size_type; + using VectorOfViews7 = etl::vector; + using VectorOfViews5 = etl::vector; + #if ETL_USING_CPP17 constexpr auto Whitespace = etl::whitespace_v; #else @@ -1085,6 +1091,121 @@ namespace CHECK_EQUAL(0U, tokens.size()); } + //************************************************************************* + TEST(test_split_to_vector_of_string_view_all_tokens_captured_ignore_empty_tokens) + { + String text(STR(",,,The,cat,sat,,on,the,mat")); + VectorOfViews7 views; + + bool all_views_found = etl::get_token_list(text, views, STR(","), true); + + CHECK_TRUE(all_views_found); + CHECK_EQUAL(6, views.size()); + CHECK_EQUAL(std::string("The"), std::string(views[0].begin(), views[0].end())); + CHECK_EQUAL(std::string("cat"), std::string(views[1].begin(), views[1].end())); + CHECK_EQUAL(std::string("sat"), std::string(views[2].begin(), views[2].end())); + CHECK_EQUAL(std::string("on"), std::string(views[3].begin(), views[3].end())); + CHECK_EQUAL(std::string("the"), std::string(views[4].begin(), views[4].end())); + CHECK_EQUAL(std::string("mat"), std::string(views[5].begin(), views[5].end())); + } + + //************************************************************************* + TEST(test_get_token_list_to_vector_of_string_view_all_but_1_tokens_captured_ignore_empty_tokens) + { + String text(STR(",,,The,cat,sat,,on,the,mat")); + VectorOfViews5 views; + + bool all_views_found = etl::get_token_list(text, views, STR(","), true); + + CHECK_FALSE(all_views_found); + CHECK_EQUAL(5, views.size()); + CHECK_EQUAL(std::string("The"), std::string(views[0].begin(), views[0].end())); + CHECK_EQUAL(std::string("cat"), std::string(views[1].begin(), views[1].end())); + CHECK_EQUAL(std::string("sat"), std::string(views[2].begin(), views[2].end())); + CHECK_EQUAL(std::string("on"), std::string(views[3].begin(), views[3].end())); + CHECK_EQUAL(std::string("the"), std::string(views[4].begin(), views[4].end())); + } + +#if ETL_USING_CPP17 + //************************************************************************* + TEST(test_get_token_list_to_std_vector_of_std_string_view_all_tokens_captured_ignore_empty_tokens) + { + std::string text(STR(",,,The,cat,sat,,on,the,mat")); + std::vector views; + + bool all_views_found = etl::get_token_list(text, views, STR(","), true); + + CHECK_TRUE(all_views_found); + CHECK_EQUAL(6, views.size()); + CHECK_EQUAL(std::string("The"), std::string(views[0].begin(), views[0].end())); + CHECK_EQUAL(std::string("cat"), std::string(views[1].begin(), views[1].end())); + CHECK_EQUAL(std::string("sat"), std::string(views[2].begin(), views[2].end())); + CHECK_EQUAL(std::string("on"), std::string(views[3].begin(), views[3].end())); + CHECK_EQUAL(std::string("the"), std::string(views[4].begin(), views[4].end())); + CHECK_EQUAL(std::string("mat"), std::string(views[5].begin(), views[5].end())); + } +#endif + + //************************************************************************* + TEST(test_get_token_list_to_vector_of_string_view_all_tokens_captured_ignore_empty_tokens_maximum_of_3_tokens) + { + String text(STR(",,,The,cat,sat,,on,the,mat")); + VectorOfViews7 views; + + bool all_views_found = etl::get_token_list(text, views, STR(","), true, 3); + + CHECK_FALSE(all_views_found); + CHECK_EQUAL(3, views.size()); + CHECK_EQUAL(std::string("The"), std::string(views[0].begin(), views[0].end())); + CHECK_EQUAL(std::string("cat"), std::string(views[1].begin(), views[1].end())); + CHECK_EQUAL(std::string("sat"), std::string(views[2].begin(), views[2].end())); + } + +#if ETL_USING_CPP17 + //************************************************************************* + TEST(test_get_token_list_to_std_vector_of_std_string_view_all_tokens_captured_ignore_empty_tokens_maximum_of_3_tokens) + { + std::string text(STR(",,,The,cat,sat,,on,the,mat")); + std::vector views; + + bool all_views_found = etl::get_token_list(text, views, STR(","), true, 3); + + CHECK_FALSE(all_views_found); + CHECK_EQUAL(3, views.size()); + CHECK_EQUAL(std::string("The"), std::string(views[0].begin(), views[0].end())); + CHECK_EQUAL(std::string("cat"), std::string(views[1].begin(), views[1].end())); + CHECK_EQUAL(std::string("sat"), std::string(views[2].begin(), views[2].end())); + } +#endif + +#if ETL_USING_CPP17 + //************************************************************************* + TEST(test_get_token_list_to_std_list_of_std_string_view_all_tokens_captured_ignore_empty_tokens) + { + std::string text(STR(",,,The,cat,sat,,on,the,mat")); + std::list views; + + bool all_views_found = etl::get_token_list(text, views, STR(","), true); + + CHECK_TRUE(all_views_found); + CHECK_EQUAL(6, views.size()); + + auto itr = views.begin(); + + CHECK_EQUAL(std::string("The"), std::string(itr->begin(), itr->end())); + ++itr; + CHECK_EQUAL(std::string("cat"), std::string(itr->begin(), itr->end())); + ++itr; + CHECK_EQUAL(std::string("sat"), std::string(itr->begin(), itr->end())); + ++itr; + CHECK_EQUAL(std::string("on"), std::string(itr->begin(), itr->end())); + ++itr; + CHECK_EQUAL(std::string("the"), std::string(itr->begin(), itr->end())); + ++itr; + CHECK_EQUAL(std::string("mat"), std::string(itr->begin(), itr->end())); + } +#endif + //************************************************************************* TEST(test_pad_left) {