summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/fusion/example/cookbook
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 18:24:20 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 18:24:20 +0000
commit483eb2f56657e8e7f419ab1a4fab8dce9ade8609 (patch)
treee5d88d25d870d5dedacb6bbdbe2a966086a0a5cf /src/boost/libs/fusion/example/cookbook
parentInitial commit. (diff)
downloadceph-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.cpp268
-rw-r--r--src/boost/libs/fusion/example/cookbook/fill_em_up.cpp105
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;
+}
+