From 99cc550b055f9d39134756606c70904c0687f44b Mon Sep 17 00:00:00 2001 From: Denis Mikhaylov Date: Mon, 14 Nov 2022 15:17:34 +0600 Subject: [PATCH 1/4] Add 'boost::intersperse' string algorithm --- .../algorithm/string/detail/formatter.hpp | 23 +++ .../algorithm/string/detail/intersperse.hpp | 56 ++++++ include/boost/algorithm/string/formatter.hpp | 21 ++ .../boost/algorithm/string/intersperse.hpp | 182 ++++++++++++++++++ string/test/Jamfile.v2 | 6 + string/test/intersperse_test.cpp | 103 ++++++++++ 6 files changed, 391 insertions(+) mode change 100644 => 100755 include/boost/algorithm/string/detail/formatter.hpp create mode 100755 include/boost/algorithm/string/detail/intersperse.hpp mode change 100644 => 100755 include/boost/algorithm/string/formatter.hpp create mode 100755 include/boost/algorithm/string/intersperse.hpp mode change 100644 => 100755 string/test/Jamfile.v2 create mode 100755 string/test/intersperse_test.cpp diff --git a/include/boost/algorithm/string/detail/formatter.hpp b/include/boost/algorithm/string/detail/formatter.hpp old mode 100644 new mode 100755 index f4c6728b3..c6135f465 --- a/include/boost/algorithm/string/detail/formatter.hpp +++ b/include/boost/algorithm/string/detail/formatter.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include @@ -111,6 +112,28 @@ namespace boost { FinderT m_Finder; }; +// joint format functor ----------------------------------------------------// + + // joint format functor + template + struct join_formatF + { + public: + // Construction + join_formatF(const RangeT& Other) : + m_Other(Other) {} + + template + inline joined_range< + const Range2T, const RangeT> + operator()(const Range2T& Replace) const + { + return ::boost::range::join(Replace, m_Other); + } + + private: + RangeT m_Other; + }; } // namespace detail } // namespace algorithm diff --git a/include/boost/algorithm/string/detail/intersperse.hpp b/include/boost/algorithm/string/detail/intersperse.hpp new file mode 100755 index 000000000..041dbcaa0 --- /dev/null +++ b/include/boost/algorithm/string/detail/intersperse.hpp @@ -0,0 +1,56 @@ +// Boost string_algo library intersperse.hpp header file ---------------------------// + +// Copyright Denis Mikhailov 2022. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_INTERSPERSE_DETAIL_HPP +#define BOOST_STRING_INTERSPERSE_DETAIL_HPP + +#include +#include + +#include +#include +#include // for iterator_adaptor + +namespace boost { + namespace algorithm { + namespace detail { + + // just workaround for https://github.com/boostorg/iterator/issues/75 + // FIXME remove this when the issue will be resolved + template + struct just_iterator_adaptor : iterator_adaptor, It> { + explicit just_iterator_adaptor(It p) + : just_iterator_adaptor::iterator_adaptor_(p) {} + }; + + // functor to be passed into ::boost::token_finder + template + class non_last_condition { + public: + typedef BOOST_STRING_TYPENAME range_size::type size_type; + typedef BOOST_STRING_TYPENAME range_value::type value_type; + + explicit non_last_condition(size_type s, size_type& counter) + : m_Size(s), m_Counter(counter) { } + bool operator() (const value_type&) const { + return ++m_Counter < m_Size; + } + private: + const size_type m_Size; + size_type& m_Counter; + }; + + + } // namespace detail + } // namespace algorithm +} // namespace boost + + +#endif // BOOST_STRING_INTERSPERSE_DETAIL_HPP diff --git a/include/boost/algorithm/string/formatter.hpp b/include/boost/algorithm/string/formatter.hpp old mode 100644 new mode 100755 index 0e08ae7b3..f29eb7cd2 --- a/include/boost/algorithm/string/formatter.hpp +++ b/include/boost/algorithm/string/formatter.hpp @@ -104,6 +104,26 @@ namespace boost { return detail::dissect_formatF(Finder); } + //! Join formatter + /*! + Constructs a \c join_formatter. Join formatter uses an other range to concatenate parameter + with the range. The joining of parameter and the range is returned + as a result + + \param Other a range used to be concatenated with parameter + \return An instance of the \c join_formatter object. + */ + template + inline detail::join_formatF< + iterator_range< + BOOST_STRING_TYPENAME range_const_iterator::type> > + join_formatter(const RangeT& Other) + { + return detail::join_formatF< + iterator_range< + BOOST_STRING_TYPENAME range_const_iterator::type> >(::boost::as_literal(Other)); + } + } // namespace algorithm @@ -112,6 +132,7 @@ namespace boost { using algorithm::identity_formatter; using algorithm::empty_formatter; using algorithm::dissect_formatter; + using algorithm::join_formatter; } // namespace boost diff --git a/include/boost/algorithm/string/intersperse.hpp b/include/boost/algorithm/string/intersperse.hpp new file mode 100755 index 000000000..c84cafd42 --- /dev/null +++ b/include/boost/algorithm/string/intersperse.hpp @@ -0,0 +1,182 @@ +// Boost string_algo library intersperse.hpp header file ---------------------------// + +// Copyright Denis Mikhailov 2022. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_INTERSPERSE_HPP +#define BOOST_STRING_INTERSPERSE_HPP + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/*! \file + Defines intersperse algorithms. + Intersperse algorithms are used to insert value between each contiguous elements + from a sequence (string). Also, variants with (\c _fill) postfix can insert a whole + range instead of value. + + Parametric (\c _generate) variants use a generator (functor) to obtain characters + to be inserted.. + Functions take a nullary function object as a parameter, which is used to extract + a new character and then insert. +*/ + +namespace boost { + namespace algorithm { + + // intersperse fill -----------------------------------------------// + + + //! Intersperse fill + /*! + Insert string between each contiguous elements from the input. + The input sequence is modified in-place. + + \param Input An input sequence + \param Fill A string to be inserted + */ + template + inline void intersperse_fill(SequenceT& Input, const RangeT& Fill) + { + typename ::boost::range_size::type counter = 0; + ::boost::find_format_all( + Input, + ::boost::token_finder( + detail::non_last_condition(::boost::size(Input), counter)), + ::boost::join_formatter(::boost::as_literal(Fill))); + } + + //! Intersperse fill + /*! + Insert string between each contiguous elements from the input. + The result is an interspersed copy of the input + + \param Input An input sequence + \param Fill A string to be inserted + \return An interspersed copy of the input + + \note This function provides the strong exception-safety guarantee + */ + template + inline SequenceT intersperse_fill_copy( + const SequenceT& Input, + const RangeT& Fill) + { + typename ::boost::range_size::type counter = 0; + return + ::boost::find_format_all_copy( + Input, + ::boost::token_finder( + detail::non_last_condition(::boost::size(Input), counter)), + ::boost::join_formatter(::boost::as_literal(Fill))); + } + + // intersperse -----------------------------------------------// + + //! Intersperse - parametric + /*! + Insert generated char between each contiguous elements from the input. + The input sequence is modified in-place. + + \param Input An input sequence + \param G A generator(nullary function object) used to create insertable char + */ + template + inline void intersperse_generate(SequenceT& Input, GeneratorT G) + { + typedef ::boost::function_input_iterator It; + intersperse_fill(Input, boost::make_iterator_range( + detail::just_iterator_adaptor(::boost::make_function_input_iterator(G, 0)), + detail::just_iterator_adaptor(::boost::make_function_input_iterator(G, 1)))); + } + + //! Intersperse - parametric + /*! + Insert generated char between each contiguous elements from the input. + The result is an interspersed copy of the input. + \param Input An input sequence + \param G A generator(nullary function object) used to create insertable char + \return An interspersed copy of the input + */ + template + inline SequenceT intersperse_generate_copy( + const SequenceT& Input, + GeneratorT G) + { + typedef ::boost::function_input_iterator It; + return + intersperse_fill_copy(Input, ::boost::make_iterator_range( + detail::just_iterator_adaptor(::boost::make_function_input_iterator(G, 0)), + detail::just_iterator_adaptor(::boost::make_function_input_iterator(G, 1)))); + } + + //! Intersperse + /*! + Insert char between each contiguous elements from the input. + The input sequence is modified in-place. + + \param Input An input sequence + \param Value A char to be inserted + */ + template + inline void intersperse(SequenceT& Input, const T& Value) + { + intersperse_fill(Input, ::boost::make_iterator_range( + ::boost::addressof(Value), + ::boost::addressof(Value)+1)); + } + + //! Intersperse + /*! + Insert char between each contiguous elements from the input. + The result is an interspersed copy of the input + + \param Input An input sequence + \param Value A char to be inserted + \return An interspersed copy of the input + + \note This function provides the strong exception-safety guarantee + */ + template + inline SequenceT intersperse_copy( + const SequenceT& Input, + const T& Value) + { + return + intersperse_fill_copy(Input, ::boost::make_iterator_range( + ::boost::addressof(Value), + ::boost::addressof(Value)+1)); + } + + } // namespace algorithm + + // pull names to the boost namespace + using algorithm::intersperse_fill; + using algorithm::intersperse_fill_copy; + using algorithm::intersperse_generate; + using algorithm::intersperse_generate_copy; + using algorithm::intersperse; + using algorithm::intersperse_copy; + +} // namespace boost + +#endif // BOOST_STRING_INTERSPERSE_HPP diff --git a/string/test/Jamfile.v2 b/string/test/Jamfile.v2 old mode 100644 new mode 100755 index 7f60df703..a6ff5ad9d --- a/string/test/Jamfile.v2 +++ b/string/test/Jamfile.v2 @@ -21,6 +21,12 @@ test-suite algorithm/string : : trim ] + [ run + intersperse_test.cpp unit_test_framework + : : + : + : intersperse + ] [ run conv_test.cpp unit_test_framework : : diff --git a/string/test/intersperse_test.cpp b/string/test/intersperse_test.cpp new file mode 100755 index 000000000..72d61c353 --- /dev/null +++ b/string/test/intersperse_test.cpp @@ -0,0 +1,103 @@ +// Boost string_algo library intersperse_test.cpp file ---------------------------// + +// Copyright Denis Mikhailov 2022. Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +#include + +// Include unit test framework +#define BOOST_TEST_MAIN +#include + +#include +#include +#include + +using namespace std; +using namespace boost; + +struct CharGenerator { + typedef char result_type; + char counter; + CharGenerator() { counter = '1'; } + char operator() () { + return counter++; + } +}; + +void intersperse_test() +{ + string test = ""; + intersperse(test, ','); + BOOST_CHECK(test == ""); + + test = "a"; + intersperse(test, ','); + BOOST_CHECK(test == "a"); + + test = "ab"; + intersperse(test, ','); + BOOST_CHECK(test == "a,b"); + intersperse(test, ' '); + BOOST_CHECK(test == "a , b"); + intersperse(test, ' '); + BOOST_CHECK(test == "a , b"); + + const string input1 = "abcde"; + const string input2 = ""; + const string input3 = "a"; + const string input4 = "ab"; + + BOOST_CHECK(intersperse_copy(input1, ',') == "a,b,c,d,e"); + BOOST_CHECK(intersperse_copy(input2, ',') == ""); + BOOST_CHECK(intersperse_copy(input3, ',') == "a"); + BOOST_CHECK(intersperse_copy(input4, ',') == "a,b"); +} + +void intersperse_fill_test() +{ + string test = ""; + intersperse_fill(test, ", "); + BOOST_CHECK(test == ""); + + test = "a"; + intersperse_fill(test, ", "); + BOOST_CHECK(test == "a"); + + test = "ab"; + intersperse_fill(test, ", "); + BOOST_CHECK(test == "a, b"); + intersperse_fill(test, " "); + BOOST_CHECK(test == "a , b"); + + const string input1 = "abcde"; + const string input2 = ""; + const string input3 = "a"; + const string input4 = "ab"; + + BOOST_CHECK(intersperse_fill_copy(input1, ", ") == "a, b, c, d, e"); + BOOST_CHECK(intersperse_fill_copy(input2, ", ") == ""); + BOOST_CHECK(intersperse_fill_copy(input3, ", ") == "a"); + BOOST_CHECK(intersperse_fill_copy(input4, ", ") == "a, b"); +} + +void intersperse_generate_test() +{ + string test = "test"; + CharGenerator g1, g2; + BOOST_CHECK(intersperse_generate_copy(test, g1) == "t1e2s3t"); + + intersperse_generate(test, g2); + BOOST_CHECK(test == "t1e2s3t"); +} + +BOOST_AUTO_TEST_CASE( test_main ) +{ + intersperse_test(); + intersperse_fill_test(); + intersperse_generate_test(); +} From 0266a09afac33537542e49267965370d564bdf7e Mon Sep 17 00:00:00 2001 From: Denis Mikhaylov Date: Mon, 14 Nov 2022 15:24:04 +0600 Subject: [PATCH 2/4] fix permissions --- include/boost/algorithm/string/detail/formatter.hpp | 0 include/boost/algorithm/string/detail/intersperse.hpp | 0 include/boost/algorithm/string/formatter.hpp | 0 include/boost/algorithm/string/intersperse.hpp | 4 ++-- string/test/Jamfile.v2 | 0 string/test/intersperse_test.cpp | 0 6 files changed, 2 insertions(+), 2 deletions(-) mode change 100755 => 100644 include/boost/algorithm/string/detail/formatter.hpp mode change 100755 => 100644 include/boost/algorithm/string/detail/intersperse.hpp mode change 100755 => 100644 include/boost/algorithm/string/formatter.hpp mode change 100755 => 100644 include/boost/algorithm/string/intersperse.hpp mode change 100755 => 100644 string/test/Jamfile.v2 mode change 100755 => 100644 string/test/intersperse_test.cpp diff --git a/include/boost/algorithm/string/detail/formatter.hpp b/include/boost/algorithm/string/detail/formatter.hpp old mode 100755 new mode 100644 diff --git a/include/boost/algorithm/string/detail/intersperse.hpp b/include/boost/algorithm/string/detail/intersperse.hpp old mode 100755 new mode 100644 diff --git a/include/boost/algorithm/string/formatter.hpp b/include/boost/algorithm/string/formatter.hpp old mode 100755 new mode 100644 diff --git a/include/boost/algorithm/string/intersperse.hpp b/include/boost/algorithm/string/intersperse.hpp old mode 100755 new mode 100644 index c84cafd42..3f5b7a126 --- a/include/boost/algorithm/string/intersperse.hpp +++ b/include/boost/algorithm/string/intersperse.hpp @@ -57,7 +57,7 @@ namespace boost { template inline void intersperse_fill(SequenceT& Input, const RangeT& Fill) { - typename ::boost::range_size::type counter = 0; + BOOST_STRING_TYPENAME ::boost::range_size::type counter = 0; ::boost::find_format_all( Input, ::boost::token_finder( @@ -81,7 +81,7 @@ namespace boost { const SequenceT& Input, const RangeT& Fill) { - typename ::boost::range_size::type counter = 0; + BOOST_STRING_TYPENAME ::boost::range_size::type counter = 0; return ::boost::find_format_all_copy( Input, diff --git a/string/test/Jamfile.v2 b/string/test/Jamfile.v2 old mode 100755 new mode 100644 diff --git a/string/test/intersperse_test.cpp b/string/test/intersperse_test.cpp old mode 100755 new mode 100644 From b01be9825993d58158cf9df7d296a7ceaa5e30e8 Mon Sep 17 00:00:00 2001 From: Denis Mikhailov Date: Fri, 18 Nov 2022 00:16:01 +0600 Subject: [PATCH 3/4] Update intersperse_test.cpp --- string/test/intersperse_test.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/string/test/intersperse_test.cpp b/string/test/intersperse_test.cpp index 72d61c353..223eaed88 100644 --- a/string/test/intersperse_test.cpp +++ b/string/test/intersperse_test.cpp @@ -87,10 +87,11 @@ void intersperse_fill_test() void intersperse_generate_test() { - string test = "test"; + const string input = "test"; CharGenerator g1, g2; - BOOST_CHECK(intersperse_generate_copy(test, g1) == "t1e2s3t"); + BOOST_CHECK(intersperse_generate_copy(input, g1) == "t1e2s3t"); + string test = "test"; intersperse_generate(test, g2); BOOST_CHECK(test == "t1e2s3t"); } From 2b0b321b588d31d759d4be7c1bd2d0822bd195d6 Mon Sep 17 00:00:00 2001 From: Denis Mikhailov Date: Fri, 18 Nov 2022 00:34:09 +0600 Subject: [PATCH 4/4] Update intersperse_test.cpp --- string/test/intersperse_test.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/string/test/intersperse_test.cpp b/string/test/intersperse_test.cpp index 223eaed88..d56699832 100644 --- a/string/test/intersperse_test.cpp +++ b/string/test/intersperse_test.cpp @@ -87,13 +87,14 @@ void intersperse_fill_test() void intersperse_generate_test() { - const string input = "test"; + const string immutable_input = "test"; CharGenerator g1, g2; - BOOST_CHECK(intersperse_generate_copy(input, g1) == "t1e2s3t"); + BOOST_CHECK(intersperse_generate_copy(immutable_input, g1) + == "t1e2s3t"); - string test = "test"; - intersperse_generate(test, g2); - BOOST_CHECK(test == "t1e2s3t"); + string mutable_input = "test"; + intersperse_generate(mutable_input, g2); + BOOST_CHECK(mutable_input == "t1e2s3t"); } BOOST_AUTO_TEST_CASE( test_main )