From 483eb2f56657e8e7f419ab1a4fab8dce9ade8609 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 20:24:20 +0200 Subject: Adding upstream version 14.2.21. Signed-off-by: Daniel Baumann --- .../libs/fusion/example/cookbook/do_the_bind.cpp | 268 +++++++++++++++++++++ .../libs/fusion/example/cookbook/fill_em_up.cpp | 105 ++++++++ 2 files changed, 373 insertions(+) create mode 100644 src/boost/libs/fusion/example/cookbook/do_the_bind.cpp create mode 100644 src/boost/libs/fusion/example/cookbook/fill_em_up.cpp (limited to 'src/boost/libs/fusion/example/cookbook') diff --git a/src/boost/libs/fusion/example/cookbook/do_the_bind.cpp b/src/boost/libs/fusion/example/cookbook/do_the_bind.cpp new file mode 100644 index 00000000..ac5baee4 --- /dev/null +++ b/src/boost/libs/fusion/example/cookbook/do_the_bind.cpp @@ -0,0 +1,268 @@ +/*============================================================================= + Copyright (c) 2006-2007 Tobias Schwinger + + Use modification and distribution are 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). + + Problem: + + How to "do the Bind?" + + This recipe shows how to implement a function binder, similar to + Boost.Bind based on the Functional module of Fusion. + + It works as follows: + + 'bind' is a global, stateless function object. It is implemented in + fused form (fused_binder) and transformed into a variadic function + object. When called, 'bind' returns another function object, which + holds the arguments of the call to 'bind'. It is, again, implemented + in fused form (fused_bound_function) and transformed into unfused + form. +==============================================================================*/ + + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace impl +{ + namespace fusion = boost::fusion; + namespace traits = boost::fusion::traits; + namespace result_of = boost::fusion::result_of; + namespace mpl = boost::mpl; + using mpl::placeholders::_; + + // Placeholders (we inherit from mpl::int_, so we can use placeholders + // as indices for fusion::at, later) + template struct placeholder : mpl::int_ { }; + + // A traits class to find out whether T is a placeholeder + template struct is_placeholder : mpl::false_ { }; + template struct is_placeholder< placeholder > : mpl::true_ { }; + template struct is_placeholder< placeholder & > : mpl::true_ { }; + template struct is_placeholder< placeholder const > : mpl::true_ { }; + template struct is_placeholder< placeholder const & > : mpl::true_ { }; + + // This class template provides a Polymorphic Function Object to be used + // with fusion::transform. It is applied to the sequence of arguments that + // describes the binding and holds a reference to the sequence of arguments + // from the final call. + template struct argument_transform + { + FinalArgs const & ref_final_args; + public: + + explicit argument_transform(FinalArgs const & final_args) + : ref_final_args(final_args) + { } + + // A placeholder? Replace it with an argument from the final call... + template + inline typename result_of::at_c::type + operator()(placeholder const &) const + { + return fusion::at_c(this->ref_final_args); + } + // ...just return the bound argument, otherwise. + template inline T & operator()(T & bound) const + { + return bound; + } + + template + struct result; + + template + struct result< Self (T) > + : mpl::eval_if< is_placeholder, + result_of::at::type>, + mpl::identity + > + { }; + }; + + // Fused implementation of the bound function, the function object + // returned by bind + template class fused_bound_function + { + // Transform arguments to be held by value + typedef typename traits::deduce_sequence::type bound_args; + + bound_args fsq_bind_args; + public: + + fused_bound_function(BindArgs const & bind_args) + : fsq_bind_args(bind_args) + { } + + template + struct result; + + template + struct result_impl + : result_of::invoke< typename result_of::front::type, + typename result_of::transform< + typename result_of::pop_front::type, + argument_transform const + >::type + > + { }; + + template + struct result< Self (FinalArgs) > + : result_impl< typename boost::remove_reference::type > + { }; + + template + inline typename result_impl::type + operator()(FinalArgs const & final_args) const + { + return fusion::invoke( fusion::front(this->fsq_bind_args), + fusion::transform( fusion::pop_front(this->fsq_bind_args), + argument_transform(final_args) ) ); + } + // Could add a non-const variant - omitted for readability + + }; + + // Find the number of placeholders in use + struct n_placeholders + { + struct fold_op + { + template struct result; + template struct result< S(A &,B &) > + : mpl::max { }; + }; + struct filter_pred + { + template struct apply : is_placeholder { }; + }; + + template + struct apply + : mpl::next< typename result_of::fold< + fusion::filter_view, mpl::int_<-1>, fold_op + >::type>::type + { }; + }; + + // Fused implementation of the 'bind' function + struct fused_binder + { + template + struct result; + + template ::value> + struct result_impl + { + typedef boost::forward_adapter,!Placeholders>,Placeholders> type; + }; + + template + struct result< Self (BindArgs) > + : result_impl< typename boost::remove_reference::type > + { }; + + template + inline typename result_impl< BindArgs >::type + operator()(BindArgs & bind_args) const + { + return typename result< void(BindArgs) >::type( + fusion::unfused< fused_bound_function, + ! n_placeholders::apply::value >(bind_args) ); + } + }; + + // The binder's unfused type. We use lightweght_forward_adapter to make + // that thing more similar to Boost.Bind. Because of that we have to use + // Boost.Ref (below in the sample code) + typedef boost::lightweight_forward_adapter< fusion::unfused > binder; +} + +// Placeholder globals +impl::placeholder<0> const _1_ = impl::placeholder<0>(); +impl::placeholder<1> const _2_ = impl::placeholder<1>(); +impl::placeholder<2> const _3_ = impl::placeholder<2>(); +impl::placeholder<3> const _4_ = impl::placeholder<3>(); + +// The bind function is a global, too +impl::binder const bind = impl::binder(); + + +// OK, let's try it out: + +struct func +{ + typedef int result_type; + + inline int operator()() const + { + std::cout << "operator()" << std::endl; + return 0; + } + + template + inline int operator()(A const & a) const + { + std::cout << "operator()(A const & a)" << std::endl; + std::cout << " a = " << a << " A = " << typeid(A).name() << std::endl; + return 1; + } + + template + inline int operator()(A const & a, B & b) const + { + std::cout << "operator()(A const & a, B & b)" << std::endl; + std::cout << " a = " << a << " A = " << typeid(A).name() << std::endl; + std::cout << " b = " << b << " B = " << typeid(B).name() << std::endl; + return 2; + } +}; + +int main() +{ + func f; + int value = 42; + using boost::ref; + + int errors = 0; + + errors += !( bind(f)() == 0); + errors += !( bind(f,"Hi")() == 1); + errors += !( bind(f,_1_)("there.") == 1); + errors += !( bind(f,"The answer is",_1_)(12) == 2); + errors += !( bind(f,_1_,ref(value))("Really?") == 2); + errors += !( bind(f,_1_,_2_)("Dunno. If there is an answer, it's",value) == 2); + + return !! errors; +} + diff --git a/src/boost/libs/fusion/example/cookbook/fill_em_up.cpp b/src/boost/libs/fusion/example/cookbook/fill_em_up.cpp new file mode 100644 index 00000000..9b37aec8 --- /dev/null +++ b/src/boost/libs/fusion/example/cookbook/fill_em_up.cpp @@ -0,0 +1,105 @@ +/*============================================================================= + Copyright (c) 2011 Joel de Guzman + + 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) + + Problem: + + So... you have an input sequence I and a target vector R. You want to + copy I into R. But, I may have less elements than the result vector R. + For those elements not in R, you want them to be default constructed. + + Here's a case: + + I: list + R: vector + + You want the elements at the right of I not in R (i.e. int, short) + default constructed. Those at the left, found in both I and R, you want + to simply copy from I. + + Of course you want to be able to handle any type of I and R. + +==============================================================================*/ + +// We'll use these containers as examples +#include +#include + +// For doing I/O +#include + +// We'll use join and advance for processing +#include +#include + +// The fusion <--> MPL link header +#include + +// Same-o same-o +#include +#include + +int +main() +{ + using namespace boost::fusion; + using namespace boost; + + // Let's specify our own tuple delimeters for nicer printing + std::cout << tuple_open('['); + std::cout << tuple_close(']'); + std::cout << tuple_delimiter(", "); + + // Here's your input sequence + typedef list I; + I i(123.456, "Hello"); + + // Here's your output sequence. For now, it is just a typedef + typedef vector R; + + // Let's get the sizes of the sequences. Yeah, you already know that. + // But with templates, you are simply given, say, R and I, corresponding + // to the types of the sequences. You'll have to deal with it generically. + static int const r_size = result_of::size::value; + static int const i_size = result_of::size::value; + + // Make sure that I has no more elements than R + // Be nice and catch obvious errors earlier rather than later. + // Without this assert, the mistake will still be caught by Fusion, + // but the error will point to somewhere really obscure. + BOOST_STATIC_ASSERT(i_size <= r_size); + + // Let's get the begin and end iterator types of the output sequence + // There's no actual vector yet. We just want to know the types. + typedef result_of::begin::type r_begin; + typedef result_of::end::type r_end; + + // Let's skip i_size elements from r_begin. Again, we just want to know the type. + typedef result_of::advance_c::type r_advance; + + // Now, make MPL iterators from r_advance and r_end. Ditto, just types. + typedef mpl::fusion_iterator mpl_r_advance; + typedef mpl::fusion_iterator mpl_r_end; + + // Make an mpl::iterator_range from the MPL iterators we just created + // You guessed it! --just a type. + typedef mpl::iterator_range tail; + + // Use join to join the input sequence and our mpl::iterator_range + // Our mpl::iterator_range is 'tail'. Here, we'll actually instantiate + // 'tail'. Notice that this is a flyweight object, typically just 1 byte + // in size -- it doesn't really hold any data, but is a fully conforming + // sequence nonetheless. When asked to return its elements, 'tail' returns + // each element default constructed. Breeds like a rabbit! + + // Construct R from the joined sequences: + R r(join(i, tail())); + + // Then finally, print the result: + std::cout << r << std::endl; + + return 0; +} + -- cgit v1.2.3