From 8d0ecfbcc3608c179276d79f31617f6e1acc2c69 Mon Sep 17 00:00:00 2001 From: Denis Mikhaylov Date: Mon, 17 Oct 2022 20:08:42 +0600 Subject: [PATCH 1/3] Add and new algorithms --- doc/algorithm.qbk | 17 + include/boost/algorithm/cxx11/move_if.hpp | 96 ++++++ test/Jamfile.v2 | 1 + test/move_if_test1.cpp | 374 ++++++++++++++++++++++ 4 files changed, 488 insertions(+) mode change 100644 => 100755 doc/algorithm.qbk create mode 100755 include/boost/algorithm/cxx11/move_if.hpp mode change 100644 => 100755 test/Jamfile.v2 create mode 100755 test/move_if_test1.cpp diff --git a/doc/algorithm.qbk b/doc/algorithm.qbk old mode 100644 new mode 100755 index 02a156236..a98393694 --- a/doc/algorithm.qbk +++ b/doc/algorithm.qbk @@ -150,6 +150,23 @@ Copy all elements that satisfy the element predicate from the start of the input [endsect:Copy] +[section:Move Variations on Move] +[section:variations_on_move] + +[section:move_until move_until ] +[*[^[link header.boost.algorithm.cxx11.move_if_hpp move_until] ] ] +Move all the elements from the start of the input range to the output range until the predicate is satisfied +[endsect:move_until] + +[section:move_while move_while ] +[*[^[link header.boost.algorithm.cxx11.move_if_hpp move_while] ] ] +Move all the elements from the start of the input range to the output range while the predicate is satisfied +[endsect:move_while] + +[endsect:variations_on_move] +[endsect:Move] + + [section:Misc Other Algorithms] [section:misc_inner_algorithms] diff --git a/include/boost/algorithm/cxx11/move_if.hpp b/include/boost/algorithm/cxx11/move_if.hpp new file mode 100755 index 000000000..549f59e4f --- /dev/null +++ b/include/boost/algorithm/cxx11/move_if.hpp @@ -0,0 +1,96 @@ +/* + Copyright (c) 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) +*/ + +/// \file move_if.hpp +/// \brief Move a subset of a sequence to a new sequence +/// \author Denis Mikhailov + +#ifndef BOOST_ALGORITHM_MOVE_IF_HPP +#define BOOST_ALGORITHM_MOVE_IF_HPP + +#include // for std::pair, std::make_pair, std::move + +#include +#include +#include + +namespace boost { namespace algorithm { + +/// \fn move_while ( InputIterator first, InputIterator last, OutputIterator d_first, Predicate p ) +/// \brief Moves all the elements at the start of the range that +/// satisfy the predicate to the another range. +/// \return Updated two iterators for the first and the second range +/// +/// \param first The start of the range to move +/// \param last One past the end of the range to move +/// \param d_first The start of the destination range +/// \param p A predicate for testing the elements of the range +/// \note C++11-compatible compiler required. +template +BOOST_CXX14_CONSTEXPR std::pair +move_while ( InputIterator first, InputIterator last, OutputIterator d_first, Predicate p ) +{ + while (first != last && p(*first)) + *d_first++ = std::move(*first++); + return std::make_pair(first, d_first); +} + +/// \fn move_while ( const Range &r, OutputIterator d_first, Predicate p ) +/// \brief Moves all the elements at the start of the range that +/// satisfy the predicate to the another range. +/// \return Updated two iterators for the first and the second range +/// +/// \param r The range to move +/// \param d_first The start of the destination range +/// \param p A predicate for testing the elements of the range +/// \note C++11-compatible compiler required. +template +BOOST_CXX14_CONSTEXPR std::pair::type, OutputIterator> +move_while ( Range &r, OutputIterator d_first, Predicate p ) +{ + return boost::algorithm::move_while (boost::begin (r), boost::end(r), d_first, p); +} + + +/// \fn move_until ( InputIterator first, InputIterator last, OutputIterator d_first, Predicate p ) +/// \brief Moves all the elements at the start of the range that do not +/// satisfy the predicate to the another range. +/// \return Updated two iterators for the first and the second range +/// +/// \param first The start of the range to move +/// \param last One past the end of the range to move +/// \param d_first The start of the destination range +/// \param p A predicate for testing the elements of the range +/// \note C++11-compatible compiler required. +template +BOOST_CXX14_CONSTEXPR std::pair +move_until ( InputIterator first, InputIterator last, OutputIterator d_first, Predicate p ) +{ + while (first != last && !p(*first)) + *d_first++ = std::move(*first++); + return std::make_pair(first, d_first); +} + +/// \fn move_until ( const Range &r, OutputIterator d_first, Predicate p ) +/// \brief Moves all the elements at the start of the range that do not +/// satisfy the predicate to the another range. +/// \return Updated two iterators for the first and the second range +/// +/// \param r The range to move +/// \param d_first The start of the destination range +/// \param p A predicate for testing the elements of the range +/// \note C++11-compatible compiler required. +template +BOOST_CXX14_CONSTEXPR std::pair::type, OutputIterator> +move_until ( Range &r, OutputIterator d_first, Predicate p ) +{ + return boost::algorithm::move_until (boost::begin (r), boost::end(r), d_first, p); +} + +}} // namespace boost and algorithm + +#endif // BOOST_ALGORITHM_MOVE_IF_HPP diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 old mode 100644 new mode 100755 index aef6bdb38..2292fb266 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -42,6 +42,7 @@ alias unit_test_framework [ run ordered_test.cpp unit_test_framework : : : : ordered_test ] [ run find_if_not_test1.cpp unit_test_framework : : : : find_if_not_test1 ] [ run copy_if_test1.cpp unit_test_framework : : : : copy_if_test1 ] + [ run move_if_test1.cpp unit_test_framework : : : : move_if_test1 ] [ run copy_n_test1.cpp unit_test_framework : : : : copy_n_test1 ] [ run iota_test1.cpp unit_test_framework : : : : iota_test1 ] diff --git a/test/move_if_test1.cpp b/test/move_if_test1.cpp new file mode 100755 index 000000000..0288ea8a8 --- /dev/null +++ b/test/move_if_test1.cpp @@ -0,0 +1,374 @@ +/* + Copyright (c) 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) + + For more information, see http://www.boost.org +*/ + +#include +#include + +#include "iterator_test.hpp" + +#define BOOST_TEST_MAIN +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace ba = boost::algorithm; +// namespace ba = boost; + +struct move_test +{ + int a = -1; + bool moved_from = false; + + move_test() = default; + move_test(int a): a(a) {} + move_test(const move_test&) = delete; + move_test& operator=(const move_test&) = delete; + + move_test(move_test&& other) + { + if (this != &other) + { + *this = std::move(other); + } + } + + move_test& operator=(move_test&& other) + { + a = other.a; + other.moved_from = true; + moved_from = false; + return *this; + } +}; + +bool operator== (const move_test& l, const move_test& r) { return l.a == r.a; } + +struct is_true { template BOOST_CXX14_CONSTEXPR bool operator() (const T&) { return true; } }; +struct is_false { template BOOST_CXX14_CONSTEXPR bool operator() (const T&) { return false; } }; +struct is_even { + BOOST_CXX14_CONSTEXPR bool operator() ( int v ) { return v % 2 == 0; } + BOOST_CXX14_CONSTEXPR bool operator() ( const move_test& v ) { return is_even()(v.a); } +}; +struct is_odd { + BOOST_CXX14_CONSTEXPR bool operator() ( int v ) { return v % 2 == 1; } + BOOST_CXX14_CONSTEXPR bool operator() ( const move_test& v ) { return is_odd()(v.a); } +}; +struct is_zero { + BOOST_CXX14_CONSTEXPR bool operator() ( int v ) { return v == 0; } + BOOST_CXX14_CONSTEXPR bool operator() ( const move_test& v ) { return is_zero()(v.a); } +}; +struct is_moved { + BOOST_CXX14_CONSTEXPR bool operator() ( int v ) { return false; } + BOOST_CXX14_CONSTEXPR bool operator() ( const move_test& v ) { return v.moved_from != false; } +}; + + + + + +template +void test_move_while ( const std::function make_container ) { + + typedef typename Container::value_type value_type; + + const Container e = make_container(); + + +// None of the elements + { + std::vector v; + Container c = make_container(); + ba::move_while ( c.begin (), c.end (), back_inserter ( v ), is_false()); + BOOST_CHECK( ba::none_of(c.begin (), c.end (), is_moved()) ); + BOOST_CHECK ( v.size () == 0 ); + } + + { + std::vector v; + Container c = make_container(); + ba::move_while ( c, back_inserter ( v ), is_false()); + BOOST_CHECK( ba::none_of(c.begin (), c.end (), is_moved()) ); + BOOST_CHECK ( v.size () == 0 ); + } + +// All the elements + { + std::vector v; + Container c = make_container(); + ba::move_while ( c.begin (), c.end (), back_inserter ( v ), is_true()); + BOOST_CHECK( ba::all_of(c.begin (), c.end (), is_moved()) ); + BOOST_CHECK ( v.size () == e.size ()); + BOOST_CHECK ( std::equal ( v.begin (), v.end (), e.begin ())); + } + + { + std::vector v; + Container c = make_container(); + ba::move_while ( c, back_inserter ( v ), is_true()); + BOOST_CHECK( ba::all_of(c.begin (), c.end (), is_moved()) ); + BOOST_CHECK ( v.size () == e.size ()); + BOOST_CHECK ( std::equal ( v.begin (), v.end (), e.begin ())); + } + +// Some of the elements + { + std::vector v; + Container c = make_container(); + auto it = ba::move_while ( c.begin (), c.end (), back_inserter ( v ), is_even() ).first; + const std::size_t mcount = std::count_if(c.begin (), c.end (), is_moved()); + + std::cout << "moved: " << mcount << std::endl; + + BOOST_CHECK ( is_even()(e.front()) ? mcount != 0 : mcount == 0 ); + BOOST_CHECK ( v.size () == (size_t) std::distance ( c.begin (), it )); + BOOST_CHECK ( it == c.end () || !is_even() ( *it )); + BOOST_CHECK ( ba::all_of ( v.begin (), v.end (), is_even() )); + BOOST_CHECK ( std::equal ( v.begin (), v.end (), e.begin ())); + } + + { + std::vector v; + Container c = make_container(); + auto it = ba::move_while ( c, back_inserter ( v ), is_even() ).first; + const std::size_t mcount = std::count_if(c.begin (), c.end (), is_moved()); + + std::cout << "moved: " << mcount << std::endl; + + BOOST_CHECK ( is_even()(e.front()) ? mcount != 0 : mcount == 0 ); + BOOST_CHECK ( v.size () == (size_t) std::distance ( c.begin (), it )); + BOOST_CHECK ( it == c.end () || !is_even() ( *it )); + BOOST_CHECK ( ba::all_of ( v.begin (), v.end (), is_even() )); + BOOST_CHECK ( std::equal ( v.begin (), v.end (), e.begin ())); + } +} + +template +void test_move_until ( const std::function make_container ) { + + typedef typename Container::value_type value_type; + + const Container e = make_container(); + + +// None of the elements + { + std::vector v; + Container c = make_container(); + ba::move_until ( c.begin (), c.end (), back_inserter ( v ), is_true()); + BOOST_CHECK( ba::none_of(c.begin (), c.end (), is_moved()) ); + BOOST_CHECK ( v.size () == 0 ); + } + + { + std::vector v; + Container c = make_container(); + ba::move_until ( c, back_inserter ( v ), is_true()); + BOOST_CHECK( ba::none_of(c.begin (), c.end (), is_moved()) ); + BOOST_CHECK ( v.size () == 0 ); + } + +// All the elements + { + std::vector v; + Container c = make_container(); + ba::move_until ( c.begin (), c.end (), back_inserter ( v ), is_false()); + BOOST_CHECK( ba::all_of(c.begin (), c.end (), is_moved()) ); + BOOST_CHECK ( v.size () == e.size ()); + BOOST_CHECK ( std::equal ( v.begin (), v.end (), e.begin ())); + } + + { + std::vector v; + Container c = make_container(); + ba::move_until ( c, back_inserter ( v ), is_false()); + BOOST_CHECK( ba::all_of(c.begin (), c.end (), is_moved()) ); + BOOST_CHECK ( v.size () == e.size ()); + BOOST_CHECK ( std::equal ( v.begin (), v.end (), e.begin ())); + } + +// Some of the elements + { + std::vector v; + Container c = make_container(); + auto it = ba::move_until ( c.begin (), c.end (), back_inserter ( v ), is_even() ).first; + const std::size_t mcount = std::count_if(c.begin (), c.end (), is_moved()); + + std::cout << "moved: " << mcount << std::endl; + + BOOST_CHECK ( mcount != 0 ); + BOOST_CHECK ( v.size () == (size_t) std::distance ( c.begin (), it )); + BOOST_CHECK ( it == c.end () || is_even() ( *it )); + BOOST_CHECK ( ba::none_of ( v.begin (), v.end (), is_even() )); + BOOST_CHECK ( std::equal ( v.begin (), v.end (), e.begin ())); + } + + { + std::vector v; + Container c = make_container(); + auto it = ba::move_until ( c, back_inserter ( v ), is_even() ).first; + const std::size_t mcount = std::count_if(c.begin (), c.end (), is_moved()); + + std::cout << "moved: " << mcount << std::endl; + + BOOST_CHECK ( mcount != 0 ); + BOOST_CHECK ( v.size () == (size_t) std::distance ( c.begin (), it )); + BOOST_CHECK ( it == c.end () || is_even() ( *it )); + BOOST_CHECK ( ba::none_of ( v.begin (), v.end (), is_even() )); + BOOST_CHECK ( std::equal ( v.begin (), v.end (), e.begin ())); + } +} + +void test_move_while_valid_it() { + std::vector c = {2,2,4,3,3}; + + +// None of the elements + { + std::vector v; + auto it = ba::move_while ( c.begin (), c.end (), back_inserter ( v ), is_false()).first; + BOOST_CHECK( it == c.begin() ); + } + +// All the elements + { + std::vector v; + auto it = ba::move_while ( c.begin (), c.end (), back_inserter ( v ), is_true()).first; + BOOST_CHECK( it == c.end() ); + } + +// Some of the elements + { + std::vector v; + auto it = ba::move_while ( c.begin (), c.end (), back_inserter ( v ), is_even() ).first; + BOOST_CHECK( it == c.begin() + 3 ); + } +} + +void test_move_until_valid_it() { + typename std::vector::const_iterator it; + + std::vector c = {1,1,2,2,3}; + + +// None of the elements + { + std::vector v; + auto it = ba::move_until ( c.begin (), c.end (), back_inserter ( v ), is_true()).first; + BOOST_CHECK( it == c.begin() ); + } + +// All the elements + { + std::vector v; + auto it = ba::move_until ( c.begin (), c.end (), back_inserter ( v ), is_false()).first; + BOOST_CHECK( it == c.end() ); + } + +// Some of the elements + { + std::vector v; + auto it = ba::move_until ( c.begin (), c.end (), back_inserter ( v ), is_even() ).first; + BOOST_CHECK( it == c.begin() + 2 ); + } +} + +BOOST_CXX14_CONSTEXPR inline bool constexpr_test_move_while() { + const int sz = 64; + int in_data[sz] = {0}; + bool res = true; + + const int* from = in_data; + const int* to = in_data + sz; + + int out_data[sz] = {0}; + int* out = out_data; + + int etalon_data[sz] = {0}; + int* e = etalon_data; + + out = ba::move_while ( from, to, out, is_false() ).second; // move none + res = (res && out == out_data && ba::all_of(out, out + sz, is_zero())); + + out = ba::move_while ( from, to, out, is_true() ).second; // move all + res = (res && out == out_data + sz + && ba::equal( input_iterator(out_data), input_iterator(out_data + sz), + input_iterator(e), input_iterator(e + sz))); + + return res; + } + +BOOST_CXX14_CONSTEXPR inline bool constexpr_test_move_until() { + const int sz = 64; + int in_data[sz] = {0}; + bool res = true; + + const int* from = in_data; + const int* to = in_data + sz; + + int out_data[sz] = {0}; + int* out = out_data; + + int etalon_data[sz] = {0}; + int* e = etalon_data; + + out = ba::move_until ( from, to, out, is_true() ).second; // move none + res = (res && out == out_data && ba::all_of(out, out + sz, is_zero())); + + out = ba::move_until ( from, to, out, is_false() ).second; // move all + res = (res && out == out_data + sz + && ba::equal( input_iterator(out_data), input_iterator(out_data + sz), + input_iterator(e), input_iterator(e + sz))); + + return res; + } + +std::vector make_vector_container() { + std::vector v; + for ( int i = 5; i < 15; ++i ) + v.push_back ( move_test(i) ); + return v; +} + +std::list make_list_container() { + std::list l; + for ( int i = 25; i > 15; --i ) + l.push_back ( move_test(i) ); + return l; +} + +void test_sequence1 () { + test_move_while> ( make_vector_container ); + test_move_until> ( make_vector_container ); + + BOOST_CXX14_CONSTEXPR bool constexpr_res_while = constexpr_test_move_while(); + BOOST_CHECK ( constexpr_res_while ); + BOOST_CXX14_CONSTEXPR bool constexpr_res_until = constexpr_test_move_until(); + BOOST_CHECK ( constexpr_res_until ); + + test_move_while> ( make_list_container ); + test_move_until> ( make_list_container ); + + test_move_while_valid_it(); + test_move_until_valid_it(); + } + + +BOOST_AUTO_TEST_CASE( test_main ) +{ + test_sequence1 (); +} From d7a3a4dd6ea87af95a6cbafdfb397a2a29ad6a79 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 25 Oct 2022 01:12:51 +0400 Subject: [PATCH 2/3] Fix permissions --- doc/algorithm.qbk | 0 include/boost/algorithm/cxx11/move_if.hpp | 0 test/Jamfile.v2 | 0 test/move_if_test1.cpp | 0 4 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 doc/algorithm.qbk mode change 100755 => 100644 include/boost/algorithm/cxx11/move_if.hpp mode change 100755 => 100644 test/Jamfile.v2 mode change 100755 => 100644 test/move_if_test1.cpp diff --git a/doc/algorithm.qbk b/doc/algorithm.qbk old mode 100755 new mode 100644 diff --git a/include/boost/algorithm/cxx11/move_if.hpp b/include/boost/algorithm/cxx11/move_if.hpp old mode 100755 new mode 100644 diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 old mode 100755 new mode 100644 diff --git a/test/move_if_test1.cpp b/test/move_if_test1.cpp old mode 100755 new mode 100644 From e8b35dfad37f5d6ead64dd6da5be2a4e7c136bc5 Mon Sep 17 00:00:00 2001 From: Denis Mikhailov Date: Tue, 25 Oct 2022 01:56:41 +0400 Subject: [PATCH 3/3] Update move_if_test1.cpp --- test/move_if_test1.cpp | 48 +++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/test/move_if_test1.cpp b/test/move_if_test1.cpp index 0288ea8a8..82b25a925 100644 --- a/test/move_if_test1.cpp +++ b/test/move_if_test1.cpp @@ -1,9 +1,7 @@ /* Copyright (c) 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) - For more information, see http://www.boost.org */ @@ -135,7 +133,8 @@ void test_move_while ( const std::function make_container ) { std::cout << "moved: " << mcount << std::endl; BOOST_CHECK ( is_even()(e.front()) ? mcount != 0 : mcount == 0 ); - BOOST_CHECK ( v.size () == (size_t) std::distance ( c.begin (), it )); + BOOST_CHECK ( v.size () == (size_t) std::distance ( c.begin (), it ) && + v.size () == mcount ); BOOST_CHECK ( it == c.end () || !is_even() ( *it )); BOOST_CHECK ( ba::all_of ( v.begin (), v.end (), is_even() )); BOOST_CHECK ( std::equal ( v.begin (), v.end (), e.begin ())); @@ -150,7 +149,8 @@ void test_move_while ( const std::function make_container ) { std::cout << "moved: " << mcount << std::endl; BOOST_CHECK ( is_even()(e.front()) ? mcount != 0 : mcount == 0 ); - BOOST_CHECK ( v.size () == (size_t) std::distance ( c.begin (), it )); + BOOST_CHECK ( v.size () == (size_t) std::distance ( c.begin (), it ) && + v.size () == mcount ); BOOST_CHECK ( it == c.end () || !is_even() ( *it )); BOOST_CHECK ( ba::all_of ( v.begin (), v.end (), is_even() )); BOOST_CHECK ( std::equal ( v.begin (), v.end (), e.begin ())); @@ -210,8 +210,9 @@ void test_move_until ( const std::function make_container ) { std::cout << "moved: " << mcount << std::endl; - BOOST_CHECK ( mcount != 0 ); - BOOST_CHECK ( v.size () == (size_t) std::distance ( c.begin (), it )); + BOOST_CHECK ( is_even()(e.front()) ? mcount == 0 : mcount != 0 ); + BOOST_CHECK ( v.size () == (size_t) std::distance ( c.begin (), it ) && + v.size () == mcount ); BOOST_CHECK ( it == c.end () || is_even() ( *it )); BOOST_CHECK ( ba::none_of ( v.begin (), v.end (), is_even() )); BOOST_CHECK ( std::equal ( v.begin (), v.end (), e.begin ())); @@ -225,8 +226,9 @@ void test_move_until ( const std::function make_container ) { std::cout << "moved: " << mcount << std::endl; - BOOST_CHECK ( mcount != 0 ); - BOOST_CHECK ( v.size () == (size_t) std::distance ( c.begin (), it )); + BOOST_CHECK ( is_even()(e.front()) ? mcount == 0 : mcount != 0 ); + BOOST_CHECK ( v.size () == (size_t) std::distance ( c.begin (), it ) && + v.size () == mcount ); BOOST_CHECK ( it == c.end () || is_even() ( *it )); BOOST_CHECK ( ba::none_of ( v.begin (), v.end (), is_even() )); BOOST_CHECK ( std::equal ( v.begin (), v.end (), e.begin ())); @@ -337,35 +339,47 @@ BOOST_CXX14_CONSTEXPR inline bool constexpr_test_move_until() { return res; } -std::vector make_vector_container() { +std::vector make_vector_container(bool is_front_even) { std::vector v; - for ( int i = 5; i < 15; ++i ) + const int front = is_front_even ? 6 : 5; + const int back = is_front_even ? 15 : 14; + for ( int i = front; i <= back; ++i ) v.push_back ( move_test(i) ); return v; } -std::list make_list_container() { +std::list make_list_container(bool is_front_even) { std::list l; - for ( int i = 25; i > 15; --i ) + const int rfront = is_front_even ? 26 : 25; + const int rback = is_front_even ? 17 : 16; + for ( int i = rfront; i >= rback; --i ) l.push_back ( move_test(i) ); return l; } void test_sequence1 () { - test_move_while> ( make_vector_container ); - test_move_until> ( make_vector_container ); + std::cout << "testing with vector.." << std::endl; + for (const bool is_front_even : {true, false}) + { + test_move_while> ( std::bind(&make_vector_container, is_front_even) ); + test_move_until> ( std::bind(&make_vector_container, is_front_even) ); + } BOOST_CXX14_CONSTEXPR bool constexpr_res_while = constexpr_test_move_while(); BOOST_CHECK ( constexpr_res_while ); BOOST_CXX14_CONSTEXPR bool constexpr_res_until = constexpr_test_move_until(); BOOST_CHECK ( constexpr_res_until ); - test_move_while> ( make_list_container ); - test_move_until> ( make_list_container ); + std::cout << "testing with list.." << std::endl; + for (const bool is_front_even : {true, false}) + { + test_move_while> ( std::bind(&make_list_container, is_front_even) ); + test_move_until> ( std::bind(&make_list_container, is_front_even) ); + } test_move_while_valid_it(); test_move_until_valid_it(); - } +} BOOST_AUTO_TEST_CASE( test_main )