diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
commit | 483eb2f56657e8e7f419ab1a4fab8dce9ade8609 (patch) | |
tree | e5d88d25d870d5dedacb6bbdbe2a966086a0a5cf /src/boost/libs/fusion/example/cookbook | |
parent | Initial commit. (diff) | |
download | ceph-483eb2f56657e8e7f419ab1a4fab8dce9ade8609.tar.xz ceph-483eb2f56657e8e7f419ab1a4fab8dce9ade8609.zip |
Adding upstream version 14.2.21.upstream/14.2.21upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/boost/libs/fusion/example/cookbook')
-rw-r--r-- | src/boost/libs/fusion/example/cookbook/do_the_bind.cpp | 268 | ||||
-rw-r--r-- | src/boost/libs/fusion/example/cookbook/fill_em_up.cpp | 105 |
2 files changed, 373 insertions, 0 deletions
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 <boost/fusion/functional/invocation/invoke.hpp> +#include <boost/fusion/functional/adapter/unfused.hpp> +#include <boost/fusion/support/deduce_sequence.hpp> + +#include <boost/fusion/sequence/intrinsic/at.hpp> +#include <boost/fusion/sequence/intrinsic/front.hpp> +#include <boost/fusion/sequence/intrinsic/size.hpp> +#include <boost/fusion/algorithm/transformation/transform.hpp> +#include <boost/fusion/algorithm/transformation/pop_front.hpp> +#include <boost/fusion/algorithm/iteration/fold.hpp> +#include <boost/fusion/view/filter_view.hpp> + +#include <boost/functional/forward_adapter.hpp> +#include <boost/functional/lightweight_forward_adapter.hpp> + +#include <boost/type_traits/remove_reference.hpp> + +#include <boost/mpl/eval_if.hpp> +#include <boost/mpl/identity.hpp> +#include <boost/mpl/int.hpp> +#include <boost/mpl/max.hpp> +#include <boost/mpl/next.hpp> + +#include <boost/ref.hpp> +#include <iostream> +#include <typeinfo> + +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 <int I> struct placeholder : mpl::int_<I> { }; + + // A traits class to find out whether T is a placeholeder + template <typename T> struct is_placeholder : mpl::false_ { }; + template <int I> struct is_placeholder< placeholder<I> > : mpl::true_ { }; + template <int I> struct is_placeholder< placeholder<I> & > : mpl::true_ { }; + template <int I> struct is_placeholder< placeholder<I> const > : mpl::true_ { }; + template <int I> struct is_placeholder< placeholder<I> 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<class FinalArgs> 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 <int Index> + inline typename result_of::at_c<FinalArgs const, Index>::type + operator()(placeholder<Index> const &) const + { + return fusion::at_c<Index>(this->ref_final_args); + } + // ...just return the bound argument, otherwise. + template <typename T> inline T & operator()(T & bound) const + { + return bound; + } + + template <typename Signature> + struct result; + + template <class Self, typename T> + struct result< Self (T) > + : mpl::eval_if< is_placeholder<T>, + result_of::at<FinalArgs,typename boost::remove_reference<T>::type>, + mpl::identity<T> + > + { }; + }; + + // Fused implementation of the bound function, the function object + // returned by bind + template <class BindArgs> class fused_bound_function + { + // Transform arguments to be held by value + typedef typename traits::deduce_sequence<BindArgs>::type bound_args; + + bound_args fsq_bind_args; + public: + + fused_bound_function(BindArgs const & bind_args) + : fsq_bind_args(bind_args) + { } + + template <typename Signature> + struct result; + + template <class FinalArgs> + struct result_impl + : result_of::invoke< typename result_of::front<bound_args>::type, + typename result_of::transform< + typename result_of::pop_front<bound_args>::type, + argument_transform<FinalArgs> const + >::type + > + { }; + + template <class Self, class FinalArgs> + struct result< Self (FinalArgs) > + : result_impl< typename boost::remove_reference<FinalArgs>::type > + { }; + + template <class FinalArgs> + inline typename result_impl<FinalArgs>::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<FinalArgs>(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 <typename Sig> struct result; + template <class S, class A, class B> struct result< S(A &,B &) > + : mpl::max<A,B> { }; + }; + struct filter_pred + { + template <class X> struct apply : is_placeholder<X> { }; + }; + + template <typename Seq> + struct apply + : mpl::next< typename result_of::fold< + fusion::filter_view<Seq,filter_pred>, mpl::int_<-1>, fold_op + >::type>::type + { }; + }; + + // Fused implementation of the 'bind' function + struct fused_binder + { + template <class Signature> + struct result; + + template <class BindArgs, + int Placeholders = n_placeholders::apply<BindArgs>::value> + struct result_impl + { + typedef boost::forward_adapter<fusion::unfused< + fused_bound_function<BindArgs>,!Placeholders>,Placeholders> type; + }; + + template <class Self, class BindArgs> + struct result< Self (BindArgs) > + : result_impl< typename boost::remove_reference<BindArgs>::type > + { }; + + template <class BindArgs> + inline typename result_impl< BindArgs >::type + operator()(BindArgs & bind_args) const + { + return typename result< void(BindArgs) >::type( + fusion::unfused< fused_bound_function<BindArgs>, + ! n_placeholders::apply<BindArgs>::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<fused_binder> > 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 <typename A> + 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 <typename A, typename B> + 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<double, std::string> + R: vector<double, std::string, int, short> + + 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 <boost/fusion/container/list.hpp> +#include <boost/fusion/container/vector.hpp> + +// For doing I/O +#include <boost/fusion/sequence/io.hpp> + +// We'll use join and advance for processing +#include <boost/fusion/algorithm/transformation/join.hpp> +#include <boost/fusion/iterator/advance.hpp> + +// The fusion <--> MPL link header +#include <boost/fusion/mpl.hpp> + +// Same-o same-o +#include <iostream> +#include <string> + +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<double, std::string> I; + I i(123.456, "Hello"); + + // Here's your output sequence. For now, it is just a typedef + typedef vector<double, std::string, int, short> 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<R>::value; + static int const i_size = result_of::size<I>::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<R>::type r_begin; + typedef result_of::end<R>::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<r_begin, i_size>::type r_advance; + + // Now, make MPL iterators from r_advance and r_end. Ditto, just types. + typedef mpl::fusion_iterator<r_advance> mpl_r_advance; + typedef mpl::fusion_iterator<r_end> 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<mpl_r_advance, mpl_r_end> 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; +} + |