diff options
Diffstat (limited to 'src/boost/libs/hana/example/tutorial')
22 files changed, 2545 insertions, 0 deletions
diff --git a/src/boost/libs/hana/example/tutorial/algorithms.cpp b/src/boost/libs/hana/example/tutorial/algorithms.cpp new file mode 100644 index 000000000..9afe86b1e --- /dev/null +++ b/src/boost/libs/hana/example/tutorial/algorithms.cpp @@ -0,0 +1,148 @@ +// Copyright Louis Dionne 2013-2017 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#include <boost/hana.hpp> +#include <boost/hana/ext/std/integral_constant.hpp> + +#include <sstream> +#include <string> +#include <tuple> +#include <type_traits> +namespace hana = boost::hana; +using namespace hana::literals; +using namespace std::literals; + + +int main() { + +{ + +//! [reverse_transform] +auto to_str = [](auto const& x) { + std::stringstream ss; + ss << x; + return ss.str(); +}; + +auto xs = hana::make_tuple(1, 2.2, 'a', "bcde"); + +BOOST_HANA_RUNTIME_CHECK( + hana::reverse(hana::transform(xs, to_str)) == hana::make_tuple("bcde", "a", "2.2", "1") +); +//! [reverse_transform] + +//! [reverse_transform_copy] +hana::reverse( + hana::transform(xs, to_str) // <-- copy into reverse(...) here? +); +//! [reverse_transform_copy] + +//! [reverse_transform_move] +hana::reverse( + hana::transform(xs, to_str) // <-- nope, move from the temporary instead! +); +//! [reverse_transform_move] + +}{ + +//! [effects] +auto r = hana::any_of(hana::make_tuple("hello"s, 1.2, 3), [](auto x) { + return std::is_integral<decltype(x)>{}; +}); + +BOOST_HANA_CONSTANT_CHECK(r); +//! [effects] + +{ + +//! [effects.codegen] +auto xs = hana::make_tuple("hello"s, 1.2, 3); +auto pred = [](auto x) { return std::is_integral<decltype(x)>{}; }; + +auto r = hana::bool_c< + decltype(pred(xs[0_c]))::value ? true : + decltype(pred(xs[1_c]))::value ? true : + decltype(pred(xs[2_c]))::value ? true : + false +>; + +BOOST_HANA_CONSTANT_CHECK(r); +//! [effects.codegen] + +} + +}{ + +//! [cross_phase.setup] +struct Fish { std::string name; }; +struct Cat { std::string name; }; +struct Dog { std::string name; }; + +auto animals = hana::make_tuple(Fish{"Nemo"}, Cat{"Garfield"}, Dog{"Snoopy"}); +// ^^^^^^^ not a compile-time value + +BOOST_HANA_CONSTANT_CHECK(hana::length(animals) == hana::size_c<3>); +// ^^^^^^^^^^^^^^^^^^^^^ assertion done at compile-time +//! [cross_phase.setup] + +//! [cross_phase.is_empty] +BOOST_HANA_CONSTANT_CHECK(!hana::is_empty(animals)); +// ^^^^^^^^^^^^^^^^^^^^^^^ assertion done at compile-time +//! [cross_phase.is_empty] + +{ + +//! [cross_phase.any_of_runtime] +bool any_garfield = hana::any_of(animals, [](auto animal) { + return animal.name == "Garfield"s; +}); + +BOOST_HANA_RUNTIME_CHECK(any_garfield); +//! [cross_phase.any_of_runtime] + +}{ + +//! [cross_phase.any_of_compile_time] +auto any_cat = hana::any_of(animals, [](auto x) { + return std::is_same<decltype(x), Cat>{}; +}); + +BOOST_HANA_CONSTANT_CHECK(any_cat); +//! [cross_phase.any_of_compile_time] + +}{ + +//! [cross_phase.any_of_explicit] +hana::integral_constant<bool, true> any_cat = hana::any_of(animals, [](auto x) { + return std::is_same<decltype(x), Cat>{}; +}); + +BOOST_HANA_CONSTANT_CHECK(any_cat); +//! [cross_phase.any_of_explicit] + +}{ + +//! [cross_phase.filter] +auto mammals = hana::filter(animals, [](auto animal) { + return hana::type_c<decltype(animal)> != hana::type_c<Fish>; +}); +//! [cross_phase.filter] + +BOOST_HANA_RUNTIME_CHECK( + hana::transform(mammals, [](auto x) { return x.name; }) + == hana::make_tuple("Garfield", "Snoopy") +); + +} + +}{ + +//! [cross_phase.std::tuple_size] +std::tuple<int, char, std::string> xs{1, '2', std::string{"345"}}; +static_assert(std::tuple_size<decltype(xs)>::value == 3u, ""); +//! [cross_phase.std::tuple_size] + +} + +} diff --git a/src/boost/libs/hana/example/tutorial/appendix_mpl.cpp b/src/boost/libs/hana/example/tutorial/appendix_mpl.cpp new file mode 100644 index 000000000..3174af2ce --- /dev/null +++ b/src/boost/libs/hana/example/tutorial/appendix_mpl.cpp @@ -0,0 +1,697 @@ +// Copyright Louis Dionne 2013-2017 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#include <boost/hana.hpp> +#include <boost/hana/ext/boost/mpl.hpp> +#include <boost/hana/ext/std.hpp> + +#include <boost/mpl/lambda.hpp> +#include <boost/mpl/placeholders.hpp> +#include <boost/mpl/quote.hpp> + +#include <iostream> +#include <type_traits> +namespace hana = boost::hana; +namespace mpl = boost::mpl; + + +namespace hpl { +////////////////////////////////////////////////////////////////////////////// +// Utilities +////////////////////////////////////////////////////////////////////////////// +namespace detail { + template <typename Pred> + constexpr auto mpl_predicate = hana::integral(hana::metafunction_class< + typename mpl::lambda<Pred>::type + >); + + template <typename F> + constexpr auto mpl_metafunction = hana::metafunction_class< + typename mpl::lambda<F>::type + >; +} + +////////////////////////////////////////////////////////////////////////////// +// integral_c +////////////////////////////////////////////////////////////////////////////// +template <typename T, T v> +using integral_c = std::integral_constant<T, v>; + +template <int i> +using int_ = integral_c<int, i>; + +template <long i> +using long_ = integral_c<long, i>; + +template <bool b> +using bool_ = integral_c<bool, b>; + +using true_ = bool_<true>; +using false_ = bool_<false>; + + +////////////////////////////////////////////////////////////////////////////// +// Sequences, compile-time integers & al +// +// Differences with the MPL: +// 1. `pair<...>::first` and `pair<...>::second` won't work; +// use `first<pair<...>>` instead +////////////////////////////////////////////////////////////////////////////// +template <typename ...T> +using vector = hana::tuple<hana::type<T>...>; + +template <typename T, T ...v> +using vector_c = hana::tuple<hana::integral_constant<T, v>...>; + +template <typename T, T from, T to> +using range_c = decltype(hana::range_c<T, from, to>); + + +template <typename T, typename U> +using pair = hana::pair<hana::type<T>, hana::type<U>>; + +template <typename P> +struct first : decltype(+hana::first(P{})) { }; + +template <typename P> +struct second : decltype(+hana::second(P{})) { }; + + +////////////////////////////////////////////////////////////////////////////// +// Miscellaneous metafunctions +////////////////////////////////////////////////////////////////////////////// +template <typename C1, typename C2> +struct equal_to + : bool_<C1::value == C2::value> +{ }; + +template <typename C1, typename C2> +struct less + : bool_<(C1::value < C2::value)> +{ }; + +template <typename C1, typename C2> +struct greater + : bool_<(C1::value > C2::value)> +{ }; + +template <typename N> +struct next + : integral_c<typename N::value_type, N::value + 1> +{ }; + +////////////////////////////////////////////////////////////////////////////// +// Intrinsics +// +// Differences with the MPL: +// 1. `at` does not work for associative sequences; use `find` instead. +// 2. `begin`, `end`, `clear`, `erase`, `erase_key`, `insert`, `insert_range`, +// `is_sequence`, `key_type`, `order`, `sequence_tag`, `value_type`: not implemented +////////////////////////////////////////////////////////////////////////////// +template <typename Sequence, typename N> +struct at + : decltype(hana::at(Sequence{}, N{})) +{ }; + +template <typename Sequence, long n> +using at_c = at<Sequence, long_<n>>; + +template <typename Sequence> +struct back + : decltype(+hana::back(Sequence{})) +{ }; + +template <typename Sequence> +struct empty + : decltype(hana::is_empty(Sequence{})) +{ }; + +template <typename Sequence> +struct front + : decltype(+hana::front(Sequence{})) +{ }; + +template <typename Sequence> +struct pop_back { + using type = decltype(hana::drop_back( + hana::to_tuple(Sequence{}), hana::size_c<1> + )); +}; + +template <typename Sequence> +struct pop_front { + using type = decltype(hana::drop_front(Sequence{})); +}; + +template <typename Sequence, typename T> +struct push_back { + using type = decltype(hana::append(Sequence{}, hana::type_c<T>)); +}; + +template <typename Sequence, typename T> +struct push_front { + using type = decltype(hana::prepend(Sequence{}, hana::type_c<T>)); +}; + +template <typename Sequence> +struct size + : decltype(hana::length(Sequence{})) +{ }; + +////////////////////////////////////////////////////////////////////////////// +// Iteration algorithms +// +// Differences with the MPL: +// 1. reverse_fold: +// Does not take an optional additional ForwardOp argument. +// +// 2. iter_fold, reverse_iter_fold: +// Not implemented because we don't use iterators +////////////////////////////////////////////////////////////////////////////// +template <typename Sequence, typename State, typename F> +struct fold + : decltype(hana::fold( + Sequence{}, hana::type_c<State>, detail::mpl_metafunction<F> + )) +{ }; + +template <typename Sequence, typename State, typename F> +struct reverse_fold + : decltype(hana::reverse_fold( + Sequence{}, hana::type_c<State>, detail::mpl_metafunction<F> + )) +{ }; + +template <typename Sequence, typename State, typename F> +using accumulate = fold<Sequence, State, F>; + +////////////////////////////////////////////////////////////////////////////// +// Query algorithms +// +// Differences with the MPL: +// 1. find_if and find: +// Instead of returning an iterator, they either have a nested `::type` +// alias to the answer, or they have no nested `::type` at all, which +// makes them SFINAE-friendly. +// +// 2. lower_bound, upper_bound: +// Not implemented. +// +// 3. {min,max}_element: +// Not returning an iterator, and also won't work on empty sequences. +////////////////////////////////////////////////////////////////////////////// +template <typename Sequence, typename Pred> +struct find_if + : decltype(hana::find_if(Sequence{}, detail::mpl_predicate<Pred>)) +{ }; + +template <typename Sequence, typename T> +struct find + : decltype(hana::find(Sequence{}, hana::type_c<T>)) +{ }; + +template <typename Sequence, typename T> +struct contains + : decltype(hana::contains(Sequence{}, hana::type_c<T>)) +{ }; + +template <typename Sequence, typename T> +struct count + : decltype(hana::count(Sequence{}, hana::type_c<T>)) +{ }; + +template <typename Sequence, typename Pred> +struct count_if + : decltype(hana::count_if(Sequence{}, detail::mpl_predicate<Pred>)) +{ }; + +template <typename Sequence, typename Pred = mpl::quote2<less>> +struct min_element + : decltype(hana::minimum(Sequence{}, detail::mpl_predicate<Pred>)) +{ }; + +template <typename Sequence, typename Pred = mpl::quote2<less>> +struct max_element + : decltype(hana::maximum(Sequence{}, detail::mpl_predicate<Pred>)) +{ }; + +template <typename S1, typename S2, typename Pred = mpl::quote2<std::is_same>> +struct equal + : decltype( // inefficient but whatever + hana::length(S1{}) == hana::length(S2{}) && + hana::all(hana::zip_shortest_with(detail::mpl_predicate<Pred>, + hana::to_tuple(S1{}), + hana::to_tuple(S2{}))) + ) +{ }; + +////////////////////////////////////////////////////////////////////////////// +// Transformation algorithms +// +// Differences from the MPL: +// 1. The algorithms do not accept an optional inserter, and they always +// return a `vector`. +// 2. stable_partition: not implemented +// 3. All the reverse_* algorithms are not implemented. +////////////////////////////////////////////////////////////////////////////// +template <typename Sequence> +struct copy { + using type = decltype(hana::to_tuple(Sequence{})); +}; + +template <typename Sequence, typename Pred> +struct copy_if { + using type = decltype(hana::filter( + hana::to_tuple(Sequence{}), + detail::mpl_predicate<Pred> + )); +}; + +template <typename Sequence, typename Sequence_or_Op, typename = void> +struct transform; + +template <typename Sequence, typename Op> +struct transform<Sequence, Op> { + using type = decltype(hana::transform( + hana::to_tuple(Sequence{}), detail::mpl_metafunction<Op> + )); +}; + +template <typename S1, typename S2, typename Op> +struct transform { + using type = decltype(hana::zip_with( + detail::mpl_metafunction<Op>, + hana::to_tuple(S1{}), + hana::to_tuple(S2{}) + )); +}; + +template <typename Sequence, typename OldType, typename NewType> +struct replace { + using type = decltype(hana::replace( + hana::to_tuple(Sequence{}), + hana::type_c<OldType>, + hana::type_c<NewType> + )); +}; + +template <typename Sequence, typename Pred, typename NewType> +struct replace_if { + using type = decltype(hana::replace_if( + hana::to_tuple(Sequence{}), + detail::mpl_predicate<Pred>, + hana::type_c<NewType> + )); +}; + +template <typename Sequence, typename T> +struct remove { + using type = decltype(hana::filter( + hana::to_tuple(Sequence{}), + hana::not_equal.to(hana::type_c<T>) + )); +}; + +template <typename Sequence, typename Pred> +struct remove_if { + using type = decltype(hana::filter( + hana::to_tuple(Sequence{}), + hana::compose(hana::not_, detail::mpl_predicate<Pred>) + )); +}; + +template <typename Sequence, typename Pred> +struct unique { + using type = decltype(hana::unique( + hana::to_tuple(Sequence{}), + detail::mpl_predicate<Pred> + )); +}; + +template <typename Sequence, typename Pred> +struct partition { + using hana_pair = decltype(hana::partition( + hana::to_tuple(Sequence{}), + detail::mpl_predicate<Pred> + )); + using type = pair< + decltype(hana::first(hana_pair{})), + decltype(hana::second(hana_pair{})) + >; +}; + +template <typename Sequence, typename Pred = mpl::quote2<less>> +struct sort { + using type = decltype(hana::sort( + hana::to_tuple(Sequence{}), detail::mpl_predicate<Pred> + )); +}; + +template <typename Sequence> +struct reverse { + using type = decltype(hana::reverse(hana::to_tuple(Sequence{}))); +}; + + +////////////////////////////////////////////////////////////////////////////// +// Runtime algorithms +////////////////////////////////////////////////////////////////////////////// +template <typename Sequence, typename F> +void for_each(F f) { + hana::for_each(Sequence{}, [&f](auto t) { + f(typename decltype(t)::type{}); + }); +} + +template <typename Sequence, typename TransformOp, typename F> +void for_each(F f) { + for_each<typename transform<Sequence, TransformOp>::type>(f); +} + +} // end namespace hpl + + +template <typename N> +struct is_odd + : hpl::bool_<(N::value % 2)> +{ }; + + +int main() { +using namespace hpl; + +////////////////////////////////////////////////////////////////////////////// +// Misc +////////////////////////////////////////////////////////////////////////////// + +// pair +{ + static_assert(std::is_same<first<pair<int, float>>::type, int>{}, ""); + static_assert(std::is_same<second<pair<int, float>>::type, float>{}, ""); +} + +////////////////////////////////////////////////////////////////////////////// +// Intrinsics +////////////////////////////////////////////////////////////////////////////// + +// at +{ + using range = range_c<long,10,50>; + static_assert(at<range, int_<0>>::value == 10, ""); + static_assert(at<range, int_<10>>::value == 20, ""); + static_assert(at<range, int_<40>>::value == 50, ""); +} + +// at_c +{ + using range = range_c<long, 10, 50>; + static_assert(at_c<range, 0>::value == 10, ""); + static_assert(at_c<range, 10>::value == 20, ""); + static_assert(at_c<range, 40>::value == 50, ""); +} + +// back +{ + using range1 = range_c<int,0,1>; + using range2 = range_c<int,0,10>; + using range3 = range_c<int,-10,0>; + using types = vector<int, char, float>; + static_assert(back<range1>::value == 0, ""); + static_assert(back<range2>::value == 9, ""); + static_assert(back<range3>::value == -1, ""); + static_assert(std::is_same<back<types>::type, float>{}, ""); +} + +// empty +{ + using empty_range = range_c<int,0,0>; + using types = vector<long,float,double>; + static_assert(empty<empty_range>{}, ""); + static_assert(!empty<types>{}, ""); +} + +// front +{ + using types1 = vector<long>; + using types2 = vector<int,long>; + using types3 = vector<char,int,long>; + static_assert(std::is_same<front<types1>::type, long>{}, ""); + static_assert(std::is_same<front<types2>::type, int>{}, ""); + static_assert(std::is_same<front<types3>::type, char>{}, ""); +} + +// pop_back +{ + using types1 = vector<long>; + using types2 = vector<long,int>; + using types3 = vector<long,int,char>; + + + using result1 = pop_back<types1>::type; + using result2 = pop_back<types2>::type; + using result3 = pop_back<types3>::type; + + static_assert(size<result1>::value == 0, ""); + static_assert(size<result2>::value == 1, ""); + static_assert(size<result3>::value == 2, ""); + + static_assert(std::is_same< back<result2>::type, long>{}, ""); + static_assert(std::is_same< back<result3>::type, int>{}, ""); +} + +// pop_front +{ + using types1 = vector<long>; + using types2 = vector<int,long>; + using types3 = vector<char,int,long>; + + using result1 = pop_front<types1>::type; + using result2 = pop_front<types2>::type; + using result3 = pop_front<types3>::type; + + static_assert(size<result1>::value == 0, ""); + static_assert(size<result2>::value == 1, ""); + static_assert(size<result3>::value == 2, ""); + + static_assert(std::is_same<front<result2>::type, long>{}, ""); + static_assert(std::is_same<front<result3>::type, int>{}, ""); +} + +// push_back +{ + using bools = vector_c<bool,false,false,false,true,true,true,false,false>; + using message = push_back<bools, false_>::type; + static_assert(back<message>::type::value == false, ""); + static_assert(count_if<message, equal_to<mpl::_1, false_>>{} == 6u, ""); +} + +// push_front +{ + using v = vector_c<int,1,2,3,5,8,13,21>; + static_assert(size<v>{} == 7u, ""); + + using fibonacci = push_front<v, int_<1>>::type; + static_assert(size<fibonacci>{} == 8u, ""); + + static_assert(equal< + fibonacci, + vector_c<int,1,1,2,3,5,8,13,21>, + equal_to<mpl::_, mpl::_> + >{}, ""); +} + +// size +{ + using empty_list = vector<>; + using numbers = vector_c<int,0,1,2,3,4,5>; + using more_numbers = range_c<int,0,100>; + + static_assert(size<empty_list>{} == 0u, ""); + static_assert(size<numbers>{} == 6u, ""); + static_assert(size<more_numbers>{} == 100u, ""); +} + + +////////////////////////////////////////////////////////////////////////////// +// Iteration algorithms +////////////////////////////////////////////////////////////////////////////// + +// fold +{ + using types = vector<long,float,short,double,float,long,long double>; + using number_of_floats = fold<types, int_<0>, + mpl::if_<std::is_floating_point<mpl::_2>, + next<mpl::_1>, + mpl::_1 + > + >::type; + static_assert(number_of_floats{} == 4, ""); +} + +// reverse_fold +{ + using numbers = vector_c<int,5,-1,0,-7,-2,0,-5,4>; + using negatives = vector_c<int,-1,-7,-2,-5>; + using result = reverse_fold<numbers, vector_c<int>, + mpl::if_<less<mpl::_2, int_<0>>, + push_front<mpl::_1, mpl::_2>, + mpl::_1 + > + >::type; + static_assert(equal<negatives, result>{}, ""); +} + +////////////////////////////////////////////////////////////////////////////// +// Query algorithms +////////////////////////////////////////////////////////////////////////////// + +// find_if +{ + using types = vector<char,int,unsigned,long,unsigned long>; + using found = find_if<types, std::is_same<mpl::_1, unsigned>>::type; + static_assert(std::is_same<found, unsigned>{}, ""); +} + +// find +{ + using types = vector<char,int,unsigned,long,unsigned long>; + static_assert(std::is_same<find<types, unsigned>::type, unsigned>{}, ""); +} + +// contains +{ + using types = vector<char,int,unsigned,long,unsigned long>; + static_assert(!contains<types, bool>{}, ""); +} + +// count +{ + using types = vector<int,char,long,short,char,short,double,long>; + static_assert(count<types, short>{} == 2u, ""); +} + +// count_if +{ + using types = vector<int,char,long,short,char,long,double,long>; + static_assert(count_if<types, std::is_floating_point<mpl::_>>{} == 1u, ""); + static_assert(count_if<types, std::is_same<mpl::_, char>>{} == 2u, ""); + static_assert(count_if<types, std::is_same<mpl::_, void>>{} == 0u, ""); +} + +// min_element (MPL's example is completely broken) +{ +} + +// max_element (MPL's example is completely broken) +{ +} + +// equal +{ + using s1 = vector<char,int,unsigned,long,unsigned long>; + using s2 = vector<char,int,unsigned,long>; + static_assert(!equal<s1,s2>{}, ""); +} + + +////////////////////////////////////////////////////////////////////////////// +// Transformaton algorithms +////////////////////////////////////////////////////////////////////////////// +// copy +{ + using numbers = vector_c<int,10, 11, 12, 13, 14, 15, 16, 17, 18, 19>; + using result = copy<range_c<int, 10, 20>>::type; + static_assert(size<result>{} == 10u, ""); + static_assert(equal<result, numbers, mpl::quote2<equal_to>>{}, ""); +} + +// copy_if +{ + using result = copy_if<range_c<int, 0, 10>, less<mpl::_1, int_<5>>>::type; + static_assert(size<result>{} == 5u, ""); + static_assert(equal<result, range_c<int, 0, 5>>{}, ""); +} + +// transform +{ + using types = vector<char,short,int,long,float,double>; + using pointers = vector<char*,short*,int*,long*,float*,double*>; + using result = transform<types,std::add_pointer<mpl::_1>>::type; + static_assert(equal<result, pointers>{}, ""); +} + +// replace +{ + using types = vector<int,float,char,float,float,double>; + using expected = vector<int,double,char,double,double,double>; + using result = replace< types,float,double >::type; + static_assert(equal<result, expected>{}, ""); +} + +// replace_if +{ + using numbers = vector_c<int,1,4,5,2,7,5,3,5>; + using expected = vector_c<int,1,4,0,2,0,0,3,0>; + using result = replace_if<numbers, greater<mpl::_, int_<4>>, int_<0>>::type; + static_assert(equal<result, expected, mpl::quote2<equal_to>>{}, ""); +} + +// remove +{ + using types = vector<int,float,char,float,float,double>; + using result = hpl::remove<types, float>::type; + static_assert(equal<result, vector<int, char, double>>{}, ""); +} + +// remove_if +{ + using numbers = vector_c<int,1,4,5,2,7,5,3,5>; + using result = remove_if<numbers, greater<mpl::_, int_<4> > >::type; + static_assert(equal<result, vector_c<int,1,4,2,3>, mpl::quote2<equal_to>>{}, ""); +} + +// unique +{ + using types = vector<int,float,float,char,int,int,int,double>; + using expected = vector<int,float,char,int,double>; + using result = unique<types, std::is_same<mpl::_1, mpl::_2>>::type; + static_assert(equal<result, expected>{}, ""); +} + +// partition +{ + using r = partition<range_c<int,0,10>, is_odd<mpl::_1>>::type; + static_assert(equal<first<r>::type, vector_c<int,1,3,5,7,9>>{}, ""); + static_assert(equal<second<r>::type, vector_c<int,0,2,4,6,8>>{}, ""); +} + +// sort +{ + using numbers = vector_c<int,3,4,0,-5,8,-1,7>; + using expected = vector_c<int,-5,-1,0,3,4,7,8>; + using result = sort<numbers>::type; + static_assert(equal<result, expected, equal_to<mpl::_, mpl::_>>{}, ""); +} + +// reverse +{ + using numbers = vector_c<int,9,8,7,6,5,4,3,2,1,0>; + using result = reverse<numbers>::type; + static_assert(equal<result, range_c<int,0,10>>{}, ""); +} + +////////////////////////////////////////////////////////////////////////////// +// Runtime algorithms +////////////////////////////////////////////////////////////////////////////// + +// for_each +{ + auto value_printer = [](auto x) { + std::cout << x << '\n'; + }; + + for_each<range_c<int, 0, 10> >(value_printer); +} + +} diff --git a/src/boost/libs/hana/example/tutorial/concepts.cpp b/src/boost/libs/hana/example/tutorial/concepts.cpp new file mode 100644 index 000000000..751b47309 --- /dev/null +++ b/src/boost/libs/hana/example/tutorial/concepts.cpp @@ -0,0 +1,64 @@ +// Copyright Louis Dionne 2013-2017 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#include <boost/hana/core/default.hpp> +#include <boost/hana/core/tag_of.hpp> +#include <boost/hana/integral_constant.hpp> + +#include <string> +#include <type_traits> +namespace hana = boost::hana; + + +namespace with_special_base_class { +//! [special_base_class] +struct special_base_class { }; + +template <typename T> +struct print_impl : special_base_class { + template <typename ...Args> + static constexpr auto apply(Args&& ...) = delete; +}; + +template <typename T> +struct Printable + : hana::integral_constant<bool, + !std::is_base_of<special_base_class, print_impl<hana::tag_of_t<T>>>::value + > +{ }; +//! [special_base_class] + +//! [special_base_class_customize] +struct Person { std::string name; }; + +template <> +struct print_impl<Person> /* don't inherit from special_base_class */ { + // ... implementation ... +}; + +static_assert(Printable<Person>::value, ""); +static_assert(!Printable<void>::value, ""); +//! [special_base_class_customize] +} + +namespace actual { +//! [actual] +template <typename T> +struct print_impl : hana::default_ { + template <typename ...Args> + static constexpr auto apply(Args&& ...) = delete; +}; + +template <typename T> +struct Printable + : hana::integral_constant<bool, + !hana::is_default<print_impl<hana::tag_of_t<T>>>::value + > +{ }; +//! [actual] + +static_assert(!Printable<void>::value, ""); +} + +int main() { } diff --git a/src/boost/libs/hana/example/tutorial/constant_side_effects.cpp b/src/boost/libs/hana/example/tutorial/constant_side_effects.cpp new file mode 100644 index 000000000..ea81ec08e --- /dev/null +++ b/src/boost/libs/hana/example/tutorial/constant_side_effects.cpp @@ -0,0 +1,36 @@ +// Copyright Louis Dionne 2013-2017 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#include <boost/hana/bool.hpp> + +#include <iostream> +namespace hana = boost::hana; + + +namespace pure { +//! [pure] +template <typename X> +auto identity(X x) { return x; } + +auto x = identity(hana::bool_c<true>); +static_assert(hana::value(x), ""); +//! [pure] +} + +namespace impure { +//! [impure_identity] +template <typename X> +auto identity(X x) { + std::cout << "Good luck in evaluating this at compile-time!"; + return x; +} +//! [impure_identity] + +//! [impure] +auto x = identity(hana::bool_c<true>); +static_assert(hana::value(x), ""); +//! [impure] +} + +int main() { } diff --git a/src/boost/libs/hana/example/tutorial/containers.cpp b/src/boost/libs/hana/example/tutorial/containers.cpp new file mode 100644 index 000000000..fe9242704 --- /dev/null +++ b/src/boost/libs/hana/example/tutorial/containers.cpp @@ -0,0 +1,106 @@ +// Copyright Louis Dionne 2013-2017 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#include <boost/hana.hpp> + +#include <functional> +#include <string> +#include <type_traits> +#include <utility> +#include <vector> +namespace hana = boost::hana; +using namespace hana::literals; +using namespace std::literals; + + +int main() { + +{ + +//! [make<tuple_tag>] +auto xs = hana::make<hana::tuple_tag>(1, 2.2, 'a', "bcde"s); +//! [make<tuple_tag>] + +}{ + +//! [make<range_tag>] +constexpr auto r = hana::make<hana::range_tag>(hana::int_c<3>, hana::int_c<10>); +static_assert(r == hana::make_range(hana::int_c<3>, hana::int_c<10>), ""); +//! [make<range_tag>] + +}{ + +//! [tuple_constructor] +hana::tuple<int, double, char, std::string> xs{1, 2.2, 'a', "bcde"s}; +//! [tuple_constructor] +(void)xs; + +}{ + +//! [types] +auto xs = hana::make_tuple(1, '2', "345"); +auto ints = hana::make_range(hana::int_c<0>, hana::int_c<100>); +// what can we say about the types of `xs` and `ints`? +//! [types] +(void)xs; +(void)ints; + +}{ + +//! [types_maximally_specified] +hana::tuple<int, char, char const*> xs = hana::make_tuple(1, '2', "345"); +auto ints = hana::make_range(hana::int_c<0>, hana::int_c<100>); +// can't specify the type of ints, however +//! [types_maximally_specified] +(void)xs; +(void)ints; + +}{ + +//! [lifetime] +std::string hello = "Hello"; +std::vector<char> world = {'W', 'o', 'r', 'l', 'd'}; + +// hello is copied, world is moved-in +auto xs = hana::make_tuple(hello, std::move(world)); + +// s is a reference to the copy of hello inside xs. +// It becomes a dangling reference as soon as xs is destroyed. +std::string& s = xs[0_c]; +//! [lifetime] +(void)s; + +}{ + +//! [reference_wrapper] +std::vector<int> ints = { /* huge vector of ints */ }; +std::vector<std::string> strings = { /* huge vector of strings */ }; + +auto map = hana::make_map( + hana::make_pair(hana::type_c<int>, std::ref(ints)), + hana::make_pair(hana::type_c<std::string>, std::ref(strings)) +); + +auto& v = map[hana::type_c<int>].get(); +BOOST_HANA_RUNTIME_CHECK(&v == &ints); +//! [reference_wrapper] + +} + +} + + +namespace overloading { +//! [overloading] +template <typename T> +void f(std::vector<T> xs) { + // ... +} + +template <typename R, typename = std::enable_if_t<hana::is_a<hana::range_tag, R>()>> +void f(R r) { + // ... +} +//! [overloading] +} diff --git a/src/boost/libs/hana/example/tutorial/ext/fusion_to_hana.cpp b/src/boost/libs/hana/example/tutorial/ext/fusion_to_hana.cpp new file mode 100644 index 000000000..8b6a334d4 --- /dev/null +++ b/src/boost/libs/hana/example/tutorial/ext/fusion_to_hana.cpp @@ -0,0 +1,31 @@ +// Copyright Louis Dionne 2013-2017 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#include <boost/hana/for_each.hpp> +#include <boost/hana/tuple.hpp> +#include <boost/hana/ext/boost/fusion/vector.hpp> + +#include <boost/fusion/include/vector.hpp> + +#include <iostream> +namespace fusion = boost::fusion; +namespace hana = boost::hana; + + +//! [main] +// In the old code, this used to receive a Fusion sequence. +// Now, it can be either a Hana sequence or a Fusion sequence. +template <typename Sequence> +void f(Sequence const& seq) { + hana::for_each(seq, [](auto const& element) { + std::cout << element << std::endl; + }); +} +//! [main] + + +int main() { + f(hana::make_tuple(1, 2, 3)); + f(fusion::make_vector(1, 2, 3)); +} diff --git a/src/boost/libs/hana/example/tutorial/ext/mpl_vector.cpp b/src/boost/libs/hana/example/tutorial/ext/mpl_vector.cpp new file mode 100644 index 000000000..2802bafe6 --- /dev/null +++ b/src/boost/libs/hana/example/tutorial/ext/mpl_vector.cpp @@ -0,0 +1,40 @@ +// Copyright Louis Dionne 2013-2017 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#include <boost/hana/equal.hpp> +#include <boost/hana/front.hpp> +#include <boost/hana/integral_constant.hpp> +#include <boost/hana/type.hpp> + +#include <boost/mpl/size.hpp> +#include <boost/mpl/vector.hpp> +namespace hana = boost::hana; +namespace mpl = boost::mpl; + + +//! [front] +#include <boost/hana/ext/boost/mpl/vector.hpp> // bridge header + +using Vector = mpl::vector<int, char, float>; +static_assert(hana::front(Vector{}) == hana::type_c<int>, ""); +//! [front] + + +namespace _ns0 { +//! [size] +using Size = mpl::size<Vector>::type; +static_assert(hana::equal(Size{}, hana::int_c<3>), ""); // breaks! +//! [size] +} + + +//! [size-fixed] +#include <boost/hana/ext/boost/mpl/integral_c.hpp> + +using Size = mpl::size<Vector>::type; +static_assert(hana::equal(Size{}, hana::int_c<3>), ""); +//! [size-fixed] + + +int main() { } diff --git a/src/boost/libs/hana/example/tutorial/ext/ratio_plus.cpp b/src/boost/libs/hana/example/tutorial/ext/ratio_plus.cpp new file mode 100644 index 000000000..e3c15546f --- /dev/null +++ b/src/boost/libs/hana/example/tutorial/ext/ratio_plus.cpp @@ -0,0 +1,15 @@ +// Copyright Louis Dionne 2013-2017 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +//! [main] +#include <boost/hana/ext/std/ratio.hpp> +#include <boost/hana/plus.hpp> + +#include <ratio> +namespace hana = boost::hana; + +auto r = hana::plus(std::ratio<3, 4>{}, std::ratio<4, 5>{}); +//! [main] + +int main() { } diff --git a/src/boost/libs/hana/example/tutorial/include_ext.cpp b/src/boost/libs/hana/example/tutorial/include_ext.cpp new file mode 100644 index 000000000..d753d6249 --- /dev/null +++ b/src/boost/libs/hana/example/tutorial/include_ext.cpp @@ -0,0 +1,16 @@ +// Copyright Louis Dionne 2013-2017 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +//! [main] +#include <boost/hana/ext/std/tuple.hpp> +#include <boost/hana/front.hpp> +#include <tuple> // still required to create a tuple +namespace hana = boost::hana; + + +int main() { + constexpr std::tuple<int, char, float> xs{1, '2', 3.0f}; + static_assert(hana::front(xs) == 1, ""); +} +//! [main] diff --git a/src/boost/libs/hana/example/tutorial/integral-branching.cpp b/src/boost/libs/hana/example/tutorial/integral-branching.cpp new file mode 100644 index 000000000..7e93f9402 --- /dev/null +++ b/src/boost/libs/hana/example/tutorial/integral-branching.cpp @@ -0,0 +1,55 @@ +// Copyright Louis Dionne 2013-2017 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#include <boost/hana.hpp> +#include <boost/hana/ext/std/integral_constant.hpp> + +#include <memory> +#include <string> +#include <type_traits> +#include <utility> +namespace hana = boost::hana; + + + +namespace ns1 { +//! [make_unique.if_] +template <typename T, typename ...Args> +std::unique_ptr<T> make_unique(Args&&... args) { + return hana::if_(std::is_constructible<T, Args...>{}, + [](auto&& ...x) { return std::unique_ptr<T>(new T(std::forward<Args>(x)...)); }, + [](auto&& ...x) { return std::unique_ptr<T>(new T{std::forward<Args>(x)...}); } + )(std::forward<Args>(args)...); +} +//! [make_unique.if_] +} + + +namespace ns2 { +//! [make_unique.eval_if] +template <typename T, typename ...Args> +std::unique_ptr<T> make_unique(Args&&... args) { + return hana::eval_if(std::is_constructible<T, Args...>{}, + [&](auto _) { return std::unique_ptr<T>(new T(std::forward<Args>(_(args))...)); }, + [&](auto _) { return std::unique_ptr<T>(new T{std::forward<Args>(_(args))...}); } + ); +} +//! [make_unique.eval_if] +} + +struct Student { + std::string name; + int age; +}; + +int main() { + { + std::unique_ptr<int> a = ns1::make_unique<int>(3); + std::unique_ptr<Student> b = ns1::make_unique<Student>("Bob", 25); + } + { + std::unique_ptr<int> a = ns2::make_unique<int>(3); + std::unique_ptr<Student> b = ns2::make_unique<Student>("Bob", 25); + } +} diff --git a/src/boost/libs/hana/example/tutorial/integral.cpp b/src/boost/libs/hana/example/tutorial/integral.cpp new file mode 100644 index 000000000..be285c560 --- /dev/null +++ b/src/boost/libs/hana/example/tutorial/integral.cpp @@ -0,0 +1,128 @@ +// Copyright Louis Dionne 2013-2017 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#include <boost/mpl/equal_to.hpp> +#include <boost/mpl/int.hpp> +#include <boost/mpl/integral_c.hpp> +#include <boost/mpl/minus.hpp> +#include <boost/mpl/multiplies.hpp> +#include <boost/mpl/pair.hpp> +#include <boost/mpl/plus.hpp> + +#include <boost/hana/assert.hpp> +#include <boost/hana/concept/constant.hpp> +#include <boost/hana/equal.hpp> +#include <boost/hana/integral_constant.hpp> +#include <boost/hana/minus.hpp> +#include <boost/hana/mult.hpp> +#include <boost/hana/pair.hpp> +#include <boost/hana/plus.hpp> + +#include <type_traits> +namespace hana = boost::hana; + + +namespace support { +template <typename T, typename = std::enable_if_t< + !hana::Constant<T>::value +>> +constexpr T sqrt(T x) { + T inf = 0, sup = (x == 1 ? 1 : x/2); + while (!((sup - inf) <= 1 || ((sup*sup <= x) && ((sup+1)*(sup+1) > x)))) { + T mid = (inf + sup) / 2; + bool take_inf = mid*mid > x ? 1 : 0; + inf = take_inf ? inf : mid; + sup = take_inf ? mid : sup; + } + + return sup*sup <= x ? sup : inf; +} + +template <typename T, typename = std::enable_if_t< + hana::Constant<T>::value +>> +constexpr auto sqrt(T const&) { + return hana::integral_c<typename T::value_type, sqrt(T::value)>; +} +} // end namespace support + + +namespace then { +namespace mpl = boost::mpl; + +template <typename N> +struct sqrt + : mpl::integral_c<typename N::value_type, support::sqrt(N::value)> +{ }; + +template <typename X, typename Y> +struct point { + using x = X; + using y = Y; +}; + +//! [distance-mpl] +template <typename P1, typename P2> +struct distance { + using xs = typename mpl::minus<typename P1::x, + typename P2::x>::type; + using ys = typename mpl::minus<typename P1::y, + typename P2::y>::type; + using type = typename sqrt< + typename mpl::plus< + typename mpl::multiplies<xs, xs>::type, + typename mpl::multiplies<ys, ys>::type + >::type + >::type; +}; + +static_assert(mpl::equal_to< + distance<point<mpl::int_<3>, mpl::int_<5>>, + point<mpl::int_<7>, mpl::int_<2>>>::type, + mpl::int_<5> +>::value, ""); +//! [distance-mpl] +} + + +namespace now { +namespace hana = boost::hana; +using namespace hana::literals; + +template <typename X, typename Y> +struct _point { + X x; + Y y; +}; +template <typename X, typename Y> +constexpr _point<X, Y> point(X x, Y y) { return {x, y}; } + +using support::sqrt; // avoid conflicts with ::sqrt + +//! [distance-hana] +template <typename P1, typename P2> +constexpr auto distance(P1 p1, P2 p2) { + auto xs = p1.x - p2.x; + auto ys = p1.y - p2.y; + return sqrt(xs*xs + ys*ys); +} + +BOOST_HANA_CONSTANT_CHECK(distance(point(3_c, 5_c), point(7_c, 2_c)) == 5_c); +//! [distance-hana] + +void test() { + +//! [distance-dynamic] +auto p1 = point(3, 5); // dynamic values now +auto p2 = point(7, 2); // +BOOST_HANA_RUNTIME_CHECK(distance(p1, p2) == 5); // same function works! +//! [distance-dynamic] + +} +} + + +int main() { + now::test(); +} diff --git a/src/boost/libs/hana/example/tutorial/introduction.cpp b/src/boost/libs/hana/example/tutorial/introduction.cpp new file mode 100644 index 000000000..1cafff047 --- /dev/null +++ b/src/boost/libs/hana/example/tutorial/introduction.cpp @@ -0,0 +1,80 @@ +// Copyright Louis Dionne 2013-2017 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +// Make sure `assert` always triggers an assertion +#ifdef NDEBUG +# undef NDEBUG +#endif + +#include <boost/fusion/include/comparison.hpp> +#include <boost/fusion/include/make_vector.hpp> +#include <boost/fusion/include/transform.hpp> +#include <boost/fusion/include/vector.hpp> + +#include <boost/mpl/equal.hpp> +#include <boost/mpl/placeholders.hpp> +#include <boost/mpl/transform.hpp> +#include <boost/mpl/vector.hpp> + +#include <algorithm> +#include <cassert> +#include <iterator> +#include <sstream> +#include <string> +#include <vector> +namespace fusion = boost::fusion; +namespace mpl = boost::mpl; +using namespace std::literals; + + +int main() { + +{ + +//! [runtime] +auto f = [](int i) -> std::string { + return std::to_string(i * i); +}; + +std::vector<int> ints{1, 2, 3, 4}; +std::vector<std::string> strings; +std::transform(ints.begin(), ints.end(), std::back_inserter(strings), f); + +assert((strings == std::vector<std::string>{"1", "4", "9", "16"})); +//! [runtime] + +}{ + +//! [heterogeneous] +auto to_string = [](auto t) { + std::stringstream ss; + ss << t; + return ss.str(); +}; + +fusion::vector<int, std::string, float> seq{1, "abc", 3.4f}; +fusion::vector<std::string, std::string, std::string> + strings = fusion::transform(seq, to_string); + +assert(strings == fusion::make_vector("1"s, "abc"s, "3.4"s)); +//! [heterogeneous] + +} + +} + +//! [type-level] +template <typename T> +struct add_const_pointer { + using type = T const*; +}; + +using types = mpl::vector<int, char, float, void>; +using pointers = mpl::transform<types, add_const_pointer<mpl::_1>>::type; + +static_assert(mpl::equal< + pointers, + mpl::vector<int const*, char const*, float const*, void const*> +>::value, ""); +//! [type-level] diff --git a/src/boost/libs/hana/example/tutorial/introspection.adapt.cpp b/src/boost/libs/hana/example/tutorial/introspection.adapt.cpp new file mode 100644 index 000000000..bfdf4453c --- /dev/null +++ b/src/boost/libs/hana/example/tutorial/introspection.adapt.cpp @@ -0,0 +1,100 @@ +// Copyright Louis Dionne 2013-2017 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#include <boost/hana.hpp> + +#include <iostream> +#include <string> +namespace hana = boost::hana; +using namespace hana::literals; +using namespace std::literals; + + +//! [BOOST_HANA_DEFINE_STRUCT] +struct Person { + BOOST_HANA_DEFINE_STRUCT(Person, + (std::string, name), + (int, age) + ); +}; +//! [BOOST_HANA_DEFINE_STRUCT] + +int main() { + +//! [for_each] +Person john{"John", 30}; + +hana::for_each(john, [](auto pair) { + std::cout << hana::to<char const*>(hana::first(pair)) << ": " + << hana::second(pair) << std::endl; +}); + +// name: John +// age: 30 +//! [for_each] + +//! [for_each.fuse] +hana::for_each(john, hana::fuse([](auto name, auto member) { + std::cout << hana::to<char const*>(name) << ": " << member << std::endl; +})); +//! [for_each.fuse] + +#ifdef BOOST_HANA_CONFIG_ENABLE_STRING_UDL + +{ + +//! [at_key] +std::string name = hana::at_key(john, "name"_s); +BOOST_HANA_RUNTIME_CHECK(name == "John"); + +int age = hana::at_key(john, "age"_s); +BOOST_HANA_RUNTIME_CHECK(age == 30); +//! [at_key] + +}{ + +//! [to<map_tag>] +auto map = hana::insert(hana::to<hana::map_tag>(john), hana::make_pair("last name"_s, "Doe"s)); + +std::string name = map["name"_s]; +BOOST_HANA_RUNTIME_CHECK(name == "John"); + +std::string last_name = map["last name"_s]; +BOOST_HANA_RUNTIME_CHECK(last_name == "Doe"); + +int age = map["age"_s]; +BOOST_HANA_RUNTIME_CHECK(age == 30); +//! [to<map_tag>] + +} + +#endif + +} + +//! [BOOST_HANA_ADAPT_STRUCT] +namespace not_my_namespace { + struct Person { + std::string name; + int age; + }; +} + +BOOST_HANA_ADAPT_STRUCT(not_my_namespace::Person, name, age); +//! [BOOST_HANA_ADAPT_STRUCT] + + +//! [BOOST_HANA_ADAPT_ADT] +namespace also_not_my_namespace { + struct Person { + std::string get_name(); + int get_age(); + }; +} + +BOOST_HANA_ADAPT_ADT(also_not_my_namespace::Person, + (name, [](auto const& p) { return p.get_name(); }), + (age, [](auto const& p) { return p.get_age(); }) +); +//! [BOOST_HANA_ADAPT_ADT] diff --git a/src/boost/libs/hana/example/tutorial/introspection.cpp b/src/boost/libs/hana/example/tutorial/introspection.cpp new file mode 100644 index 000000000..3b72db447 --- /dev/null +++ b/src/boost/libs/hana/example/tutorial/introspection.cpp @@ -0,0 +1,158 @@ +// Copyright Louis Dionne 2013-2017 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#include <boost/hana.hpp> + +#include <string> +#include <type_traits> +#include <utility> +namespace hana = boost::hana; + + +struct yes { std::string toString() const { return "yes"; } }; +struct no { }; + +namespace has_toString_then { +//! [has_toString.then] +template <typename T, typename = void> +struct has_toString + : std::false_type +{ }; + +template <typename T> +struct has_toString<T, decltype((void)std::declval<T>().toString())> + : std::true_type +{ }; +//! [has_toString.then] + +static_assert(has_toString<yes>::value, ""); +static_assert(!has_toString<no>::value, ""); +} + +//! [has_toString.now] +auto has_toString = hana::is_valid([](auto&& obj) -> decltype(obj.toString()) { }); +//! [has_toString.now] + +BOOST_HANA_CONSTANT_CHECK(has_toString(yes{})); +BOOST_HANA_CONSTANT_CHECK(hana::not_(has_toString(no{}))); + +namespace optionalToString_then { +//! [optionalToString.then] +template <typename T> +auto optionalToString(T const& obj) + -> std::enable_if_t<decltype(has_toString(obj))::value, std::string> +{ return obj.toString(); } + +template <typename T> +auto optionalToString(T const& obj) + -> std::enable_if_t<decltype(!has_toString(obj))::value, std::string> +{ return "toString not defined"; } +//! [optionalToString.then] + +// make sure they compile +template std::string optionalToString(yes const&); +template std::string optionalToString(no const&); +} + +//! [optionalToString] +template <typename T> +std::string optionalToString(T const& obj) { + return hana::if_(has_toString(obj), + [](auto& x) { return x.toString(); }, + [](auto& x) { return "toString not defined"; } + )(obj); +} +//! [optionalToString] + + +int main() { +BOOST_HANA_RUNTIME_CHECK(optionalToString(yes{}) == "yes"); +BOOST_HANA_RUNTIME_CHECK(optionalToString(no{}) == "toString not defined"); + + +{ + +//! [non_static_member_from_object] +auto has_member = hana::is_valid([](auto&& x) -> decltype((void)x.member) { }); + +struct Foo { int member[4]; }; +struct Bar { }; +BOOST_HANA_CONSTANT_CHECK(has_member(Foo{})); +BOOST_HANA_CONSTANT_CHECK(!has_member(Bar{})); +//! [non_static_member_from_object] + +}{ + +//! [non_static_member_from_type] +auto has_member = hana::is_valid([](auto t) -> decltype( + (void)hana::traits::declval(t).member +) { }); + +struct Foo { int member[4]; }; +struct Bar { }; +BOOST_HANA_CONSTANT_CHECK(has_member(hana::type_c<Foo>)); +BOOST_HANA_CONSTANT_CHECK(!has_member(hana::type_c<Bar>)); +//! [non_static_member_from_type] + +}{ + +//! [nested_type_name] +auto has_member = hana::is_valid([](auto t) -> hana::type< + typename decltype(t)::type::member +//^^^^^^^^ needed because of the dependent context +> { }); + +struct Foo { struct member; /* not defined! */ }; +struct Bar { }; +BOOST_HANA_CONSTANT_CHECK(has_member(hana::type_c<Foo>)); +BOOST_HANA_CONSTANT_CHECK(!has_member(hana::type_c<Bar>)); +//! [nested_type_name] + +} + +} + +namespace static_member { +//! [static_member] +auto has_member = hana::is_valid([](auto t) -> decltype( + (void)decltype(t)::type::member +) { }); + +struct Foo { static int member[4]; }; +struct Bar { }; +BOOST_HANA_CONSTANT_CHECK(has_member(hana::type_c<Foo>)); +BOOST_HANA_CONSTANT_CHECK(!has_member(hana::type_c<Bar>)); +//! [static_member] +} + +namespace nested_template { +//! [nested_template] +auto has_member = hana::is_valid([](auto t) -> decltype(hana::template_< + decltype(t)::type::template member + // ^^^^^^^^ needed because of the dependent context +>) { }); + +struct Foo { template <typename ...> struct member; }; +struct Bar { }; +BOOST_HANA_CONSTANT_CHECK(has_member(hana::type_c<Foo>)); +BOOST_HANA_CONSTANT_CHECK(!has_member(hana::type_c<Bar>)); +//! [nested_template] +} + +namespace template_specialization { +//! [template_specialization] +template <typename T, typename U> +struct Foo; + +template <typename T> +struct Bar; + +auto is_binary_template = hana::is_valid([](auto trait) -> decltype( + trait(hana::type_c<void>, hana::type_c<void>) +) { }); + +BOOST_HANA_CONSTANT_CHECK(is_binary_template(hana::template_<Foo>)); +BOOST_HANA_CONSTANT_CHECK(!is_binary_template(hana::template_<Bar>)); +//! [template_specialization] +} diff --git a/src/boost/libs/hana/example/tutorial/introspection.json.cpp b/src/boost/libs/hana/example/tutorial/introspection.json.cpp new file mode 100644 index 000000000..d81dd001a --- /dev/null +++ b/src/boost/libs/hana/example/tutorial/introspection.json.cpp @@ -0,0 +1,81 @@ +// Copyright Louis Dionne 2013-2017 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#include <boost/hana.hpp> + +#include <iostream> +#include <string> +#include <type_traits> +#include <utility> +namespace hana = boost::hana; +using namespace std::literals; + + +//! [utilities] +template <typename Xs> +std::string join(Xs&& xs, std::string sep) { + return hana::fold(hana::intersperse(std::forward<Xs>(xs), sep), "", hana::_ + hana::_); +} + +std::string quote(std::string s) { return "\"" + s + "\""; } + +template <typename T> +auto to_json(T const& x) -> decltype(std::to_string(x)) { + return std::to_string(x); +} + +std::string to_json(char c) { return quote({c}); } +std::string to_json(std::string s) { return quote(s); } +//! [utilities] + +//! [Struct] +template <typename T> + std::enable_if_t<hana::Struct<T>::value, +std::string> to_json(T const& x) { + auto json = hana::transform(hana::keys(x), [&](auto name) { + auto const& member = hana::at_key(x, name); + return quote(hana::to<char const*>(name)) + " : " + to_json(member); + }); + + return "{" + join(std::move(json), ", ") + "}"; +} +//! [Struct] + +//! [Sequence] +template <typename Xs> + std::enable_if_t<hana::Sequence<Xs>::value, +std::string> to_json(Xs const& xs) { + auto json = hana::transform(xs, [](auto const& x) { + return to_json(x); + }); + + return "[" + join(std::move(json), ", ") + "]"; +} +//! [Sequence] + + +int main() { +//! [usage] +struct Car { + BOOST_HANA_DEFINE_STRUCT(Car, + (std::string, brand), + (std::string, model) + ); +}; + +struct Person { + BOOST_HANA_DEFINE_STRUCT(Person, + (std::string, name), + (std::string, last_name), + (int, age) + ); +}; + +Car bmw{"BMW", "Z3"}, audi{"Audi", "A4"}; +Person john{"John", "Doe", 30}; + +auto tuple = hana::make_tuple(john, audi, bmw); +std::cout << to_json(tuple) << std::endl; +//! [usage] +} diff --git a/src/boost/libs/hana/example/tutorial/introspection.sfinae.cpp b/src/boost/libs/hana/example/tutorial/introspection.sfinae.cpp new file mode 100644 index 000000000..9b987ff9b --- /dev/null +++ b/src/boost/libs/hana/example/tutorial/introspection.sfinae.cpp @@ -0,0 +1,44 @@ +// Copyright Louis Dionne 2013-2017 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#include <boost/hana.hpp> + +#include <string> +#include <vector> +namespace hana = boost::hana; + + +struct yes { std::string toString() const { return "yes"; } }; +struct no { }; + +//! [optionalToString.sfinae] +template <typename T> +std::string optionalToString(T const& obj) { + auto maybe_toString = hana::sfinae([](auto&& x) -> decltype(x.toString()) { + return x.toString(); + }); + + return maybe_toString(obj).value_or("toString not defined"); +} +//! [optionalToString.sfinae] + +int main() { +BOOST_HANA_RUNTIME_CHECK(optionalToString(yes{}) == "yes"); +BOOST_HANA_RUNTIME_CHECK(optionalToString(no{}) == "toString not defined"); + +{ + +//! [maybe_add] +auto maybe_add = hana::sfinae([](auto x, auto y) -> decltype(x + y) { + return x + y; +}); + +maybe_add(1, 2); // hana::just(3) + +std::vector<int> v; +maybe_add(v, "foobar"); // hana::nothing +//! [maybe_add] + +} +} diff --git a/src/boost/libs/hana/example/tutorial/mpl_cheatsheet.cpp b/src/boost/libs/hana/example/tutorial/mpl_cheatsheet.cpp new file mode 100644 index 000000000..d9e87345a --- /dev/null +++ b/src/boost/libs/hana/example/tutorial/mpl_cheatsheet.cpp @@ -0,0 +1,58 @@ +// Copyright Louis Dionne 2013-2017 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#include <boost/hana/assert.hpp> +#include <boost/hana/config.hpp> +#include <boost/hana/equal.hpp> +#include <boost/hana/ext/boost/mpl/vector.hpp> +#include <boost/hana/ext/std/integral_constant.hpp> +#include <boost/hana/integral_constant.hpp> +#include <boost/hana/plus.hpp> +#include <boost/hana/tuple.hpp> + +#include <boost/mpl/fold.hpp> +#include <boost/mpl/if.hpp> +#include <boost/mpl/int.hpp> +#include <boost/mpl/next.hpp> +#include <boost/mpl/placeholders.hpp> +#include <boost/mpl/vector.hpp> + +#include <type_traits> +namespace hana = boost::hana; +namespace mpl = boost::mpl; + + +namespace with_mpl { +//! [mpl] +using types = mpl::vector<long, float, short, float, long, long double>; +using number_of_floats = mpl::fold< + types, + mpl::int_<0>, + mpl::if_<std::is_floating_point<mpl::_2>, + mpl::next<mpl::_1>, + mpl::_1 + > +>::type; +static_assert(number_of_floats::value == 3, ""); +//! [mpl] +} + +namespace with_hana { +//! [hana] +constexpr auto types = hana::tuple_t<long, float, short, float, long, long double>; +BOOST_HANA_CONSTEXPR_LAMBDA auto number_of_floats = hana::fold_left( + types, + hana::int_c<0>, + [](auto count, auto t) { + return hana::if_(hana::trait<std::is_floating_point>(t), + count + hana::int_c<1>, + count + ); + } +); +BOOST_HANA_CONSTANT_CHECK(number_of_floats == hana::int_c<3>); +//! [hana] +} + +int main() { } diff --git a/src/boost/libs/hana/example/tutorial/quickstart.cpp b/src/boost/libs/hana/example/tutorial/quickstart.cpp new file mode 100644 index 000000000..6358e503b --- /dev/null +++ b/src/boost/libs/hana/example/tutorial/quickstart.cpp @@ -0,0 +1,101 @@ +// Copyright Louis Dionne 2013-2017 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +// Make sure `assert` always triggers an assertion +#ifdef NDEBUG +# undef NDEBUG +#endif + +//! [additional_setup] +#include <cassert> +#include <iostream> +#include <string> + +struct Fish { std::string name; }; +struct Cat { std::string name; }; +struct Dog { std::string name; }; +//! [additional_setup] + +//! [includes] +#include <boost/hana.hpp> +namespace hana = boost::hana; +//! [includes] + + +int main() { + +//! [animals] +auto animals = hana::make_tuple(Fish{"Nemo"}, Cat{"Garfield"}, Dog{"Snoopy"}); +//! [animals] + +//! [algorithms] +using namespace hana::literals; + +// Access tuple elements with operator[] instead of std::get. +Cat garfield = animals[1_c]; + +// Perform high level algorithms on tuples (this is like std::transform) +auto names = hana::transform(animals, [](auto a) { + return a.name; +}); + +assert(hana::reverse(names) == hana::make_tuple("Snoopy", "Garfield", "Nemo")); +//! [algorithms] + + +//! [type-level] +auto animal_types = hana::make_tuple(hana::type_c<Fish*>, hana::type_c<Cat&>, hana::type_c<Dog>); + +auto no_pointers = hana::remove_if(animal_types, [](auto a) { + return hana::traits::is_pointer(a); +}); + +static_assert(no_pointers == hana::make_tuple(hana::type_c<Cat&>, hana::type_c<Dog>), ""); +//! [type-level] + + +//! [has_name] +auto has_name = hana::is_valid([](auto&& x) -> decltype((void)x.name) { }); + +static_assert(has_name(garfield), ""); +static_assert(!has_name(1), ""); +//! [has_name] + +#if 0 +//! [screw_up] +auto serialize = [](std::ostream& os, auto const& object) { + hana::for_each(os, [&](auto member) { + // ^^ oopsie daisy! + os << member << std::endl; + }); +}; +//! [screw_up] +#endif + +//! [serialization] +// 1. Give introspection capabilities to 'Person' +struct Person { + BOOST_HANA_DEFINE_STRUCT(Person, + (std::string, name), + (int, age) + ); +}; + +// 2. Write a generic serializer (bear with std::ostream for the example) +auto serialize = [](std::ostream& os, auto const& object) { + hana::for_each(hana::members(object), [&](auto member) { + os << member << std::endl; + }); +}; + +// 3. Use it +Person john{"John", 30}; +serialize(std::cout, john); + +// output: +// John +// 30 +//! [serialization] + +} diff --git a/src/boost/libs/hana/example/tutorial/quickstart.switchAny.cpp b/src/boost/libs/hana/example/tutorial/quickstart.switchAny.cpp new file mode 100644 index 000000000..4456aef32 --- /dev/null +++ b/src/boost/libs/hana/example/tutorial/quickstart.switchAny.cpp @@ -0,0 +1,105 @@ +// Copyright Louis Dionne 2013-2017 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +// Make sure `assert` always triggers an assertion +#ifdef NDEBUG +# undef NDEBUG +#endif + +//! [full] +#include <boost/hana.hpp> + +#include <boost/any.hpp> +#include <cassert> +#include <string> +#include <typeindex> +#include <typeinfo> +#include <utility> +namespace hana = boost::hana; + +//! [cases] +template <typename T> +auto case_ = [](auto f) { + return hana::make_pair(hana::type_c<T>, f); +}; + +struct default_t; +auto default_ = case_<default_t>; +//! [cases] + +//! [process] +template <typename Any, typename Default> +auto process(Any&, std::type_index const&, Default& default_) { + return default_(); +} + +template <typename Any, typename Default, typename Case, typename ...Rest> +auto process(Any& a, std::type_index const& t, Default& default_, + Case& case_, Rest& ...rest) +{ + using T = typename decltype(+hana::first(case_))::type; + return t == typeid(T) ? hana::second(case_)(*boost::unsafe_any_cast<T>(&a)) + : process(a, t, default_, rest...); +} +//! [process] + +//! [switch_] +template <typename Any> +auto switch_(Any& a) { + return [&a](auto ...cases_) { + auto cases = hana::make_tuple(cases_...); + + auto default_ = hana::find_if(cases, [](auto const& c) { + return hana::first(c) == hana::type_c<default_t>; + }); + static_assert(default_ != hana::nothing, + "switch is missing a default_ case"); + + auto rest = hana::filter(cases, [](auto const& c) { + return hana::first(c) != hana::type_c<default_t>; + }); + + return hana::unpack(rest, [&](auto& ...rest) { + return process(a, a.type(), hana::second(*default_), rest...); + }); + }; +} +//! [switch_] +//! [full] + + +int main() { +using namespace std::literals; + +{ + +//! [usage] +boost::any a = 'x'; +std::string r = switch_(a)( + case_<int>([](auto i) { return "int: "s + std::to_string(i); }), + case_<char>([](auto c) { return "char: "s + std::string{c}; }), + default_([] { return "unknown"s; }) +); + +assert(r == "char: x"s); +//! [usage] + +}{ + +//! [result_inference] +boost::any a = 'x'; +auto r = switch_(a)( + case_<int>([](auto) -> int { return 1; }), + case_<char>([](auto) -> long { return 2l; }), + default_([]() -> long long { return 3ll; }) +); + +// r is inferred to be a long long +static_assert(std::is_same<decltype(r), long long>{}, ""); +assert(r == 2ll); +//! [result_inference] + +} + +} diff --git a/src/boost/libs/hana/example/tutorial/rationale.container.cpp b/src/boost/libs/hana/example/tutorial/rationale.container.cpp new file mode 100644 index 000000000..9d419af15 --- /dev/null +++ b/src/boost/libs/hana/example/tutorial/rationale.container.cpp @@ -0,0 +1,52 @@ +// Copyright Louis Dionne 2013-2017 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#include <boost/hana.hpp> + +#include <boost/fusion/include/find_if.hpp> +#include <boost/fusion/include/make_vector.hpp> +#include <boost/mpl/quote.hpp> + +#include <type_traits> +namespace fusion = boost::fusion; +namespace mpl = boost::mpl; +namespace hana = boost::hana; + + +int main() { + +{ + +//! [hana] +auto tuple = hana::make_tuple(1, 'x', 3.4f); + +auto result = hana::find_if(tuple, [](auto const& x) { + return hana::traits::is_integral(hana::typeid_(x)); +}); +//! [hana] +(void)result; + +#if 0 +//! [hana-explicit] +some_type result = hana::find_if(tuple, [](auto const& x) { + return hana::traits::is_integral(hana::typeid_(x)); +}); +//! [hana-explicit] +#endif + +}{ + +//! [fusion] +using Container = fusion::result_of::make_vector<int, char, float>::type; +Container tuple = fusion::make_vector(1, 'x', 3.4f); + +using Predicate = mpl::quote1<std::is_integral>; +using Result = fusion::result_of::find_if<Container, Predicate>::type; +Result result = fusion::find_if<Predicate>(tuple); +//! [fusion] +(void)result; + +} + +} diff --git a/src/boost/libs/hana/example/tutorial/tag_dispatching.cpp b/src/boost/libs/hana/example/tutorial/tag_dispatching.cpp new file mode 100644 index 000000000..19ca9d156 --- /dev/null +++ b/src/boost/libs/hana/example/tutorial/tag_dispatching.cpp @@ -0,0 +1,170 @@ +// Copyright Louis Dionne 2013-2017 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#include <boost/hana/assert.hpp> +#include <boost/hana/core/tag_of.hpp> +#include <boost/hana/integral_constant.hpp> +#include <boost/hana/minus.hpp> +#include <boost/hana/not_equal.hpp> +#include <boost/hana/tuple.hpp> + +#include <cstddef> +#include <iostream> +#include <sstream> +namespace hana = boost::hana; + + +//! [setup] +template <typename Tag> +struct print_impl { + template <typename X> + static void apply(std::ostream&, X const&) { + // possibly some default implementation + } +}; + +template <typename X> +void print(std::ostream& os, X x) { + using Tag = typename hana::tag_of<X>::type; + print_impl<Tag>::apply(os, x); +} +//! [setup] + +//! [vector] +struct vector_tag; + +struct vector0 { + using hana_tag = vector_tag; + static constexpr std::size_t size = 0; +}; + +template <typename T1> +struct vector1 { + T1 t1; + using hana_tag = vector_tag; + static constexpr std::size_t size = 1; + + template <typename Index> + auto const& operator[](Index i) const { + static_assert(i == 0u, "index out of bounds"); + return t1; + } +}; + +template <typename T1, typename T2> +struct vector2 { + T1 t1; T2 t2; + using hana_tag = vector_tag; + static constexpr std::size_t size = 2; + + // Using Hana as a backend to simplify the example. + template <typename Index> + auto const& operator[](Index i) const { + return *hana::make_tuple(&t1, &t2)[i]; + } +}; + +// and so on... +//! [vector] + +//! [customize] +template <> +struct print_impl<vector_tag> { + template <typename vectorN> + static void apply(std::ostream& os, vectorN xs) { + auto N = hana::size_c<vectorN::size>; + + os << "["; + N.times.with_index([&](auto i) { + os << xs[i]; + if (i != N - hana::size_c<1>) os << ", "; + }); + os << "]"; + } +}; +//! [customize] + +#if 0 +//! [customize-when] +template <typename Tag> +struct print_impl<Tag, hana::when<Tag represents some kind of sequence>> { + template <typename Seq> + static void apply(std::ostream& os, Seq xs) { + // Some implementation for any sequence + } +}; +//! [customize-when] +#endif + +int main() { + { + std::stringstream ss; + vector0 v0; + print(ss, v0); + BOOST_HANA_RUNTIME_CHECK(ss.str() == "[]"); + } + + { + std::stringstream ss; + vector1<int> v1{1}; + print(ss, v1); + BOOST_HANA_RUNTIME_CHECK(ss.str() == "[1]"); + } + + { + std::stringstream ss; + vector2<int, char> v2{1, 'x'}; + print(ss, v2); + BOOST_HANA_RUNTIME_CHECK(ss.str() == "[1, x]"); + } +} + +namespace old_way { +//! [old_way] +void print(std::ostream& os, vector0) +{ os << "[]"; } + +template <typename T1> +void print(std::ostream& os, vector1<T1> v) +{ os << "[" << v.t1 << "]"; } + +template <typename T1, typename T2> +void print(std::ostream& os, vector2<T1, T2> v) +{ os << "[" << v.t1 << ", " << v.t2 << "]"; } + +// and so on... +//! [old_way] +} + +namespace preconditions { +//! [preconditions] +template <typename X> +void print(std::ostream& os, X x) { + // **** check some precondition **** + + // The precondition only has to be checked here; implementations + // can assume their arguments to always be sane. + + using Tag = typename hana::tag_of<X>::type; + print_impl<Tag>::apply(os, x); +} +//! [preconditions] +} + +namespace function_objects { +//! [function_objects] +// Defining a function object is only needed once and implementations do not +// have to worry about static initialization and other painful tricks. +struct print_t { + template <typename X> + void operator()(std::ostream& os, X x) const { + using Tag = typename hana::tag_of<X>::type; + print_impl<Tag>::apply(os, x); + } +}; +constexpr print_t print{}; +//! [function_objects] + +static_assert(sizeof(print) || true, "remove unused variable print warning"); +} diff --git a/src/boost/libs/hana/example/tutorial/type.cpp b/src/boost/libs/hana/example/tutorial/type.cpp new file mode 100644 index 000000000..92010d499 --- /dev/null +++ b/src/boost/libs/hana/example/tutorial/type.cpp @@ -0,0 +1,260 @@ +// Copyright Louis Dionne 2013-2017 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#include <boost/hana.hpp> +#include <boost/hana/ext/std/integral_constant.hpp> + +#include <boost/mpl/copy_if.hpp> +#include <boost/mpl/equal.hpp> +#include <boost/mpl/less.hpp> +#include <boost/mpl/min_element.hpp> +#include <boost/mpl/or.hpp> +#include <boost/mpl/placeholders.hpp> +#include <boost/mpl/sizeof.hpp> +#include <boost/mpl/vector.hpp> + +#include <boost/fusion/include/at_key.hpp> +#include <boost/fusion/include/equal_to.hpp> +#include <boost/fusion/include/filter_if.hpp> +#include <boost/fusion/include/make_map.hpp> +#include <boost/fusion/include/make_vector.hpp> + +#include <string> +#include <type_traits> +#include <vector> +namespace fusion = boost::fusion; +namespace mpl = boost::mpl; +namespace hana = boost::hana; +using namespace hana::literals; + + +template <int n> +struct storage { char weight[n]; }; + +int main() { + +{ + +//! [tuple] +auto types = hana::make_tuple(hana::type_c<int*>, hana::type_c<char&>, hana::type_c<void>); +auto char_ref = types[1_c]; + +BOOST_HANA_CONSTANT_CHECK(char_ref == hana::type_c<char&>); +//! [tuple] + +}{ + +//! [filter.MPL] +using types = mpl::vector<int, char&, void*>; +using ts = mpl::copy_if<types, mpl::or_<std::is_pointer<mpl::_1>, + std::is_reference<mpl::_1>>>::type; +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// placeholder expression + +static_assert(mpl::equal<ts, mpl::vector<char&, void*>>::value, ""); +//! [filter.MPL] + +}{ + +using hana::traits::is_pointer; // the traits namespace was not introduced +using hana::traits::is_reference; // yet, so we use unqualified names for now + +//! [filter.Hana] +auto types = hana::tuple_t<int*, char&, void>; + +auto ts = hana::filter(types, [](auto t) { + return is_pointer(t) || is_reference(t); +}); + +BOOST_HANA_CONSTANT_CHECK(ts == hana::tuple_t<int*, char&>); +//! [filter.Hana] + +}{ + +//! [single_library.then] +// types (MPL) +using types = mpl::vector<int*, char&, void>; +using ts = mpl::copy_if<types, mpl::or_<std::is_pointer<mpl::_1>, + std::is_reference<mpl::_1>>>::type; + +// values (Fusion) +auto values = fusion::make_vector(1, 'c', nullptr, 3.5); +auto vs = fusion::filter_if<std::is_integral<mpl::_1>>(values); +//! [single_library.then] + +static_assert(mpl::equal<ts, mpl::vector<int*, char&>>::value, ""); +BOOST_HANA_RUNTIME_CHECK(vs == fusion::make_vector(1, 'c')); + +}{ + +using hana::traits::is_pointer; +using hana::traits::is_reference; +using hana::traits::is_integral; + +//! [single_library.Hana] +// types +auto types = hana::tuple_t<int*, char&, void>; +auto ts = hana::filter(types, [](auto t) { + return is_pointer(t) || is_reference(t); +}); + +// values +auto values = hana::make_tuple(1, 'c', nullptr, 3.5); +auto vs = hana::filter(values, [](auto const& t) { + return is_integral(hana::typeid_(t)); +}); +//! [single_library.Hana] + +BOOST_HANA_CONSTANT_CHECK(ts == hana::tuple_t<int*, char&>); +BOOST_HANA_RUNTIME_CHECK(vs == hana::make_tuple(1, 'c')); + +}{ + +//! [make_map.Fusion] +auto map = fusion::make_map<char, int, long, float, double, void>( + "char", "int", "long", "float", "double", "void" +); + +std::string Int = fusion::at_key<int>(map); +BOOST_HANA_RUNTIME_CHECK(Int == "int"); +//! [make_map.Fusion] + +}{ + +//! [make_map.Hana] +auto map = hana::make_map( + hana::make_pair(hana::type_c<char>, "char"), + hana::make_pair(hana::type_c<int>, "int"), + hana::make_pair(hana::type_c<long>, "long"), + hana::make_pair(hana::type_c<float>, "float"), + hana::make_pair(hana::type_c<double>, "double") +); + +std::string Int = map[hana::type_c<int>]; +BOOST_HANA_RUNTIME_CHECK(Int == "int"); +//! [make_map.Hana] + +}{ + +using hana::traits::add_pointer; + +//! [skip_first_step] +auto types = hana::tuple_t<int*, char&, void>; // first step skipped + +auto pointers = hana::transform(types, [](auto t) { + return add_pointer(t); +}); +//! [skip_first_step] + +BOOST_HANA_CONSTANT_CHECK(pointers == hana::tuple_t<int**, char*, void*>); + +}{ + +//! [traits] +BOOST_HANA_CONSTANT_CHECK(hana::traits::add_pointer(hana::type_c<int>) == hana::type_c<int*>); +BOOST_HANA_CONSTANT_CHECK(hana::traits::common_type(hana::type_c<int>, hana::type_c<long>) == hana::type_c<long>); +BOOST_HANA_CONSTANT_CHECK(hana::traits::is_integral(hana::type_c<int>)); + +auto types = hana::tuple_t<int, char, long>; +BOOST_HANA_CONSTANT_CHECK(hana::all_of(types, hana::traits::is_integral)); +//! [traits] + +}{ + +//! [extent] +auto extent = [](auto t, auto n) { + return std::extent<typename decltype(t)::type, hana::value(n)>{}; +}; + +BOOST_HANA_CONSTANT_CHECK(extent(hana::type_c<char>, hana::int_c<1>) == hana::size_c<0>); +BOOST_HANA_CONSTANT_CHECK(extent(hana::type_c<char[1][2]>, hana::int_c<1>) == hana::size_c<2>); +//! [extent] + +} + +} + +namespace mpl_based { +//! [smallest.MPL] +template <typename ...T> +struct smallest + : mpl::deref< + typename mpl::min_element< + mpl::vector<T...>, + mpl::less<mpl::sizeof_<mpl::_1>, mpl::sizeof_<mpl::_2>> + >::type + > +{ }; + +template <typename ...T> +using smallest_t = typename smallest<T...>::type; + +static_assert(std::is_same< + smallest_t<char, long, long double>, + char +>::value, ""); +//! [smallest.MPL] + +static_assert(std::is_same< + smallest_t<storage<3>, storage<1>, storage<2>>, + storage<1> +>::value, ""); +} // end namespace mpl_based + +namespace hana_based { +//! [smallest.Hana] +template <typename ...T> +auto smallest = hana::minimum(hana::make_tuple(hana::type_c<T>...), [](auto t, auto u) { + return hana::sizeof_(t) < hana::sizeof_(u); +}); + +template <typename ...T> +using smallest_t = typename decltype(smallest<T...>)::type; + +static_assert(std::is_same< + smallest_t<char, long, long double>, char +>::value, ""); +//! [smallest.Hana] + +static_assert(std::is_same< + smallest_t<storage<3>, storage<1>, storage<2>>, + storage<1> +>::value, ""); +} // end namespace hana_based + + +namespace metafunction1 { +//! [metafunction1] +template <template <typename> class F, typename T> +constexpr auto metafunction(hana::basic_type<T> const&) +{ return hana::type_c<typename F<T>::type>; } + +auto t = hana::type_c<int>; +BOOST_HANA_CONSTANT_CHECK(metafunction<std::add_pointer>(t) == hana::type_c<int*>); +//! [metafunction1] +} + +namespace metafunction2 { +//! [metafunction2] +template <template <typename ...> class F, typename ...T> +constexpr auto metafunction(hana::basic_type<T> const& ...) +{ return hana::type_c<typename F<T...>::type>; } + +BOOST_HANA_CONSTANT_CHECK( + metafunction<std::common_type>(hana::type_c<int>, hana::type_c<long>) == hana::type_c<long> +); +//! [metafunction2] +} + +namespace _template { +//! [template_] +template <template <typename ...> class F, typename ...T> +constexpr auto template_(hana::basic_type<T> const& ...) +{ return hana::type_c<F<T...>>; } + +BOOST_HANA_CONSTANT_CHECK( + template_<std::vector>(hana::type_c<int>) == hana::type_c<std::vector<int>> +); +//! [template_] +} |