diff --git a/doc/iterator.qbk b/doc/iterator.qbk index ef33240a..51640450 100644 --- a/doc/iterator.qbk +++ b/doc/iterator.qbk @@ -254,6 +254,7 @@ expressions must be valid: * __iterator_range__ iterator (where adapted iterators are __associative_iterator__\ s) * __joint_view__ iterator (where adapted sequences are __associative_sequence__\ s and __forward_sequence__\ s) * __reverse_view__ iterator (where adapted sequence is an __associative_sequence__ and a __bidirectional_sequence__) +* __transform_view__ iterator (where adapted sequence is an __associative_sequence__ and a __forward_sequence__) [endsect] diff --git a/doc/sequence.qbk b/doc/sequence.qbk index 6f50fe21..b193b8e9 100644 --- a/doc/sequence.qbk +++ b/doc/sequence.qbk @@ -360,6 +360,7 @@ you can use `__result_of_value_at_key__`.] * __iterator_range__ (where adapted iterators are __associative_iterator__\ s) * __joint_view__ (where adapted sequences are __associative_sequence__\ s and __forward_sequence__\ s) * __reverse_view__ (where adapted sequence is an __associative_sequence__ and a __bidirectional_sequence__) +* __transform_view__ (where adapted sequence is an __associative_sequence__ and a __forward_sequence__) [endsect] diff --git a/doc/view.qbk b/doc/view.qbk index e65ac630..d99b325f 100644 --- a/doc/view.qbk +++ b/doc/view.qbk @@ -363,6 +363,7 @@ given a binary function object or function pointer. * __forward_sequence__, __bidirectional_sequence__ or __random_access_sequence__ depending on the traversal characteristics (see __traversal_concept__) of its underlying sequence or sequences. +* __associative_sequence__ if underlying sequence implements the __associative_sequence__ model(available only with unary version of `transform_view`). [variablelist Notation [[`TV`] [A `transform_view` type]] diff --git a/include/boost/fusion/view/transform_view/detail/deref_data_impl.hpp b/include/boost/fusion/view/transform_view/detail/deref_data_impl.hpp new file mode 100644 index 00000000..3eb325a4 --- /dev/null +++ b/include/boost/fusion/view/transform_view/detail/deref_data_impl.hpp @@ -0,0 +1,66 @@ +/*============================================================================= + Copyright (c) 2022 Denis Mikhailov + 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) +==============================================================================*/ + +#if !defined(BOOST_FUSION_TRANSFORM_VIEW_DEREF_DATA_IMPL_JAN_9_2022_0354PM) +#define BOOST_FUSION_TRANSFORM_VIEW_DEREF_DATA_IMPL_JAN_9_2022_0354PM + +#include +#include +#include + +namespace boost { namespace fusion +{ + struct transform_view_iterator_tag; + struct transform_view_iterator2_tag; + + namespace extension + { + template + struct deref_data_impl; + + // Unary Version + template<> + struct deref_data_impl + { + template + struct apply + { + typedef typename + result_of::deref::type + value_type; + + typedef typename Iterator::transform_type F; + typedef typename boost::result_of::type transformed_type; + typedef typename boost::remove_reference::type transformed_type_unref; + typedef typename boost::remove_const::type transformed_type_unconst; + + typedef typename transformed_type_unconst::second_type raw_type; + typedef typename + boost::mpl::if_< + is_reference + , typename boost::mpl::if_< + is_const + , typename boost::add_reference::type>::type + , typename boost::add_reference::type + >::type + , raw_type + >::type + type; + + BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED + static type + call(Iterator const& i) + { + return i.f(fusion::deref(i.first)).second; + } + }; + }; + + // Binary Version is not supported with Associative Sequence + } +}} + +#endif diff --git a/include/boost/fusion/view/transform_view/detail/key_of_impl.hpp b/include/boost/fusion/view/transform_view/detail/key_of_impl.hpp new file mode 100644 index 00000000..226814f1 --- /dev/null +++ b/include/boost/fusion/view/transform_view/detail/key_of_impl.hpp @@ -0,0 +1,47 @@ +/*============================================================================= + Copyright (c) 2022 Denis Mikhailov + 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) +==============================================================================*/ + +#if !defined(BOOST_FUSION_TRANSFORM_VIEW_KEY_OF_IMPL_JAN_9_2022_0354PM) +#define BOOST_FUSION_TRANSFORM_VIEW_KEY_OF_IMPL_JAN_9_2022_0354PM + +#include +#include +#include + +namespace boost { namespace fusion +{ + struct transform_view_iterator_tag; + struct transform_view_iterator2_tag; + + namespace extension + { + template + struct key_of_impl; + + // Unary Version + template<> + struct key_of_impl + { + template + struct apply + { + typedef typename + result_of::deref::type + value_type; + + typedef typename Iterator::transform_type F; + typedef typename boost::result_of::type transformed_type; + typedef typename boost::remove_reference::type transformed_type_unref; + typedef typename boost::remove_const::type transformed_type_unconst; + + typedef typename transformed_type_unconst::first_type type; + }; + }; + + // Binary Version is not supported with Associative Sequence + } +}} +#endif diff --git a/include/boost/fusion/view/transform_view/detail/value_of_data_impl.hpp b/include/boost/fusion/view/transform_view/detail/value_of_data_impl.hpp new file mode 100644 index 00000000..e350db49 --- /dev/null +++ b/include/boost/fusion/view/transform_view/detail/value_of_data_impl.hpp @@ -0,0 +1,47 @@ +/*============================================================================= + Copyright (c) 2022 Denis Mikhailov + 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) +==============================================================================*/ + +#if !defined(BOOST_FUSION_TRANSFORM_VIEW_VALUE_OF_IMPL_JAN_9_2022_0354PM) +#define BOOST_FUSION_TRANSFORM_VIEW_VALUE_OF_IMPL_JAN_9_2022_0354PM + +#include +#include +#include + +namespace boost { namespace fusion +{ + struct transform_view_iterator_tag; + struct transform_view_iterator2_tag; + + namespace extension + { + template + struct value_of_data_impl; + + // Unary Version + template<> + struct value_of_data_impl + { + template + struct apply + { + typedef typename + result_of::deref::type + value_type; + + typedef typename Iterator::transform_type F; + typedef typename boost::result_of::type transformed_type; + typedef typename boost::remove_reference::type transformed_type_unref; + typedef typename boost::remove_const::type transformed_type_unconst; + + typedef typename transformed_type_unconst::second_type type; + }; + }; + + // Binary Version is not supported with Associative Sequence + } +}} +#endif diff --git a/include/boost/fusion/view/transform_view/transform_view_iterator.hpp b/include/boost/fusion/view/transform_view/transform_view_iterator.hpp index 2689ae8a..071cba8e 100644 --- a/include/boost/fusion/view/transform_view/transform_view_iterator.hpp +++ b/include/boost/fusion/view/transform_view/transform_view_iterator.hpp @@ -19,6 +19,9 @@ #include #include #include +#include +#include +#include namespace boost { namespace fusion { diff --git a/test/sequence/transform_view.cpp b/test/sequence/transform_view.cpp index b9e3f943..4f11e6b7 100644 --- a/test/sequence/transform_view.cpp +++ b/test/sequence/transform_view.cpp @@ -1,11 +1,14 @@ /*============================================================================= Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2022 Denis Mikhailov 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) ==============================================================================*/ #include #include +#include +#include #include #include #include @@ -14,15 +17,29 @@ #include #include #include +#include +#include +#include +#include #include #include #include #include #include +#include +#include +#include +#include +#include #include #include +#include +#include #include +#include +#include +#include struct square { @@ -60,6 +77,85 @@ struct add } }; +struct abstract +{ + virtual void foo() = 0; +}; + +struct functor +{ + typedef boost::fusion::pair pair_0; + typedef boost::fusion::pair pair_1; + typedef boost::fusion::pair pair_2; + + typedef boost::mpl::map< + boost::mpl::pair< boost::fusion::pair , pair_0> + , boost::mpl::pair< pair_1 , pair_1> + , boost::mpl::pair< boost::fusion::pair , pair_2> + > m; + + template + struct result; + + template + struct result + : boost::mpl::at< + m, + typename boost::remove_reference::type + > + {}; + + pair_0 operator() (const boost::fusion::pair& arg) const + { + return pair_0(arg.second); + } + + pair_1 operator() (const pair_1 & arg) const + { + return pair_1(arg.second + "_transformed"); + } + + pair_2 operator() (const boost::fusion::pair& arg) const + { + return pair_2(arg.second); + } +}; + +struct simple_identity +{ + template + struct result; + + template + struct result + { + typedef U type; + }; + + template + T& operator() (T& arg) const + { + return arg; + } +}; + +struct simple_identity_nonref +{ + template + struct result; + + template + struct result + : boost::remove_reference + {}; + + template + T operator() (T arg) const + { + return arg; + } +}; + int main() { @@ -110,6 +206,183 @@ main() BOOST_MPL_ASSERT((boost::is_same::type, int>)); } + /// Associative + { + typedef map< + pair + , pair + , pair > + map_type; + typedef transform_view transformed_type; + + BOOST_MPL_ASSERT((traits::is_associative)); + BOOST_MPL_ASSERT((traits::is_random_access)); + + map_type m( + make_pair('X') + , make_pair("Men") + , make_pair(2)); + transformed_type t(m, functor()); + + std::cout << at_key(t) << std::endl; + std::cout << at_key(t) << std::endl; + std::cout << at_key(t) << std::endl; + + BOOST_TEST(at_key(t) == 'X'); + BOOST_TEST(at_key(t) == "Men_transformed"); + BOOST_TEST(at_key(t) == 2); + + BOOST_STATIC_ASSERT(( + boost::is_same::type, char>::value)); + BOOST_STATIC_ASSERT(( + boost::is_same::type, std::string>::value)); + BOOST_STATIC_ASSERT(( + boost::is_same::type, long>::value)); + + std::cout << t << std::endl; + + BOOST_STATIC_ASSERT((boost::fusion::result_of::has_key::value)); + BOOST_STATIC_ASSERT((boost::fusion::result_of::has_key::value)); + BOOST_STATIC_ASSERT((boost::fusion::result_of::has_key::value)); + BOOST_STATIC_ASSERT((!boost::fusion::result_of::has_key::value)); + + std::cout << deref_data(begin(t)) << std::endl; + std::cout << deref_data(boost::fusion::next(begin(t))) << std::endl; + + BOOST_TEST(deref_data(begin(t)) == 'X'); + BOOST_TEST(deref_data(boost::fusion::next(begin(t))) == "Men_transformed"); + BOOST_TEST(deref_data(boost::fusion::next(next(begin(t)))) == 2); + + BOOST_STATIC_ASSERT((boost::is_same::type>::type, short>::value)); + BOOST_STATIC_ASSERT((boost::is_same::type>::type>::type, double>::value)); + BOOST_STATIC_ASSERT((boost::is_same::type>::type>::type>::type, abstract>::value)); + BOOST_STATIC_ASSERT((boost::is_same::type>::type, char>::value)); + BOOST_STATIC_ASSERT((boost::is_same::type>::type>::type, std::string>::value)); + BOOST_STATIC_ASSERT((boost::is_same::type>::type>::type>::type, long>::value)); + + // Test random access interface. + pair a = at_c<0>(t); (void) a; + pair b = at_c<1>(t); + pair c = at_c<2>(t); + (void)c; + + typedef boost::fusion::result_of::begin::type first; + typedef boost::fusion::result_of::next::type second; + typedef boost::fusion::result_of::next::type third; + + BOOST_MPL_ASSERT((boost::is_same::type, boost::fusion::pair >)); + BOOST_MPL_ASSERT((boost::is_same::type, boost::fusion::pair >)); + BOOST_MPL_ASSERT((boost::is_same::type, boost::fusion::pair >)); + } + + { + typedef map< + pair + , pair + , pair > + map_type; + typedef transform_view transformed_type; + + BOOST_MPL_ASSERT((traits::is_associative)); + BOOST_MPL_ASSERT((traits::is_random_access)); + + map_type m( + make_pair('X') + , make_pair("Men") + , make_pair(2)); + transformed_type t(m, simple_identity()); + + std::cout << at_key(t) << std::endl; + std::cout << at_key(t) << std::endl; + std::cout << at_key(t) << std::endl; + + BOOST_TEST(at_key(t) == 'X'); + BOOST_TEST(at_key(t) == "Men"); + BOOST_TEST(at_key(t) == 2); + + BOOST_STATIC_ASSERT(( + boost::is_same::type, char>::value)); + BOOST_STATIC_ASSERT(( + boost::is_same::type, std::string>::value)); + BOOST_STATIC_ASSERT(( + boost::is_same::type, int>::value)); + + std::cout << t << std::endl; + + BOOST_STATIC_ASSERT((boost::fusion::result_of::has_key::value)); + BOOST_STATIC_ASSERT((boost::fusion::result_of::has_key::value)); + BOOST_STATIC_ASSERT((boost::fusion::result_of::has_key::value)); + BOOST_STATIC_ASSERT((!boost::fusion::result_of::has_key::value)); + + std::cout << deref_data(begin(t)) << std::endl; + std::cout << deref_data(boost::fusion::next(begin(t))) << std::endl; + + BOOST_TEST(deref_data(begin(t)) == 'X'); + BOOST_TEST(deref_data(boost::fusion::next(begin(t))) == "Men"); + BOOST_TEST(deref_data(boost::fusion::next(next(begin(t)))) == 2); + + BOOST_STATIC_ASSERT((boost::is_same::type>::type, int>::value)); + BOOST_STATIC_ASSERT((boost::is_same::type>::type>::type, double>::value)); + BOOST_STATIC_ASSERT((boost::is_same::type>::type>::type>::type, abstract>::value)); + BOOST_STATIC_ASSERT((boost::is_same::type>::type, char>::value)); + BOOST_STATIC_ASSERT((boost::is_same::type>::type>::type, std::string>::value)); + BOOST_STATIC_ASSERT((boost::is_same::type>::type>::type>::type, int>::value)); + + // Test random access interface. + pair a = at_c<0>(t); (void) a; + pair b = at_c<1>(t); + pair c = at_c<2>(t); + (void)c; + + typedef boost::fusion::result_of::begin::type first; + typedef boost::fusion::result_of::next::type second; + typedef boost::fusion::result_of::next::type third; + + // BOOST_MPL_ASSERT((boost::is_same::type, boost::fusion::pair >)); + // BOOST_MPL_ASSERT((boost::is_same::type, boost::fusion::pair >)); + // BOOST_MPL_ASSERT((boost::is_same::type, boost::fusion::pair >)); + } + + { + // compile test only + // make sure result_of::deref_data returns a reference + typedef map > map_type; + typedef transform_view transformed_type; + typedef boost::fusion::result_of::begin::type i_type; + typedef boost::fusion::result_of::deref_data::type r_type; + BOOST_STATIC_ASSERT((boost::is_same::value)); + } + + { + // compile test only + // make sure result_of::deref_data is const correct + typedef map > const map_type; + typedef transform_view transformed_type; + typedef boost::fusion::result_of::begin::type i_type; + typedef boost::fusion::result_of::deref_data::type r_type; + BOOST_STATIC_ASSERT((boost::is_same::value)); + } + + { + // compile test only + // make sure result_of::deref_data will not return a reference to temp object + typedef map > const map_type; + typedef transform_view transformed_type; + typedef boost::fusion::result_of::begin::type i_type; + typedef boost::fusion::result_of::deref_data::type r_type; + BOOST_STATIC_ASSERT((boost::is_same::value)); + } + + { + // compile test only + // make sure result_of::deref_data will not const for non-constant references + typedef map > const map_type; + typedef transform_view transformed_type; + typedef boost::fusion::result_of::begin::type i_type; + typedef boost::fusion::result_of::deref_data::type r_type; + BOOST_STATIC_ASSERT((boost::is_same::value)); + } + return boost::report_errors(); }