/*============================================================================= Copyright (c) 2001-2011 Joel de Guzman Copyright (c) 2011 Nathan Ridge Copyright (c) 2006 Dan Marsden 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) ==============================================================================*/ /*============================================================================= An implementation of a std::pair like triple<T0, T1, T2> We use fusion::sequence_facade and fusion::iterator_facade to make our triple a fully conforming Boost.Fusion random traversal sequence. ==============================================================================*/ #include <boost/detail/lightweight_test.hpp> #include <boost/fusion/sequence/sequence_facade.hpp> #include <boost/fusion/iterator/iterator_facade.hpp> #include <boost/fusion/sequence/intrinsic.hpp> #include <boost/fusion/iterator.hpp> #include <boost/fusion/support/category_of.hpp> #include <boost/fusion/algorithm/iteration/fold.hpp> #include <boost/mpl/int.hpp> #include <boost/mpl/identity.hpp> #include <boost/mpl/minus.hpp> #include <boost/mpl/assert.hpp> #include <boost/type_traits/is_const.hpp> #include <boost/type_traits/is_same.hpp> #include <string> namespace mpl = boost::mpl; namespace fusion = boost::fusion; namespace demo { template<typename Seq, int N> struct triple_iterator : fusion::iterator_facade<triple_iterator<Seq, N>, fusion::random_access_traversal_tag> { typedef mpl::int_<N> index; typedef Seq sequence_type; triple_iterator(Seq& seq) : seq_(seq) {} Seq& seq_; template<typename T> struct value_of; template<typename Sq> struct value_of<triple_iterator<Sq, 0> > : mpl::identity<typename Sq::t0_type> {}; template<typename Sq> struct value_of<triple_iterator<Sq, 1> > : mpl::identity<typename Sq::t1_type> {}; template<typename Sq> struct value_of<triple_iterator<Sq, 2> > : mpl::identity<typename Sq::t2_type> {}; template<typename T> struct deref; template <typename Sq> struct deref<triple_iterator<Sq, 0> > { typedef typename Sq::t0_type& type; static type call(triple_iterator<Sq, 0> const& iter) { return iter.seq_.t0; } }; template <typename Sq> struct deref<triple_iterator<Sq, 0> const> { typedef typename Sq::t0_type const& type; static type call(triple_iterator<Sq, 0> const& iter) { return iter.seq_.t0; } }; template <typename Sq> struct deref<triple_iterator<Sq, 1> > { typedef typename Sq::t1_type& type; static type call(triple_iterator<Sq, 1> const& iter) { return iter.seq_.t1; } }; template <typename Sq> struct deref<triple_iterator<Sq, 1> const> { typedef typename Sq::t1_type const& type; static type call(triple_iterator<Sq, 1> const& iter) { return iter.seq_.t1; } }; template <typename Sq> struct deref<triple_iterator<Sq, 2> > { typedef typename Sq::t2_type& type; static type call(triple_iterator<Sq, 2> const& iter) { return iter.seq_.t2; } }; template <typename Sq> struct deref<triple_iterator<Sq, 2> const> { typedef typename Sq::t2_type const& type; static type call(triple_iterator<Sq, 2> const& iter) { return iter.seq_.t2; } }; template<typename It> struct next { typedef triple_iterator< typename It::sequence_type, It::index::value + 1> type; static type call(It const& it) { return type(it.seq_); } }; template<typename It> struct prior { typedef triple_iterator< typename It::sequence_type, It::index::value - 1> type; static type call(It const& it) { return type(it.seq_); } }; template<typename It1, typename It2> struct distance { typedef typename mpl::minus< typename It2::index, typename It1::index>::type type; static type call(It1 const& it1, It2 const& it2) { return type(); } }; template<typename It, typename M> struct advance { typedef triple_iterator< typename It::sequence_type, It::index::value + M::value> type; static type call(It const& it) { return type(it.seq_); } }; }; template<typename T0, typename T1, typename T2> struct triple : fusion::sequence_facade<triple<T0, T1, T2>, fusion::random_access_traversal_tag> { triple(T0 const& t0, T1 const& t1, T2 const& t2) : t0(t0), t1(t1), t2(t2) {} template<typename Sq> struct begin { typedef demo::triple_iterator<Sq, 0> type; static type call(Sq& sq) { return type(sq); } }; template<typename Sq> struct end { typedef demo::triple_iterator<Sq, 3> type; static type call(Sq& sq) { return type(sq); } }; template<typename Sq> struct size : mpl::int_<3> {}; template<typename Sq, typename N> struct value_at : value_at<Sq, mpl::int_<N::value> > {}; template<typename Sq> struct value_at<Sq, mpl::int_<0> > { typedef typename Sq::t0_type type; }; template<typename Sq> struct value_at<Sq, mpl::int_<1> > { typedef typename Sq::t1_type type; }; template<typename Sq> struct value_at<Sq, mpl::int_<2> > { typedef typename Sq::t2_type type; }; template<typename Sq, typename N> struct at : at<Sq, mpl::int_<N::value> > {}; template<typename Sq> struct at<Sq, mpl::int_<0> > { typedef typename mpl::if_< boost::is_const<Sq> , typename Sq::t0_type const& , typename Sq::t0_type& >::type type; static type call(Sq& sq) { return sq.t0; } }; template<typename Sq> struct at<Sq, mpl::int_<1> > { typedef typename mpl::if_< boost::is_const<Sq> , typename Sq::t1_type const& , typename Sq::t1_type& >::type type; static type call(Sq& sq) { return sq.t1; } }; template<typename Sq> struct at<Sq, mpl::int_<2> > { typedef typename mpl::if_< boost::is_const<Sq> , typename Sq::t2_type const& , typename Sq::t2_type& >::type type; static type call(Sq& sq) { return sq.t2; } }; typedef T0 t0_type; typedef T1 t1_type; typedef T2 t2_type; T0 t0; T1 t1; T2 t2; }; } struct modifying_fold_functor { template <typename T> struct result { typedef bool type; }; template <typename T> bool operator()(bool b, T&) { return b; } }; struct nonmodifying_fold_functor { template <typename T> struct result { typedef bool type; }; template <typename T> bool operator()(bool b, const T&) { return b; } }; int main() { typedef demo::triple<int, char, std::string> my_triple; my_triple t(101, 'a', "hello"); BOOST_TEST(*fusion::begin(t) == 101); BOOST_TEST(*fusion::next(fusion::begin(t)) == 'a'); BOOST_TEST(*fusion::prior(fusion::end(t)) == "hello"); BOOST_TEST(fusion::distance(fusion::begin(t), fusion::end(t)) == 3); BOOST_TEST(fusion::size(t) == 3); BOOST_MPL_ASSERT((boost::is_same< int, fusion::result_of::value_at_c<my_triple, 0>::type>)); BOOST_MPL_ASSERT((boost::is_same< char, fusion::result_of::value_at_c<my_triple, 1>::type>)); BOOST_MPL_ASSERT((boost::is_same< std::string, fusion::result_of::value_at_c<my_triple, 2>::type>)); BOOST_TEST(fusion::at_c<0>(t) == 101); BOOST_TEST(fusion::at_c<1>(t) == 'a'); BOOST_TEST(fusion::at_c<2>(t) == "hello"); BOOST_TEST(fusion::fold(t, true, modifying_fold_functor()) == true); BOOST_TEST(fusion::fold(t, true, nonmodifying_fold_functor()) == true); return boost::report_errors(); }