stabilize build system: depends, installer, boost/bdb fixes, cross targets groundwork

This commit is contained in:
2026-02-24 18:38:47 +00:00
parent da8c28aaeb
commit 65cb2619a7
13106 changed files with 2484322 additions and 1804 deletions
@@ -0,0 +1,50 @@
/*!
@file
Forward declares `boost::hana::accessors`.
@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)
*/
#ifndef BOOST_HANA_FWD_ACCESSORS_HPP
#define BOOST_HANA_FWD_ACCESSORS_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Returns a `Sequence` of pairs representing the accessors of the
//! data structure.
//! @ingroup group-Struct
//!
//! Given a `Struct` `S`, `accessors<S>()` is a `Sequence` of `Product`s
//! where the first element of each pair is the "name" of a member of
//! the `Struct`, and the second element of each pair is a function that
//! can be used to access that member when given an object of the proper
//! data type. As described in the global documentation for `Struct`, the
//! accessor functions in this sequence must be move-independent.
//!
//!
//! Example
//! -------
//! @include example/accessors.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
template <typename S>
constexpr auto accessors = []() {
return tag-dispatched;
};
#else
template <typename S, typename = void>
struct accessors_impl : accessors_impl<S, when<true>> { };
template <typename S>
struct accessors_t;
template <typename S>
constexpr accessors_t<S> accessors{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_ACCESSORS_HPP
@@ -0,0 +1,48 @@
/*!
@file
Documents the `BOOST_HANA_ADAPT_ADT` macro.
@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)
*/
#ifndef BOOST_HANA_FWD_ADAPT_ADT_HPP
#define BOOST_HANA_FWD_ADAPT_ADT_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
// Note:
// The weird definition as a variable seems to exploit a glitch in Doxygen
// which makes the macro appear in the related objects of Struct (as we
// want it to).
//! Defines a model of `Struct` with the given accessors.
//! @ingroup group-Struct
//!
//! Using this macro at _global scope_ will define a model of the `Struct`
//! concept for the given type. This can be used to easily adapt existing
//! user-defined types in a ad-hoc manner. Unlike `BOOST_HANA_ADAPT_STRUCT`,
//! this macro requires specifying the way to retrieve each member by
//! providing a function that does the extraction.
//!
//! @note
//! This macro only works if the tag of the user-defined type `T` is `T`
//! itself. This is the case unless you specifically asked for something
//! different; see `tag_of`'s documentation.
//!
//!
//! Example
//! -------
//! @include example/adapt_adt.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
auto BOOST_HANA_ADAPT_ADT(...) = ;
#define BOOST_HANA_ADAPT_ADT(Name, ...) see documentation
#else
// defined in <boost/hana/adapt_adt.hpp>
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_ADAPT_ADT_HPP
@@ -0,0 +1,48 @@
/*!
@file
Documents the `BOOST_HANA_ADAPT_STRUCT` macro.
@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)
*/
#ifndef BOOST_HANA_FWD_ADAPT_STRUCT_HPP
#define BOOST_HANA_FWD_ADAPT_STRUCT_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
// Note:
// The weird definition as a variable seems to exploit a glitch in Doxygen
// which makes the macro appear in the related objects of Struct (as we
// want it to).
//! Defines a model of `Struct` with the given members.
//! @ingroup group-Struct
//!
//! Using this macro at _global scope_ will define a model of the `Struct`
//! concept for the given type. This can be used to easily adapt existing
//! user-defined types in a ad-hoc manner. Unlike the
//! `BOOST_HANA_DEFINE_STRUCT` macro, this macro does not
//! require the types of the members to be specified.
//!
//! @note
//! This macro only works if the tag of the user-defined type `T` is `T`
//! itself. This is the case unless you specifically asked for something
//! different; see `tag_of`'s documentation.
//!
//!
//! Example
//! -------
//! @include example/adapt_struct.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
auto BOOST_HANA_ADAPT_STRUCT(...) = ;
#define BOOST_HANA_ADAPT_STRUCT(Name, ...) see documentation
#else
// defined in <boost/hana/adapt_struct.hpp>
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_ADAPT_STRUCT_HPP
@@ -0,0 +1,64 @@
/*!
@file
Forward declares `boost::hana::adjust`.
@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)
*/
#ifndef BOOST_HANA_FWD_ADJUST_HPP
#define BOOST_HANA_FWD_ADJUST_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Apply a function on all the elements of a structure that compare
//! equal to some value.
//! @ingroup group-Functor
//!
//!
//! Signature
//! ---------
//! Given `F` a Functor and `U` a type that can be compared with `T`'s,
//! the signature is
//! \f$
//! \mathtt{adjust} : F(T) \times U \times (T \to T) \to F(T)
//! \f$
//!
//! @param xs
//! The structure to adjust with `f`.
//!
//! @param value
//! An object that is compared with each element `x` of the structure.
//! Elements of the structure that compare equal to `value` are adjusted
//! with the `f` function.
//!
//! @param f
//! A function called as `f(x)` on the element(s) of the structure that
//! compare equal to `value`.
//!
//!
//! Example
//! -------
//! @include example/adjust.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto adjust = [](auto&& xs, auto&& value, auto&& f) {
return tag-dispatched;
};
#else
template <typename Xs, typename = void>
struct adjust_impl : adjust_impl<Xs, when<true>> { };
struct adjust_t {
template <typename Xs, typename Value, typename F>
constexpr auto operator()(Xs&& xs, Value&& value, F&& f) const;
};
constexpr adjust_t adjust{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_ADJUST_HPP
@@ -0,0 +1,69 @@
/*!
@file
Forward declares `boost::hana::adjust_if`.
@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)
*/
#ifndef BOOST_HANA_FWD_ADJUST_IF_HPP
#define BOOST_HANA_FWD_ADJUST_IF_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Apply a function on all the elements of a structure satisfying a predicate.
//! @ingroup group-Functor
//!
//! Given a Functor, a predicate `pred` and a function `f`, `adjust_if`
//! will _adjust_ the elements of the Functor that satisfy the predicate
//! with the function `f`. In other words, `adjust_if` will return a new
//! Functor equal to the original one, except that the elements satisfying
//! the predicate will be transformed with the given function. Elements
//! for which the predicate is not satisfied are left untouched, and they
//! are kept as-is in the resulting Functor.
//!
//!
//! Signature
//! ---------
//! Given a `Functor` `F` and a `Logical` `Bool`, the signature is
//! \f$
//! \mathtt{adjust_if} : F(T) \times (T \to Bool) \times (T \to T) \to F(T)
//! \f$
//!
//! @param xs
//! The structure to adjust with `f`.
//!
//! @param pred
//! A function called as `pred(x)` for each element of the Functor,
//! and returning whether `f` should be applied on that element.
//!
//! @param f
//! A function called as `f(x)` on the element(s) of the Functor that
//! satisfy the predicate.
//!
//!
//! Example
//! -------
//! @include example/adjust_if.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto adjust_if = [](auto&& xs, auto const& pred, auto const& f) {
return tag-dispatched;
};
#else
template <typename Xs, typename = void>
struct adjust_if_impl : adjust_if_impl<Xs, when<true>> { };
struct adjust_if_t {
template <typename Xs, typename Pred, typename F>
constexpr auto operator()(Xs&& xs, Pred const& pred, F const& f) const;
};
constexpr adjust_if_t adjust_if{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_ADJUST_IF_HPP
@@ -0,0 +1,46 @@
/*!
@file
Forward declares `boost::hana::all`.
@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)
*/
#ifndef BOOST_HANA_FWD_ALL_HPP
#define BOOST_HANA_FWD_ALL_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Returns whether all the keys of the structure are true-valued.
//! @ingroup group-Searchable
//!
//! The keys of the structure must be `Logical`s. If the structure is not
//! finite, a false-valued key must appear at a finite "index" in order
//! for this method to finish.
//!
//!
//! Example
//! -------
//! @include example/all.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto all = [](auto&& xs) {
return tag-dispatched;
};
#else
template <typename S, typename = void>
struct all_impl : all_impl<S, when<true>> { };
struct all_t {
template <typename Xs>
constexpr auto operator()(Xs&& xs) const;
};
constexpr all_t all{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_ALL_HPP
@@ -0,0 +1,54 @@
/*!
@file
Forward declares `boost::hana::all_of`.
@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)
*/
#ifndef BOOST_HANA_FWD_ALL_OF_HPP
#define BOOST_HANA_FWD_ALL_OF_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Returns whether all the keys of the structure satisfy the `predicate`.
//! @ingroup group-Searchable
//!
//! If the structure is not finite, `predicate` has to return a false-
//! valued `Logical` after looking at a finite number of keys for this
//! method to finish.
//!
//!
//! @param xs
//! The structure to search.
//!
//! @param predicate
//! A function called as `predicate(k)`, where `k` is a key of the
//! structure, and returning a `Logical`.
//!
//!
//! Example
//! -------
//! @include example/all_of.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto all_of = [](auto&& xs, auto&& predicate) {
return tag-dispatched;
};
#else
template <typename S, typename = void>
struct all_of_impl : all_of_impl<S, when<true>> { };
struct all_of_t {
template <typename Xs, typename Pred>
constexpr auto operator()(Xs&& xs, Pred&& pred) const;
};
constexpr all_of_t all_of{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_ALL_OF_HPP
@@ -0,0 +1,53 @@
/*!
@file
Forward declares `boost::hana::and_`.
@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)
*/
#ifndef BOOST_HANA_FWD_AND_HPP
#define BOOST_HANA_FWD_AND_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Return whether all the arguments are true-valued.
//! @ingroup group-Logical
//!
//! `and_` can be called with one argument or more. When called with
//! two arguments, `and_` uses tag-dispatching to find the right
//! implementation. Otherwise,
//! @code
//! and_(x) == x
//! and_(x, y, ...z) == and_(and_(x, y), z...)
//! @endcode
//!
//!
//! Example
//! -------
//! @include example/and.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto and_ = [](auto&& x, auto&& ...y) -> decltype(auto) {
return tag-dispatched;
};
#else
template <typename L, typename = void>
struct and_impl : and_impl<L, when<true>> { };
struct and_t {
template <typename X, typename Y>
constexpr decltype(auto) operator()(X&& x, Y&& y) const;
template <typename X, typename ...Y>
constexpr decltype(auto) operator()(X&& x, Y&& ...y) const;
};
constexpr and_t and_{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_AND_HPP
@@ -0,0 +1,46 @@
/*!
@file
Forward declares `boost::hana::any`.
@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)
*/
#ifndef BOOST_HANA_FWD_ANY_HPP
#define BOOST_HANA_FWD_ANY_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Returns whether any key of the structure is true-valued.
//! @ingroup group-Searchable
//!
//! The keys of the structure must be `Logical`s. If the structure is not
//! finite, a true-valued key must appear at a finite "index" in order for
//! this method to finish.
//!
//!
//! Example
//! -------
//! @include example/any.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto any = [](auto&& xs) {
return tag-dispatched;
};
#else
template <typename S, typename = void>
struct any_impl : any_impl<S, when<true>> { };
struct any_t {
template <typename Xs>
constexpr auto operator()(Xs&& xs) const;
};
constexpr any_t any{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_ANY_HPP
@@ -0,0 +1,53 @@
/*!
@file
Forward declares `boost::hana::any_of`.
@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)
*/
#ifndef BOOST_HANA_FWD_ANY_OF_HPP
#define BOOST_HANA_FWD_ANY_OF_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Returns whether any key of the structure satisfies the `predicate`.
//! @ingroup group-Searchable
//!
//! If the structure is not finite, `predicate` has to be satisfied
//! after looking at a finite number of keys for this method to finish.
//!
//!
//! @param xs
//! The structure to search.
//!
//! @param predicate
//! A function called as `predicate(k)`, where `k` is a key of the
//! structure, and returning a `Logical`.
//!
//!
//! Example
//! -------
//! @include example/any_of.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto any_of = [](auto&& xs, auto&& predicate) {
return tag-dispatched;
};
#else
template <typename S, typename = void>
struct any_of_impl : any_of_impl<S, when<true>> { };
struct any_of_t {
template <typename Xs, typename Pred>
constexpr auto operator()(Xs&& xs, Pred&& pred) const;
};
constexpr any_of_t any_of{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_ANY_OF_HPP
@@ -0,0 +1,82 @@
/*!
@file
Forward declares `boost::hana::ap`.
@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)
*/
#ifndef BOOST_HANA_FWD_AP_HPP
#define BOOST_HANA_FWD_AP_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Lifted application.
//! @ingroup group-Applicative
//!
//! Specifically, `ap` applies a structure containing functions to a
//! structure containing values, and returns a new structure containing
//! values. The exact way in which the functions are applied to the values
//! depends on the `Applicative`.
//!
//! `ap` can be called with two arguments or more; the functions in the `f`
//! structure are curried and then applied to the values in each `x...`
//! structure using the binary form of `ap`. Note that this requires the
//! number of `x...` must match the arity of the functions in the `f`
//! structure. In other words, `ap(f, x1, ..., xN)` is equivalent to
//! @code
//! ((f' <ap> x1) <ap> x2) ... <ap> xN
//! @endcode
//! where `f'` is `f` but containing curried functions instead and
//! `x <ap> y` is just `ap(x, y)` written in infix notation to emphasize
//! the left associativity.
//!
//!
//! Signature
//! ---------
//! Given an Applicative `A`, the signature is
//! @f$ \mathtt{ap} : A(T_1 \times \cdots \times T_n \to U)
//! \times A(T_1) \times \cdots \times A(T_n)
//! \to A(U) @f$.
//!
//! @param f
//! A structure containing function(s).
//!
//! @param x...
//! Structure(s) containing value(s) and on which `f` is applied. The
//! number of structures must match the arity of the functions in the
//! `f` structure.
//!
//!
//! Example
//! -------
//! @include example/ap.cpp
//!
//! @todo
//! Consider giving access to all the arguments to the tag-dispatched
//! implementation for performance purposes.
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto ap = [](auto&& f, auto&& ...x) -> decltype(auto) {
return tag-dispatched;
};
#else
template <typename A, typename = void>
struct ap_impl : ap_impl<A, when<true>> { };
struct ap_t {
template <typename F, typename X>
constexpr decltype(auto) operator()(F&& f, X&& x) const;
template <typename F, typename ...Xs>
constexpr decltype(auto) operator()(F&& f, Xs&& ...xs) const;
};
constexpr ap_t ap{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_AP_HPP
@@ -0,0 +1,68 @@
/*!
@file
Forward declares `boost::hana::append`.
@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)
*/
#ifndef BOOST_HANA_FWD_APPEND_HPP
#define BOOST_HANA_FWD_APPEND_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Append an element to a monadic structure.
//! @ingroup group-MonadPlus
//!
//! Given an element `x` and a monadic structure `xs`, `append` returns a
//! new monadic structure which is the result of lifting `x` into the
//! monadic structure and then combining that (to the right) with `xs`.
//! In other words,
//! @code
//! append(xs, x) == concat(xs, lift<Xs>(x))
//! @endcode
//! where `Xs` is the tag of `xs`. For sequences, this has the intuitive
//! behavior of simply appending an element to the end of the sequence,
//! hence the name.
//!
//! > #### Rationale for not calling this `push_back`
//! > See the rationale for using `prepend` instead of `push_front`.
//!
//!
//! Signature
//! ---------
//! Given a MonadPlus `M`, the signature is
//! @f$ \mathtt{append} : M(T) \times T \to M(T) @f$.
//!
//! @param xs
//! A monadic structure that will be combined to the left of the element.
//!
//! @param x
//! An element to combine to the right of the monadic structure.
//!
//!
//! Example
//! -------
//! @include example/append.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto append = [](auto&& xs, auto&& x) {
return tag-dispatched;
};
#else
template <typename M, typename = void>
struct append_impl : append_impl<M, when<true>> { };
struct append_t {
template <typename Xs, typename X>
constexpr auto operator()(Xs&& xs, X&& x) const;
};
constexpr append_t append{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_APPEND_HPP
@@ -0,0 +1,89 @@
/*!
@file
Forward declares `boost::hana::at` and `boost::hana::at_c`.
@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)
*/
#ifndef BOOST_HANA_FWD_AT_HPP
#define BOOST_HANA_FWD_AT_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
#include <cstddef>
BOOST_HANA_NAMESPACE_BEGIN
//! Returns the `n`th element of an iterable.
//! @ingroup group-Iterable
//!
//! Given an `Iterable` and an `IntegralConstant` index, `at` returns the
//! element located at the index in the linearization of the iterable.
//! Specifically, given an iterable `xs` with a linearization of
//! `[x1, ..., xN]`, `at(xs, k)` is equivalent to `xk`.
//!
//! If the `Iterable` actually stores the elements it contains, `at` is
//! required to return a lvalue reference, a lvalue reference to const
//! or a rvalue reference to the matching element, where the type of
//! reference must match that of the iterable passed to `at`. If the
//! `Iterable` does not store the elements it contains (i.e. it generates
//! them on demand), this requirement is dropped.
//!
//!
//! @param xs
//! The iterable in which an element is retrieved. The iterable must
//! contain at least `n + 1` elements.
//!
//! @param n
//! A non-negative `IntegralConstant` representing the 0-based index of
//! the element to return. It is an error to call `at` with an index that
//! out of bounds of the iterable.
//!
//!
//! Example
//! -------
//! @include example/at.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto at = [](auto&& xs, auto const& n) -> decltype(auto) {
return tag-dispatched;
};
#else
template <typename It, typename = void>
struct at_impl : at_impl<It, when<true>> { };
struct at_t {
template <typename Xs, typename N>
constexpr decltype(auto) operator()(Xs&& xs, N const& n) const;
};
constexpr at_t at{};
#endif
//! Equivalent to `at`; provided for convenience.
//! @ingroup group-Iterable
//!
//!
//! @note
//! `hana::at_c<n>` is an overloaded function, not a function object.
//! Hence, it can't be passed to higher-order algorithms. This is done
//! for compile-time performance reasons.
//!
//!
//! Example
//! -------
//! @include example/at_c.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
template <std::size_t n>
constexpr auto at_c = [](auto&& xs) {
return hana::at(forwarded(xs), hana::size_c<n>);
};
#else
template <std::size_t n, typename Xs>
constexpr decltype(auto) at_c(Xs&& xs);
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_AT_HPP
@@ -0,0 +1,67 @@
/*!
@file
Forward declares `boost::hana::at_key`.
@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)
*/
#ifndef BOOST_HANA_FWD_AT_KEY_HPP
#define BOOST_HANA_FWD_AT_KEY_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Returns the value associated to the given key in a structure, or fail.
//! @ingroup group-Searchable
//!
//! Given a `key` and a `Searchable` structure, `at_key` returns the first
//! value whose key is equal to the given `key`, and fails at compile-time
//! if no such key exists. This requires the `key` to be compile-time
//! `Comparable`, exactly like for `find`. `at_key` satisfies the following:
//! @code
//! at_key(xs, key) == find(xs, key).value()
//! @endcode
//!
//! If the `Searchable` actually stores the elements it contains, `at_key`
//! is required to return a lvalue reference, a lvalue reference to const
//! or a rvalue reference to the found value, where the type of reference
//! must match that of the structure passed to `at_key`. If the `Searchable`
//! does not store the elements it contains (i.e. it generates them on
//! demand), this requirement is dropped.
//!
//!
//! @param xs
//! The structure to be searched.
//!
//! @param key
//! A key to be searched for in the structure. The key has to be
//! `Comparable` with the other keys of the structure. In the current
//! version of the library, the comparison of `key` with any other key
//! of the structure must return a compile-time `Logical`.
//!
//!
//! Example
//! -------
//! @include example/at_key.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto at_key = [](auto&& xs, auto const& key) -> decltype(auto) {
return tag-dispatched;
};
#else
template <typename S, typename = void>
struct at_key_impl : at_key_impl<S, when<true>> { };
struct at_key_t {
template <typename Xs, typename Key>
constexpr decltype(auto) operator()(Xs&& xs, Key const& key) const;
};
constexpr at_key_t at_key{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_AT_KEY_HPP
@@ -0,0 +1,48 @@
/*!
@file
Forward declares `boost::hana::back`.
@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)
*/
#ifndef BOOST_HANA_FWD_BACK_HPP
#define BOOST_HANA_FWD_BACK_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Returns the last element of a non-empty and finite iterable.
//! @ingroup group-Iterable
//!
//! Given a non-empty and finite iterable `xs` with a linearization of
//! `[x1, ..., xN]`, `back(xs)` is equal to `xN`. Equivalently, `back(xs)`
//! must be equivalent to `at_c<N-1>(xs)`, and that regardless of the
//! value category of `xs` (`back` must respect the reference semantics
//! of `at`).
//!
//!
//! Example
//! -------
//! @include example/back.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto back = [](auto&& xs) -> decltype(auto) {
return tag-dispatched;
};
#else
template <typename It, typename = void>
struct back_impl : back_impl<It, when<true>> { };
struct back_t {
template <typename Xs>
constexpr decltype(auto) operator()(Xs&& xs) const;
};
constexpr back_t back{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_BACK_HPP
@@ -0,0 +1,65 @@
/*!
@file
Forward declares `boost::hana::basic_tuple`.
@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)
*/
#ifndef BOOST_HANA_FWD_BASIC_TUPLE_HPP
#define BOOST_HANA_FWD_BASIC_TUPLE_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/fwd/core/make.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-datatypes
//! Stripped down version of `hana::tuple`.
//!
//! Whereas `hana::tuple` aims to provide an interface somewhat close to a
//! `std::tuple`, `basic_tuple` provides the strict minimum required to
//! implement a closure with maximum compile-time efficiency.
//!
//!
//! Modeled concepts
//! ----------------
//! `Sequence`, and all the concepts it refines
template <typename ...Xs>
struct basic_tuple;
//! Tag representing `hana::basic_tuple`.
//! @relates hana::basic_tuple
struct basic_tuple_tag { };
#ifdef BOOST_HANA_DOXYGEN_INVOKED
//! Function object for creating a `basic_tuple`.
//! @relates hana::basic_tuple
//!
//! Given zero or more objects `xs...`, `make<basic_tuple_tag>` returns a
//! new `basic_tuple` containing those objects. The elements are held by
//! value inside the resulting tuple, and they are hence copied or moved
//! in. This is analogous to `std::make_tuple` for creating `basic_tuple`s.
//!
//!
//! Example
//! -------
//! @include example/basic_tuple/make.cpp
template <>
constexpr auto make<basic_tuple_tag> = [](auto&& ...xs) {
return basic_tuple<std::decay_t<decltype(xs)>...>{forwarded(xs)...};
};
#endif
//! Alias to `make<basic_tuple_tag>`; provided for convenience.
//! @relates hana::basic_tuple
//!
//!
//! Example
//! -------
//! @include example/basic_tuple/make.cpp
constexpr auto make_basic_tuple = make<basic_tuple_tag>;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_BASIC_TUPLE_HPP
@@ -0,0 +1,15 @@
/*!
@file
Includes boost/hana/fwd/integral_constant.hpp.
@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)
*/
#ifndef BOOST_HANA_FWD_BOOL_HPP
#define BOOST_HANA_FWD_BOOL_HPP
#include <boost/hana/fwd/integral_constant.hpp>
#endif // !BOOST_HANA_FWD_BOOL_HPP
@@ -0,0 +1,62 @@
/*!
@file
Forward declares `boost::hana::cartesian_product`.
@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)
*/
#ifndef BOOST_HANA_FWD_CARTESIAN_PRODUCT_HPP
#define BOOST_HANA_FWD_CARTESIAN_PRODUCT_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Computes the cartesian product of a sequence of sequences.
//! @ingroup group-Sequence
//!
//! Given a sequence of sequences, `cartesian_product` returns a new
//! sequence of sequences containing the cartesian product of the
//! original sequences. For this method to finish, a finite number
//! of finite sequences must be provided.
//!
//! @note
//! All the sequences must have the same tag, and that tag must also match
//! that of the top-level sequence.
//!
//!
//! Signature
//! ---------
//! Given a `Sequence` `S(T)`, the signature is
//! \f[
//! \mathtt{cartesian\_product} : S(S(T)) \to S(S(T))
//! \f]
//!
//! @param xs
//! A sequence of sequences of which the cartesian product is computed.
//!
//!
//! Example
//! -------
//! @include example/cartesian_product.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto cartesian_product = [](auto&& xs) {
return tag-dispatched;
};
#else
template <typename S, typename = void>
struct cartesian_product_impl : cartesian_product_impl<S, when<true>> { };
struct cartesian_product_t {
template <typename Xs>
constexpr auto operator()(Xs&& xs) const;
};
constexpr cartesian_product_t cartesian_product{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CARTESIAN_PRODUCT_HPP
@@ -0,0 +1,67 @@
/*!
@file
Forward declares `boost::hana::chain`.
@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)
*/
#ifndef BOOST_HANA_FWD_CHAIN_HPP
#define BOOST_HANA_FWD_CHAIN_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Feed a monadic value into a monadic computation.
//! @ingroup group-Monad
//!
//! Given a monadic value and a monadic function, `chain` feeds the
//! monadic value into the function, thus performing some Monad-specific
//! effects, and returns the result. An implementation of `chain` must
//! satisfy
//! @code
//! chain(xs, f) == flatten(transform(xs, f))
//! @endcode
//!
//!
//! Signature
//! ---------
//! For a monad `M`, given a monadic value of type `M(A)` and a monadic
//! function @f$ f : A \to M(B) @f$, `chain` has the signature
//! @f$
//! \mathtt{chain} : M(A) \times (A \to M(B)) \to M(B)
//! @f$.
//!
//! @param xs
//! A monadic value to be fed to the function `f`.
//!
//! @param f
//! A function taking a normal value in the `xs` structure, and returning
//! a monadic value. This function is called as `f(x)`, where `x` is an
//! element of the structure `xs`.
//!
//!
//! Example
//! -------
//! @include example/chain.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto chain = [](auto&& xs, auto&& f) -> decltype(auto) {
return tag-dispatched;
};
#else
template <typename M, typename = void>
struct chain_impl : chain_impl<M, when<true>> { };
struct chain_t {
template <typename Xs, typename F>
constexpr decltype(auto) operator()(Xs&& xs, F&& f) const;
};
constexpr chain_t chain{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CHAIN_HPP
@@ -0,0 +1,65 @@
/*!
@file
Forward declares `boost::hana::comparing`.
@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)
*/
#ifndef BOOST_HANA_FWD_COMPARING_HPP
#define BOOST_HANA_FWD_COMPARING_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Returns a function performing `equal` after applying a transformation
//! to both arguments.
//! @ingroup group-Comparable
//!
//! `comparing` creates an equivalence relation based on the result of
//! applying a function to some objects, which is especially useful in
//! conjunction with algorithms that accept a custom predicate that must
//! represent an equivalence relation.
//!
//! Specifically, `comparing` is such that
//! @code
//! comparing(f) == equal ^on^ f
//! @endcode
//! or, equivalently,
//! @code
//! comparing(f)(x, y) == equal(f(x), f(y))
//! @endcode
//!
//! @note
//! This is not a tag-dispatched method (hence it can't be customized),
//! but just a convenience function provided with the `Comparable` concept.
//!
//!
//! Signature
//! ---------
//! Given a Logical `Bool` and a Comparable `B`, the signature is
//! @f$ \mathtt{comparing} : (A \to B) \to (A \times A \to Bool) @f$.
//!
//!
//! Example
//! -------
//! @include example/comparing.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto comparing = [](auto&& f) {
return [perfect-capture](auto&& x, auto&& y) {
return equal(f(forwarded(x)), f(forwarded(y)));
};
};
#else
struct comparing_t {
template <typename F>
constexpr auto operator()(F&& f) const;
};
constexpr comparing_t comparing{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_COMPARING_HPP
@@ -0,0 +1,63 @@
/*!
@file
Forward declares `boost::hana::concat`.
@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)
*/
#ifndef BOOST_HANA_FWD_CONCAT_HPP
#define BOOST_HANA_FWD_CONCAT_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Combine two monadic structures together.
//! @ingroup group-MonadPlus
//!
//! Given two monadic structures, `concat` combines them together and
//! returns a new monadic structure. The exact definition of `concat`
//! will depend on the exact model of MonadPlus at hand, but for
//! sequences it corresponds intuitively to simple concatenation.
//!
//! Also note that combination is not required to be commutative.
//! In other words, there is no requirement that
//! @code
//! concat(xs, ys) == concat(ys, xs)
//! @endcode
//! and indeed it does not hold in general.
//!
//!
//! Signature
//! ---------
//! Given a `MonadPlus` `M`, the signature of `concat` is
//! @f$ \mathtt{concat} : M(T) \times M(T) \to M(T) @f$.
//!
//! @param xs, ys
//! Two monadic structures to combine together.
//!
//!
//! Example
//! -------
//! @include example/concat.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto concat = [](auto&& xs, auto&& ys) {
return tag-dispatched;
};
#else
template <typename M, typename = void>
struct concat_impl : concat_impl<M, when<true>> { };
struct concat_t {
template <typename Xs, typename Ys>
constexpr auto operator()(Xs&& xs, Ys&& ys) const;
};
constexpr concat_t concat{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCAT_HPP
@@ -0,0 +1,117 @@
/*!
@file
Forward declares `boost::hana::Applicative`.
@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)
*/
#ifndef BOOST_HANA_FWD_CONCEPT_APPLICATIVE_HPP
#define BOOST_HANA_FWD_CONCEPT_APPLICATIVE_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Applicative Applicative
//! The `Applicative` concept represents `Functor`s with the ability
//! to lift values and combine computations.
//!
//! A `Functor` can only take a normal function and map it over a
//! structure containing values to obtain a new structure containing
//! values. Intuitively, an `Applicative` can also take a value and
//! lift it into the structure. In addition, an `Applicative` can take
//! a structure containing functions and apply it to a structure
//! containing values to obtain a new structure containing values.
//! By currying the function(s) inside the structure, it is then
//! also possible to apply n-ary functions to n structures containing
//! values.
//!
//! @note
//! This documentation does not go into much details about the nature
//! of applicatives. However, the [Typeclassopedia][1] is a nice
//! Haskell-oriented resource where such information can be found.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! `lift` and `ap` satisfying the laws below. An `Applicative` must
//! also be a `Functor`.
//!
//!
//! Laws
//! ----
//! Given an `Applicative` `F`, the following laws must be satisfied:
//! 1. Identity\n
//! For all objects `xs` of tag `F(A)`,
//! @code
//! ap(lift<F>(id), xs) == xs
//! @endcode
//!
//! 2. Composition\n
//! For all objects `xs` of tag `F(A)` and functions-in-an-applicative
//! @f$ fs : F(B \to C) @f$,
//! @f$ gs : F(A \to B) @f$,
//! @code
//! ap(ap(lift<F>(compose), fs, gs), xs) == ap(fs, ap(gs, xs))
//! @endcode
//!
//! 3. Homomorphism\n
//! For all objects `x` of tag `A` and functions @f$ f : A \to B @f$,
//! @code
//! ap(lift<F>(f), lift<F>(x)) == lift<F>(f(x))
//! @endcode
//!
//! 4. Interchange\n
//! For all objects `x` of tag `A` and functions-in-an-applicative
//! @f$ fs : F(A \to B) @f$,
//! @code
//! ap(fs, lift<F>(x)) == ap(lift<F>(apply(-, x)), fs)
//! @endcode
//! where `apply(-, x)` denotes the partial application of the `apply`
//! function from the @ref group-functional module to the `x` argument.
//!
//! As a consequence of these laws, the model of `Functor` for `F` will
//! satisfy the following for all objects `xs` of tag `F(A)` and functions
//! @f$ f : A \to B @f$:
//! @code
//! transform(xs, f) == ap(lift<F>(f), xs)
//! @endcode
//!
//!
//! Refined concept
//! ---------------
//! 1. `Functor` (free model)\n
//! As a consequence of the laws, any `Applicative F` can be made a
//! `Functor` by setting
//! @code
//! transform(xs, f) = ap(lift<F>(f), xs)
//! @endcode
//!
//!
//! Concrete models
//! ---------------
//! `hana::lazy`, `hana::optional`, `hana::tuple`
//!
//!
//! @anchor applicative-transformation
//! Structure-preserving functions
//! ------------------------------
//! An _applicative transformation_ is a function @f$ t : F(X) \to G(X) @f$
//! between two Applicatives `F` and `G`, where `X` can be any tag, and
//! which preserves the operations of an Applicative. In other words, for
//! all objects `x` of tag `X`, functions-in-an-applicative
//! @f$ fs : F(X \to Y) @f$ and objects `xs` of tag `F(X)`,
//! @code
//! t(lift<F>(x)) == lift<G>(x)
//! t(ap(fs, xs)) == ap(t(fs), t(xs))
//! @endcode
//!
//! [1]: https://wiki.haskell.org/Typeclassopedia#Applicative
template <typename A>
struct Applicative;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_APPLICATIVE_HPP
@@ -0,0 +1,111 @@
/*!
@file
Forward declares `boost::hana::Comonad`.
@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)
*/
#ifndef BOOST_HANA_FWD_CONCEPT_COMONAD_HPP
#define BOOST_HANA_FWD_CONCEPT_COMONAD_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
// Note: We use a multiline C++ comment because there's a double backslash
// symbol in the documentation (for LaTeX), which triggers
// warning: multi-line comment [-Wcomment]
// on GCC.
/*!
@ingroup group-concepts
@defgroup group-Comonad Comonad
The `Comonad` concept represents context-sensitive computations and
data.
Formally, the Comonad concept is dual to the Monad concept.
But unless you're a mathematician, you don't care about that and it's
fine. So intuitively, a Comonad represents context sensitive values
and computations. First, Comonads make it possible to extract
context-sensitive values from their context with `extract`.
In contrast, Monads make it possible to wrap raw values into
a given context with `lift` (from Applicative).
Secondly, Comonads make it possible to apply context-sensitive values
to functions accepting those, and to return the result as a
context-sensitive value using `extend`. In contrast, Monads make
it possible to apply a monadic value to a function accepting a normal
value and returning a monadic value, and to return the result as a
monadic value (with `chain`).
Finally, Comonads make it possible to wrap a context-sensitive value
into an extra layer of context using `duplicate`, while Monads make
it possible to take a value with an extra layer of context and to
strip it with `flatten`.
Whereas `lift`, `chain` and `flatten` from Applicative and Monad have
signatures
\f{align*}{
\mathtt{lift}_M &: T \to M(T) \\
\mathtt{chain} &: M(T) \times (T \to M(U)) \to M(U) \\
\mathtt{flatten} &: M(M(T)) \to M(T)
\f}
`extract`, `extend` and `duplicate` from Comonad have signatures
\f{align*}{
\mathtt{extract} &: W(T) \to T \\
\mathtt{extend} &: W(T) \times (W(T) \to U) \to W(U) \\
\mathtt{duplicate} &: W(T) \to W(W(T))
\f}
Notice how the "arrows" are reversed. This symmetry is essentially
what we mean by Comonad being the _dual_ of Monad.
@note
The [Typeclassopedia][1] is a nice Haskell-oriented resource for further
reading about Comonads.
Minimal complete definition
---------------------------
`extract` and (`extend` or `duplicate`) satisfying the laws below.
A `Comonad` must also be a `Functor`.
Laws
----
For all Comonads `w`, the following laws must be satisfied:
@code
extract(duplicate(w)) == w
transform(duplicate(w), extract) == w
duplicate(duplicate(w)) == transform(duplicate(w), duplicate)
@endcode
@note
There are several equivalent ways of defining Comonads, and this one
is just one that was picked arbitrarily for simplicity.
Refined concept
---------------
1. Functor\n
Every Comonad is also required to be a Functor. At first, one might think
that it should instead be some imaginary concept CoFunctor. However, it
turns out that a CoFunctor is the same as a `Functor`, hence the
requirement that a `Comonad` also is a `Functor`.
Concrete models
---------------
`hana::lazy`
[1]: https://wiki.haskell.org/Typeclassopedia#Comonad
*/
template <typename W>
struct Comonad;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_COMONAD_HPP
@@ -0,0 +1,160 @@
/*!
@file
Forward declares `boost::hana::Comparable`.
@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)
*/
#ifndef BOOST_HANA_FWD_CONCEPT_COMPARABLE_HPP
#define BOOST_HANA_FWD_CONCEPT_COMPARABLE_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Comparable Comparable
//! The `Comparable` concept defines equality and inequality.
//!
//! Intuitively, `Comparable` objects must define a binary predicate named
//! `equal` that returns whether both objects represent the same abstract
//! value. In other words, `equal` must check for deep equality. Since
//! "representing the same abstract value" is difficult to express
//! formally, the exact meaning of equality is partially left to
//! interpretation by the programmer with the following guidelines:\n
//! 1. Equality should be compatible with copy construction; copy
//! constructing a value yields an `equal` value.
//! 2. Equality should be independent of representation; an object
//! representing a fraction as `4/8` should be `equal` to an object
//! representing a fraction as `2/4`, because they both represent
//! the mathematical object `1/2`.
//!
//! Moreover, `equal` must exhibit properties that make it intuitive to
//! use for determining the equivalence of objects, which is formalized
//! by the laws for `Comparable`.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! 1. `equal`\n
//! When `equal` is defined, `not_equal` is implemented by default as its
//! complement. For all objects `x`, `y` of a `Comparable` tag,
//! @code
//! not_equal(x, y) == not_(equal(x, y))
//! @endcode
//!
//!
//! Laws
//! ----
//! `equal` must define an [equivalence relation][1], and `not_equal` must
//! be its complement. In other words, for all objects `a`, `b`, `c` with
//! a `Comparable` tag, the following must hold:
//! @code
//! equal(a, a) // Reflexivity
//! if equal(a, b) then equal(b, a) // Symmetry
//! if equal(a, b) && equal(b, c) then equal(a, c) // Transitivity
//! not_equal(a, b) is equivalent to not_(equal(a, b))
//! @endcode
//!
//!
//! Concrete models
//! ---------------
//! `hana::integral_constant`, `hana::map`, `hana::optional`, `hana::pair`,
//! `hana::range`, `hana::set`, `hana::string`, `hana::tuple`,
//! `hana::type`
//!
//!
//! Free model for `EqualityComparable` data types
//! ----------------------------------------------
//! Two data types `T` and `U` that model the cross-type EqualityComparable
//! concept presented in [N3351][2] automatically model the `Comparable`
//! concept by setting
//! @code
//! equal(x, y) = (x == y)
//! @endcode
//! Note that this also makes EqualityComparable types in the
//! [usual sense][3] models of `Comparable` in the same way.
//!
//!
//! Equality-preserving functions
//! -----------------------------
//! Let `A` and `B` be two `Comparable` tags. A function @f$f : A \to B@f$
//! is said to be equality-preserving if it preserves the structure of the
//! `Comparable` concept, which can be rigorously stated as follows. For
//! all objects `x`, `y` of tag `A`,
//! @code
//! if equal(x, y) then equal(f(x), f(y))
//! @endcode
//! Equivalently, we simply require that `f` is a function in the usual
//! mathematical sense. Another property is [injectivity][4], which can be
//! viewed as being a "lossless" mapping. This property can be stated as
//! @code
//! if equal(f(x), f(y)) then equal(x, y)
//! @endcode
//! This is equivalent to saying that `f` maps distinct elements to
//! distinct elements, hence the "lossless" analogy. In other words, `f`
//! will not collapse distinct elements from its domain into a single
//! element in its image, thus losing information.
//!
//! These functions are very important, especially equality-preserving
//! ones, because they allow us to reason simply about programs. Also
//! note that the property of being equality-preserving is taken for
//! granted in mathematics because it is part of the definition of a
//! function. We feel it is important to make the distinction here
//! because programming has evolved differently and as a result
//! programmers are used to work with functions that do not preserve
//! equality.
//!
//!
//! Cross-type version of the methods
//! ---------------------------------
//! The `equal` and `not_equal` methods are "overloaded" to handle
//! distinct tags with certain properties. Specifically, they are
//! defined for _distinct_ tags `A` and `B` such that
//! 1. `A` and `B` share a common tag `C`, as determined by the
//! `common` metafunction
//! 2. `A`, `B` and `C` are all `Comparable` when taken individually
//! 3. @f$ \mathtt{to<C>} : A \to C @f$ and @f$\mathtt{to<C>} : B \to C@f$
//! are both equality-preserving and injective (i.e. they are embeddings),
//! as determined by the `is_embedding` metafunction.
//!
//! The method definitions for tags satisfying the above properties are
//! @code
//! equal(x, y) = equal(to<C>(x), to<C>(y))
//! not_equal(x, y) = not_equal(to<C>(x), to<C>(y))
//! @endcode
//!
//!
//! Important note: special behavior of `equal`
//! -------------------------------------------
//! In the context of programming with heterogeneous values, it is useful
//! to have unrelated objects compare `false` instead of triggering an
//! error. For this reason, `equal` adopts a special behavior for
//! unrelated objects of tags `T` and `U` that do not satisfy the above
//! requirements for the cross-type overloads. Specifically, when `T` and
//! `U` are unrelated (i.e. `T` can't be converted to `U` and vice-versa),
//! comparing objects with those tags yields a compile-time false value.
//! This has the effect that unrelated objects like `float` and
//! `std::string` will compare false, while comparing related objects that
//! can not be safely embedded into the same super structure (like
//! `long long` and `float` because of the precision loss) will trigger a
//! compile-time assertion. Also note that for any tag `T` for which the
//! minimal complete definition of `Comparable` is not provided, a
//! compile-time assertion will also be triggered because `T` and `T`
//! trivially share the common tag `T`, which is the expected behavior.
//! This design choice aims to provide more flexibility for comparing
//! objects, while still rejecting usage patterns that are most likely
//! programming errors.
//!
//!
//! [1]: http://en.wikipedia.org/wiki/Equivalence_relation#Definition
//! [2]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3351.pdf
//! [3]: http://en.cppreference.com/w/cpp/concept/EqualityComparable
//! [4]: http://en.wikipedia.org/wiki/Injective_function
template <typename T>
struct Comparable;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_COMPARABLE_HPP
@@ -0,0 +1,210 @@
/*!
@file
Forward declares `boost::hana::Constant`.
@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)
*/
#ifndef BOOST_HANA_FWD_CONCEPT_CONSTANT_HPP
#define BOOST_HANA_FWD_CONCEPT_CONSTANT_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Constant Constant
//! The `Constant` concept represents data that can be manipulated at
//! compile-time.
//!
//! At its core, `Constant` is simply a generalization of the principle
//! behind `std::integral_constant` to all types that can be constructed
//! at compile-time, i.e. to all types with a `constexpr` constructor
//! (also called [Literal types][1]). More specifically, a `Constant` is
//! an object from which a `constexpr` value may be obtained (through the
//! `value` method) regardless of the `constexpr`ness of the object itself.
//!
//! All `Constant`s must be somewhat equivalent, in the following sense.
//! Let `C(T)` and `D(U)` denote the tags of `Constant`s holding objects
//! of type `T` and `U`, respectively. Then, an object with tag `D(U)`
//! must be convertible to an object with tag `C(T)` whenever `U` is
//! convertible to `T`, as determined by `is_convertible`. The
//! interpretation here is that a `Constant` is just a box holding
//! an object of some type, and it should be possible to swap between
//! boxes whenever the objects inside the boxes can be swapped.
//!
//! Because of this last requirement, one could be tempted to think that
//! specialized "boxes" like `std::integral_constant` are prevented from
//! being `Constant`s because they are not able to hold objects of any
//! type `T` (`std::integral_constant` may only hold integral types).
//! This is false; the requirement should be interpreted as saying that
//! whenever `C(T)` is _meaningful_ (e.g. only when `T` is integral for
//! `std::integral_constant`) _and_ there exists a conversion from `U`
//! to `T`, then a conversion from `D(U)` to `C(T)` should also exist.
//! The precise requirements for being a `Constant` are embodied in the
//! following laws.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! `value` and `to`, satisfying the laws below.
//!
//!
//! Laws
//! ----
//! Let `c` be an object of with tag `C`, which represents a `Constant`
//! holding an object with tag `T`. The first law ensures that the value
//! of the wrapped object is always a constant expression by requiring
//! the following to be well-formed:
//! @code
//! constexpr auto x = hana::value<decltype(c)>();
//! @endcode
//!
//! This means that the `value` function must return an object that can
//! be constructed at compile-time. It is important to note how `value`
//! only receives the type of the object and not the object itself.
//! This is the core of the `Constant` concept; it means that the only
//! information required to implement `value` must be stored in the _type_
//! of its argument, and hence be available statically.
//!
//! The second law that must be satisfied ensures that `Constant`s are
//! basically dumb boxes, which makes it possible to provide models for
//! many concepts without much work from the user. The law simply asks
//! for the following expression to be valid:
//! @code
//! to<C>(i)
//! @endcode
//! where, `i` is an _arbitrary_ `Constant` holding an internal value
//! with a tag that can be converted to `T`, as determined by the
//! `hana::is_convertible` metafunction. In other words, whenever `U` is
//! convertible to `T`, a `Constant` holding a `U` is convertible to
//! a `Constant` holding a `T`, if such a `Constant` can be created.
//!
//! Finally, the tag `C` must provide a nested `value_type` alias to `T`,
//! which allows us to query the tag of the inner value held by objects
//! with tag `C`. In other words, the following must be true for any
//! object `c` with tag `C`:
//! @code
//! std::is_same<
//! C::value_type,
//! tag_of<decltype(hana::value(c))>::type
//! >::value
//! @endcode
//!
//!
//! Refined concepts
//! ----------------
//! In certain cases, a `Constant` can automatically be made a model of
//! another concept. In particular, if a `Constant` `C` is holding an
//! object of tag `T`, and if `T` models a concept `X`, then `C` may
//! in most cases model `X` by simply performing whatever operation is
//! required on its underlying value, and then wrapping the result back
//! in a `C`.
//!
//! More specifically, if a `Constant` `C` has an underlying value
//! (`C::value_type`) which is a model of `Comparable`, `Orderable`,
//! `Logical`, or `Monoid` up to `EuclideanRing`, then `C` must also
//! be a model of those concepts. In other words, when `C::value_type`
//! models one of the listed concepts, `C` itself must also model that
//! concept. However, note that free models are provided for all of
//! those concepts, so no additional work must be done.
//!
//! While it would be possible in theory to provide models for concepts
//! like `Foldable` too, only a couple of concepts are useful to have as
//! `Constant` in practice. Providing free models for the concepts listed
//! above is useful because it allows various types of integral constants
//! (`std::integral_constant`, `mpl::integral_c`, etc...) to easily have
//! models for them just by defining the `Constant` concept.
//!
//! @remark
//! An interesting observation is that `Constant` is actually the
//! canonical embedding of the subcategory of `constexpr` things
//! into the Hana category, which contains everything in this library.
//! Hence, whatever is true in that subcategory is also true here, via
//! this functor. This is why we can provide models of any concept that
//! works on `constexpr` things for Constants, by simply passing them
//! through that embedding.
//!
//!
//! Concrete models
//! ---------------
//! `hana::integral_constant`
//!
//!
//! Provided conversion to the tag of the underlying value
//! ------------------------------------------------------
//! Any `Constant` `c` holding an underlying value of tag `T` is
//! convertible to any tag `U` such that `T` is convertible to `U`.
//! Specifically, the conversion is equivalent to
//! @code
//! to<U>(c) == to<U>(value<decltype(c)>())
//! @endcode
//!
//! Also, those conversions are marked as an embedding whenever the
//! conversion of underlying types is an embedding. This is to allow
//! Constants to inter-operate with `constexpr` objects easily:
//! @code
//! plus(int_c<1>, 1) == 2
//! @endcode
//!
//! Strictly speaking, __this is sometimes a violation__ of what it means
//! to be an embedding. Indeed, while there exists an embedding from any
//! Constant to a `constexpr` object (since Constant is just the canonical
//! inclusion), there is no embedding from a Constant to a runtime
//! object since we would lose the ability to define the `value` method
//! (the `constexpr`ness of the object would have been lost). Since there
//! is no way to distinguish `constexpr` and non-`constexpr` objects based
//! on their type, Hana has no way to know whether the conversion is to a
//! `constexpr` object of not. In other words, the `to` method has no way
//! to differentiate between
//! @code
//! constexpr int i = hana::to<int>(int_c<1>);
//! @endcode
//! which is an embedding, and
//! @code
//! int i = hana::to<int>(int_c<1>);
//! @endcode
//!
//! which isn't. To be on the safer side, we could mark the conversion
//! as not-an-embedding. However, if e.g. the conversion from
//! `integral_constant_tag<int>` to `int` was not marked as an embedding,
//! we would have to write `plus(to<int>(int_c<1>), 1)` instead of just
//! `plus(int_c<1>, 1)`, which is cumbersome. Hence, the conversion is
//! marked as an embedding, but this also means that code like
//! @code
//! int i = 1;
//! plus(int_c<1>, i);
//! @endcode
//! will be considered valid, which implicitly loses the fact that
//! `int_c<1>` is a Constant, and hence does not follow the usual rules
//! for cross-type operations in Hana.
//!
//!
//! Provided common data type
//! -------------------------
//! Because of the requirement that `Constant`s be interchangeable when
//! their contents are compatible, two `Constant`s `A` and `B` will have
//! a common data type whenever `A::value_type` and `B::value_type` have
//! one. Their common data type is an unspecified `Constant` `C` such
//! that `C::value_type` is exactly `common_t<A::value_type, B::value_type>`.
//! A specialization of the `common` metafunction is provided for
//! `Constant`s to reflect this.
//!
//! In the same vein, a common data type is also provided from any
//! constant `A` to a type `T` such that `A::value_type` and `T` share
//! a common type. The common type between `A` and `T` is obviously the
//! common type between `A::value_type` and `T`. As explained above in
//! the section on conversions, this is sometimes a violation of the
//! definition of a common type, because there must be an embedding
//! to the common type, which is not always the case. For the same
//! reasons as explained above, this common type is still provided.
//!
//!
//! [1]: http://en.cppreference.com/w/cpp/concept/LiteralType
template <typename C>
struct Constant;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_CONSTANT_HPP
@@ -0,0 +1,117 @@
/*!
@file
Forward declares `boost::hana::EuclideanRing`.
@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)
*/
#ifndef BOOST_HANA_FWD_CONCEPT_EUCLIDEAN_RING_HPP
#define BOOST_HANA_FWD_CONCEPT_EUCLIDEAN_RING_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-EuclideanRing Euclidean Ring
//! The `EuclideanRing` concept represents a commutative `Ring` that
//! can also be endowed with a division algorithm.
//!
//! A Ring defines a binary operation often called _multiplication_ that
//! can be used to combine two elements of the ring into a new element of
//! the ring. An [Euclidean ring][1], also called an Euclidean domain, adds
//! the ability to define a special function that generalizes the Euclidean
//! division of integers.
//!
//! However, an Euclidean ring must also satisfy one more property, which
//! is that of having no non-zero zero divisors. In a Ring `(R, +, *)`, it
//! follows quite easily from the axioms that `x * 0 == 0` for any ring
//! element `x`. However, there is nothing that mandates `0` to be the
//! only ring element sending other elements to `0`. Hence, in some Rings,
//! it is possible to have elements `x` and `y` such that `x * y == 0`
//! while not having `x == 0` nor `y == 0`. We call these elements divisors
//! of zero, or zero divisors. For example, this situation arises in the
//! Ring of integers modulo 4 (the set `{0, 1, 2, 3}`) with addition and
//! multiplication `mod 4` as binary operations. In this case, we have that
//! @code
//! 2 * 2 == 4
//! == 0 (mod 4)
//! @endcode
//! even though `2 != 0 (mod 4)`.
//!
//! Following this line of thought, an Euclidean ring requires its only
//! zero divisor is zero itself. In other words, the multiplication in an
//! Euclidean won't send two non-zero elements to zero. Also note that
//! since multiplication in a `Ring` is not necessarily commutative, it
//! is not always the case that
//! @code
//! x * y == 0 implies y * x == 0
//! @endcode
//! To be rigorous, we should then distinguish between elements that are
//! zero divisors when multiplied to the right and to the left.
//! Fortunately, the concept of an Euclidean ring requires the Ring
//! multiplication to be commutative. Hence,
//! @code
//! x * y == y * x
//! @endcode
//! and we do not have to distinguish between left and right zero divisors.
//!
//! Typical examples of Euclidean rings include integers and polynomials
//! over a field. The method names used here refer to the Euclidean ring
//! of integers under the usual addition, multiplication and division
//! operations.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! `div` and `mod` satisfying the laws below
//!
//!
//! Laws
//! ----
//! To simplify the reading, we will use the `+`, `*`, `/` and `%`
//! operators with infix notation to denote the application of the
//! corresponding methods in Monoid, Group, Ring and EuclideanRing.
//! For all objects `a` and `b` of an `EuclideanRing` `R`, the
//! following laws must be satisfied:
//! @code
//! a * b == b * a // commutativity
//! (a / b) * b + a % b == a if b is non-zero
//! zero<R>() % b == zero<R>() if b is non-zero
//! @endcode
//!
//!
//! Refined concepts
//! ----------------
//! `Monoid`, `Group`, `Ring`
//!
//!
//! Concrete models
//! ---------------
//! `hana::integral_constant`
//!
//!
//! Free model for non-boolean integral data types
//! ----------------------------------------------
//! A data type `T` is integral if `std::is_integral<T>::%value` is true.
//! For a non-boolean integral data type `T`, a model of `EuclideanRing`
//! is automatically defined by using the `Ring` model provided for
//! arithmetic data types and setting
//! @code
//! div(x, y) = (x / y)
//! mod(x, y) = (x % y)
//! @endcode
//!
//! @note
//! The rationale for not providing an EuclideanRing model for `bool` is
//! the same as for not providing Monoid, Group and Ring models.
//!
//!
//! [1]: https://en.wikipedia.org/wiki/Euclidean_domain
template <typename R>
struct EuclideanRing;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_EUCLIDEAN_RING_HPP
@@ -0,0 +1,141 @@
/*!
@file
Forward declares `boost::hana::Foldable`.
@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)
*/
#ifndef BOOST_HANA_FWD_CONCEPT_FOLDABLE_HPP
#define BOOST_HANA_FWD_CONCEPT_FOLDABLE_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Foldable Foldable
//! The `Foldable` concept represents data structures that can be reduced
//! to a single value.
//!
//! Generally speaking, folding refers to the concept of summarizing a
//! complex structure as a single value, by successively applying a
//! binary operation which reduces two elements of the structure to a
//! single value. Folds come in many flavors; left folds, right folds,
//! folds with and without an initial reduction state, and their monadic
//! variants. This concept is able to express all of these fold variants.
//!
//! Another way of seeing `Foldable` is as data structures supporting
//! internal iteration with the ability to accumulate a result. By
//! internal iteration, we mean that the _loop control_ is in the hand
//! of the structure, not the caller. Hence, it is the structure who
//! decides when the iteration stops, which is normally when the whole
//! structure has been consumed. Since C++ is an eager language, this
//! requires `Foldable` structures to be finite, or otherwise one would
//! need to loop indefinitely to consume the whole structure.
//!
//! @note
//! While the fact that `Foldable` only works for finite structures may
//! seem overly restrictive in comparison to the Haskell definition of
//! `Foldable`, a finer grained separation of the concepts should
//! mitigate the issue. For iterating over possibly infinite data
//! structures, see the `Iterable` concept. For searching a possibly
//! infinite data structure, see the `Searchable` concept.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! `fold_left` or `unpack`
//!
//! However, please note that a minimal complete definition provided
//! through `unpack` will be much more compile-time efficient than one
//! provided through `fold_left`.
//!
//!
//! Concrete models
//! ---------------
//! `hana::map`, `hana::optional`, `hana::pair`, `hana::set`,
//! `hana::range`, `hana::tuple`
//!
//!
//! @anchor Foldable-lin
//! The linearization of a `Foldable`
//! ---------------------------------
//! Intuitively, for a `Foldable` structure `xs`, the _linearization_ of
//! `xs` is the sequence of all the elements in `xs` as if they had been
//! put in a list:
//! @code
//! linearization(xs) = [x1, x2, ..., xn]
//! @endcode
//!
//! Note that it is always possible to produce such a linearization
//! for a finite `Foldable` by setting
//! @code
//! linearization(xs) = fold_left(xs, [], flip(prepend))
//! @endcode
//! for an appropriate definition of `[]` and `prepend`. The notion of
//! linearization is useful for expressing various properties of
//! `Foldable` structures, and is used across the documentation. Also
//! note that `Iterable`s define an [extended version](@ref Iterable-lin)
//! of this allowing for infinite structures.
//!
//!
//! Compile-time Foldables
//! ----------------------
//! A compile-time `Foldable` is a `Foldable` whose total length is known
//! at compile-time. In other words, it is a `Foldable` whose `length`
//! method returns a `Constant` of an unsigned integral type. When
//! folding a compile-time `Foldable`, the folding can be unrolled,
//! because the final number of steps of the algorithm is known at
//! compile-time.
//!
//! Additionally, the `unpack` method is only available to compile-time
//! `Foldable`s. This is because the return _type_ of `unpack` depends
//! on the number of objects in the structure. Being able to resolve
//! `unpack`'s return type at compile-time hence requires the length of
//! the structure to be known at compile-time too.
//!
//! __In the current version of the library, only compile-time `Foldable`s
//! are supported.__ While it would be possible in theory to support
//! runtime `Foldable`s too, doing so efficiently requires more research.
//!
//!
//! Provided conversion to `Sequence`s
//! ----------------------------------
//! Given a tag `S` which is a `Sequence`, an object whose tag is a model
//! of the `Foldable` concept can be converted to an object of tag `S`.
//! In other words, a `Foldable` can be converted to a `Sequence` `S`, by
//! simply taking the linearization of the `Foldable` and creating the
//! sequence with that. More specifically, given a `Foldable` `xs` with a
//! linearization of `[x1, ..., xn]` and a `Sequence` tag `S`, `to<S>(xs)`
//! is equivalent to `make<S>(x1, ..., xn)`.
//! @include example/foldable/to.cpp
//!
//!
//! Free model for builtin arrays
//! -----------------------------
//! Builtin arrays whose size is known can be folded as-if they were
//! homogeneous tuples. However, note that builtin arrays can't be
//! made more than `Foldable` (e.g. `Iterable`) because they can't
//! be empty and they also can't be returned from functions.
//!
//!
//! @anchor monadic-folds
//! Primer on monadic folds
//! -----------------------
//! A monadic fold is a fold in which subsequent calls to the binary
//! function are chained with the monadic `chain` operator of the
//! corresponding Monad. This allows a structure to be folded in a
//! custom monadic context. For example, performing a monadic fold with
//! the `hana::optional` monad would require the binary function to return
//! the result as a `hana::optional`, and the fold would abort and return
//! `nothing` whenever one of the accumulation step would fail (i.e.
//! return `nothing`). If, however, all the reduction steps succeed,
//! then `just` the result would be returned. Different monads will of
//! course result in different effects.
template <typename T>
struct Foldable;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_FOLDABLE_HPP
@@ -0,0 +1,139 @@
/*!
@file
Forward declares `boost::hana::Functor`.
@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)
*/
#ifndef BOOST_HANA_FWD_CONCEPT_FUNCTOR_HPP
#define BOOST_HANA_FWD_CONCEPT_FUNCTOR_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Functor Functor
//! The `Functor` concept represents types that can be mapped over.
//!
//! Intuitively, a [Functor][1] is some kind of box that can hold generic
//! data and map a function over this data to create a new, transformed
//! box. Because we are only interested in mapping a function over the
//! contents of a black box, the only real requirement for being a functor
//! is to provide a function which can do the mapping, along with a couple
//! of guarantees that the mapping is well-behaved. Those requirements are
//! made precise in the laws below. The pattern captured by `Functor` is
//! very general, which makes it widely useful. A lot of objects can be
//! made `Functor`s in one way or another, the most obvious example being
//! sequences with the usual mapping of the function on each element.
//! While this documentation will not go into much more details about
//! the nature of functors, the [Typeclassopedia][2] is a nice
//! Haskell-oriented resource for such information.
//!
//! Functors are parametric data types which are parameterized over the
//! data type of the objects they contain. Like everywhere else in Hana,
//! this parametricity is only at the documentation level and it is not
//! enforced.
//!
//! In this library, the mapping function is called `transform` after the
//! `std::transform` algorithm, but other programming languages have given
//! it different names (usually `map`).
//!
//! @note
//! The word _functor_ comes from functional programming, where the
//! concept has been used for a while, notably in the Haskell programming
//! language. Haskell people borrowed the term from [category theory][3],
//! which, broadly speaking, is a field of mathematics dealing with
//! abstract structures and transformations between those structures.
//!
//!
//! Minimal complete definitions
//! ----------------------------
//! 1. `transform`\n
//! When `transform` is specified, `adjust_if` is defined analogously to
//! @code
//! adjust_if(xs, pred, f) = transform(xs, [](x){
//! if pred(x) then f(x) else x
//! })
//! @endcode
//!
//! 2. `adjust_if`\n
//! When `adjust_if` is specified, `transform` is defined analogously to
//! @code
//! transform(xs, f) = adjust_if(xs, always(true), f)
//! @endcode
//!
//!
//! Laws
//! ----
//! Let `xs` be a Functor with tag `F(A)`,
//! \f$ f : A \to B \f$ and
//! \f$ g : B \to C \f$.
//! The following laws must be satisfied:
//! @code
//! transform(xs, id) == xs
//! transform(xs, compose(g, f)) == transform(transform(xs, f), g)
//! @endcode
//! The first line says that mapping the identity function should not do
//! anything, which precludes the functor from doing something nasty
//! behind the scenes. The second line states that mapping the composition
//! of two functions is the same as mapping the first function, and then
//! the second on the result. While the usual functor laws are usually
//! restricted to the above, this library includes other convenience
//! methods and they should satisfy the following equations.
//! Let `xs` be a Functor with tag `F(A)`,
//! \f$ f : A \to A \f$,
//! \f$ \mathrm{pred} : A \to \mathrm{Bool} \f$
//! for some `Logical` `Bool`, and `oldval`, `newval`, `value` objects
//! of tag `A`. Then,
//! @code
//! adjust(xs, value, f) == adjust_if(xs, equal.to(value), f)
//! adjust_if(xs, pred, f) == transform(xs, [](x){
//! if pred(x) then f(x) else x
//! })
//! replace_if(xs, pred, value) == adjust_if(xs, pred, always(value))
//! replace(xs, oldval, newval) == replace_if(xs, equal.to(oldval), newval)
//! fill(xs, value) == replace_if(xs, always(true), value)
//! @endcode
//! The default definition of the methods will satisfy these equations.
//!
//!
//! Concrete models
//! ---------------
//! `hana::lazy`, `hana::optional`, `hana::tuple`
//!
//!
//! Structure-preserving functions for Functors
//! -------------------------------------------
//! A mapping between two functors which also preserves the functor
//! laws is called a natural transformation (the term comes from
//! category theory). A natural transformation is a function `f`
//! from a functor `F` to a functor `G` such that for every other
//! function `g` with an appropriate signature and for every object
//! `xs` of tag `F(X)`,
//! @code
//! f(transform(xs, g)) == transform(f(xs), g)
//! @endcode
//!
//! There are several examples of such transformations, like `to<tuple_tag>`
//! when applied to an optional value. Indeed, for any function `g` and
//! `hana::optional` `opt`,
//! @code
//! to<tuple_tag>(transform(opt, g)) == transform(to<tuple_tag>(opt), g)
//! @endcode
//!
//! Of course, natural transformations are not limited to the `to<...>`
//! functions. However, note that any conversion function between Functors
//! should be natural for the behavior of the conversion to be intuitive.
//!
//!
//! [1]: http://en.wikipedia.org/wiki/Functor
//! [2]: https://wiki.haskell.org/Typeclassopedia#Functor
//! [3]: http://en.wikipedia.org/wiki/Category_theory
template <typename F>
struct Functor;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_FUNCTOR_HPP
@@ -0,0 +1,111 @@
/*!
@file
Forward declares `boost::hana::Group`.
@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)
*/
#ifndef BOOST_HANA_FWD_CONCEPT_GROUP_HPP
#define BOOST_HANA_FWD_CONCEPT_GROUP_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Group Group
//! The `Group` concept represents `Monoid`s where all objects have
//! an inverse w.r.t. the `Monoid`'s binary operation.
//!
//! A [Group][1] is an algebraic structure built on top of a `Monoid`
//! which adds the ability to invert the action of the `Monoid`'s binary
//! operation on any element of the set. Specifically, a `Group` is a
//! `Monoid` `(S, +)` such that every element `s` in `S` has an inverse
//! (say `s'`) which is such that
//! @code
//! s + s' == s' + s == identity of the Monoid
//! @endcode
//!
//! There are many examples of `Group`s, one of which would be the
//! additive `Monoid` on integers, where the inverse of any integer
//! `n` is the integer `-n`. The method names used here refer to
//! exactly this model.
//!
//!
//! Minimal complete definitions
//! ----------------------------
//! 1. `minus`\n
//! When `minus` is specified, the `negate` method is defaulted by setting
//! @code
//! negate(x) = minus(zero<G>(), x)
//! @endcode
//!
//! 2. `negate`\n
//! When `negate` is specified, the `minus` method is defaulted by setting
//! @code
//! minus(x, y) = plus(x, negate(y))
//! @endcode
//!
//!
//! Laws
//! ----
//! For all objects `x` of a `Group` `G`, the following laws must be
//! satisfied:
//! @code
//! plus(x, negate(x)) == zero<G>() // right inverse
//! plus(negate(x), x) == zero<G>() // left inverse
//! @endcode
//!
//!
//! Refined concept
//! ---------------
//! `Monoid`
//!
//!
//! Concrete models
//! ---------------
//! `hana::integral_constant`
//!
//!
//! Free model for non-boolean arithmetic data types
//! ------------------------------------------------
//! A data type `T` is arithmetic if `std::is_arithmetic<T>::%value` is
//! true. For a non-boolean arithmetic data type `T`, a model of `Group`
//! is automatically defined by setting
//! @code
//! minus(x, y) = (x - y)
//! negate(x) = -x
//! @endcode
//!
//! @note
//! The rationale for not providing a Group model for `bool` is the same
//! as for not providing a `Monoid` model.
//!
//!
//! Structure-preserving functions
//! ------------------------------
//! Let `A` and `B` be two `Group`s. A function `f : A -> B` is said to
//! be a [Group morphism][2] if it preserves the group structure between
//! `A` and `B`. Rigorously, for all objects `x, y` of data type `A`,
//! @code
//! f(plus(x, y)) == plus(f(x), f(y))
//! @endcode
//! Because of the `Group` structure, it is easy to prove that the
//! following will then also be satisfied:
//! @code
//! f(negate(x)) == negate(f(x))
//! f(zero<A>()) == zero<B>()
//! @endcode
//! Functions with these properties interact nicely with `Group`s, which
//! is why they are given such a special treatment.
//!
//!
//! [1]: http://en.wikipedia.org/wiki/Group_(mathematics)
//! [2]: http://en.wikipedia.org/wiki/Group_homomorphism
template <typename G>
struct Group;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_GROUP_HPP
@@ -0,0 +1,68 @@
/*!
@file
Forward declares `boost::hana::Hashable`.
@copyright Louis Dionne 2016
@copyright Jason Rice 2016
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
#ifndef BOOST_HANA_FWD_CONCEPT_HASHABLE_HPP
#define BOOST_HANA_FWD_CONCEPT_HASHABLE_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Hashable Hashable
//! The `Hashable` concept represents objects that can be normalized to
//! a type-level hash.
//!
//! In day to day programming, hashes are very important as a way to
//! efficiently lookup objects in maps. While the implementation of
//! maps is very different, the same idea of using hashes for efficient
//! lookup applies in metaprogramming. The `Hashable` concept represents
//! objects that can be summarized (possibly with loss of information) to
//! a type, in a way suitable for use in hash-based data structures. Of
//! course, in order for a hash to be well-behaved, it must obey some laws
//! that are explained below.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! `hash`, satisfying the laws below
//!
//!
//! Laws
//! ----
//! First, `hana::hash` must return a `hana::type`. Furthermore, for any
//! two `Hashable` objects `x` and `y`, it must be the case that
//! @code
//! x == y implies hash(x) == hash(y)
//! @endcode
//!
//! where `==` denotes `hana::equal`. In other words, any two objects that
//! compare equal (with `hana::equal`) must also have the same hash.
//! However, the reverse is not true, and two different objects may have
//! the same hash. This situation of two different objects having the same
//! hash is called a _collision_.
//!
//!
//! Concrete models
//! ---------------
//! `hana::integral_constant`, `hana::type`, `hana::string`
//!
//!
//! Free model for `IntegralConstant`s
//! ----------------------------------
//! Any `IntegralConstant` is `Hashable`, by normalizing its value to a
//! `hana::integral_constant`. The type of the value held in the normalized
//! `integral_constant` is `unsigned long long` for unsigned integral
//! types, and `signed long long` for signed integral types.
template <typename T>
struct Hashable;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_HASHABLE_HPP
@@ -0,0 +1,73 @@
/*!
@file
Forward declares `boost::hana::IntegralConstant`.
@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)
*/
#ifndef BOOST_HANA_FWD_CONCEPT_INTEGRAL_CONSTANT_HPP
#define BOOST_HANA_FWD_CONCEPT_INTEGRAL_CONSTANT_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! The `IntegralConstant` concept represents compile-time integral values.
//!
//! The `IntegralConstant` concept represents objects that hold a
//! `constexpr` value of an integral type. In other words, it describes
//! the essential functionality provided by `std::integral_constant`.
//! An `IntegralConstant` is also just a special kind of `Constant`
//! whose inner value is of an integral type.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! The requirements for being an `IntegralConstant` are quite simple.
//! First, an `IntegralConstant` `C` must be a `Constant` such that
//! `Tag::value_type` is an integral type, where `Tag` is the tag of `C`.
//!
//! Secondly, `C` must have a nested `static constexpr` member named
//! `value`, such that the following code is valid:
//! @code
//! constexpr auto v = C::value;
//! @endcode
//! Because of the requirement that `Tag::value_type` be an integral type,
//! it follows that `C::value` must be an integral value.
//!
//! Finally, it is necessary to specialize the `IntegralConstant` template
//! in the `boost::hana` namespace to tell Hana that a type is a model
//! of `IntegralConstant`:
//! @code
//! namespace boost { namespace hana {
//! template <>
//! struct IntegralConstant<your_custom_tag> {
//! static constexpr bool value = true;
//! };
//! }}
//! @endcode
//!
//!
//! Refined concept
//! ---------------
//! 1. `Constant` (free implementation of `value`)\n
//! The `value` function required to be a `Constant` can be implemented
//! as follows for `IntegralConstant`s:
//! @code
//! value<C>() == C::value
//! @endcode
//! The `to` function must still be provided explicitly for the model
//! of `Constant` to be complete.
//!
//!
//! Concrete models
//! ---------------
//! `hana::integral_constant`
template <typename C>
struct IntegralConstant;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_INTEGRAL_CONSTANT_HPP
@@ -0,0 +1,149 @@
/*!
@file
Forward declares `boost::hana::Iterable`.
@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)
*/
#ifndef BOOST_HANA_FWD_CONCEPT_ITERABLE_HPP
#define BOOST_HANA_FWD_CONCEPT_ITERABLE_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Iterable Iterable
//! The `Iterable` concept represents data structures supporting external
//! iteration.
//!
//! Intuitively, an `Iterable` can be seen as a kind of container whose
//! elements can be pulled out one at a time. An `Iterable` also provides
//! a way to know when the _container_ is empty, i.e. when there are no
//! more elements to pull out.
//!
//! Whereas `Foldable` represents data structures supporting internal
//! iteration with the ability to accumulate a result, the `Iterable`
//! concept allows inverting the control of the iteration. This is more
//! flexible than `Foldable`, since it allows iterating over only some
//! part of the structure. This, in turn, allows `Iterable` to work on
//! infinite structures, while trying to fold such a structure would
//! never finish.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! `at`, `drop_front` and `is_empty`
//!
//!
//! @anchor Iterable-lin
//! The linearization of an `Iterable`
//! ----------------------------------
//! Intuitively, for an `Iterable` structure `xs`, the _linearization_ of
//! `xs` is the sequence of all the elements in `xs` as if they had been
//! put in a (possibly infinite) list:
//! @code
//! linearization(xs) = [x1, x2, x3, ...]
//! @endcode
//!
//! The `n`th element of the linearization of an `Iterable` can be
//! accessed with the `at` function. In other words, `at(xs, n) == xn`.
//!
//! Note that this notion is precisely the extension of the [linearization]
//! (@ref Foldable-lin) notion of `Foldable`s to the infinite case. This
//! notion is useful for expressing various properties of `Iterable`s,
//! and is used for that elsewhere in the documentation.
//!
//!
//! Compile-time `Iterable`s
//! ------------------------
//! A _compile-time_ `Iterable` is an `Iterable` for which `is_empty`
//! returns a compile-time `Logical`. These structures allow iteration
//! to be done at compile-time, in the sense that the "loop" doing the
//! iteration can be unrolled because the total length of the structure
//! is kown at compile-time.
//!
//! In particular, note that being a compile-time `Iterable` has nothing
//! to do with being finite or infinite. For example, it would be possible
//! to create a sequence representing the Pythagorean triples as
//! `integral_constant`s. Such a sequence would be infinite, but iteration
//! on the sequence would still be done at compile-time. However, if one
//! tried to iterate over _all_ the elements of the sequence, the compiler
//! would loop indefinitely, in contrast to your program looping
//! indefinitely if the sequence was a runtime one.
//!
//! __In the current version of the library, only compile-time `Iterable`s
//! are supported.__ While it would be possible in theory to support
//! runtime `Iterable`s, doing it efficiently is the subject of some
//! research. In particular, follow [this issue][1] for the current
//! status of runtime `Iterable`s.
//!
//!
//! Laws
//! ----
//! First, we require the equality of two `Iterable`s to be related to the
//! equality of the elements in their linearizations. More specifically,
//! if `xs` and `ys` are two `Iterable`s of data type `It`, then
//! @code
//! xs == ys => at(xs, i) == at(ys, i) for all i
//! @endcode
//!
//! This conveys that two `Iterable`s must have the same linearization
//! in order to be considered equal.
//!
//! Secondly, since every `Iterable` is also a `Searchable`, we require
//! the models of `Iterable` and `Searchable` to be consistent. This is
//! made precise by the following laws. For any `Iterable` `xs` with a
//! linearization of `[x1, x2, x3, ...]`,
//! @code
//! any_of(xs, equal.to(z)) <=> xi == z
//! @endcode
//! for some _finite_ index `i`. Furthermore,
//! @code
//! find_if(xs, pred) == just(the first xi such that pred(xi) is satisfied)
//! @endcode
//! or `nothing` if no such `xi` exists.
//!
//!
//! Refined concepts
//! ----------------
//! 1. `Searchable` (free model)\n
//! Any `Iterable` gives rise to a model of `Searchable`, where the keys
//! and the values are both the elements in the structure. Searching for
//! a key is just doing a linear search through the elements of the
//! structure.
//! @include example/iterable/searchable.cpp
//!
//! 2. `Foldable` for finite `Iterable`s\n
//! Every finite `Iterable` gives rise to a model of `Foldable`. For
//! these models to be consistent, we require the models of both `Foldable`
//! and `Iterable` to have the same linearization.
//!
//! @note
//! As explained above, `Iterable`s are also `Searchable`s and their
//! models have to be consistent. By the laws presented here, it also
//! means that the `Foldable` model for finite `Iterable`s has to be
//! consistent with the `Searchable` model.
//!
//! For convenience, finite `Iterable`s must only provide a definition of
//! `length` to model the `Foldable` concept; defining the more powerful
//! `unpack` or `fold_left` is not necessary (but still possible). The
//! default implementation of `unpack` derived from `Iterable` + `length`
//! uses the fact that `at(xs, i)` denotes the `i`th element of `xs`'s
//! linearization, and that the linearization of a finite `Iterable` must
//! be the same as its linearization as a `Foldable`.
//!
//!
//! Concrete models
//! ---------------
//! `hana::tuple`, `hana::string`, `hana::range`
//!
//!
//! [1]: https://github.com/boostorg/hana/issues/40
template <typename It>
struct Iterable;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_ITERABLE_HPP
@@ -0,0 +1,166 @@
/*!
@file
Forward declares `boost::hana::Logical`.
@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)
*/
#ifndef BOOST_HANA_FWD_CONCEPT_LOGICAL_HPP
#define BOOST_HANA_FWD_CONCEPT_LOGICAL_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Logical Logical
//! The `Logical` concept represents types with a truth value.
//!
//! Intuitively, a `Logical` is just a `bool`, or something that can act
//! like one. However, in the context of programming with heterogeneous
//! objects, it becomes extremely important to distinguish between those
//! objects whose truth value is known at compile-time, and those whose
//! truth value is only known at runtime. The reason why this is so
//! important is because it is possible to branch at compile-time on
//! a condition whose truth value is known at compile-time, and hence
//! the return type of the enclosing function can depend on that truth
//! value. However, if the truth value is only known at runtime, then
//! the compiler has to compile both branches (because any or both of
//! them may end up being used), which creates the additional requirement
//! that both branches must evaluate to the same type.
//!
//! More specifically, `Logical` (almost) represents a [boolean algebra][1],
//! which is a mathematical structure encoding the usual properties that
//! allow us to reason with `bool`. The exact properties that must be
//! satisfied by any model of `Logical` are rigorously stated in the laws
//! below.
//!
//!
//! Truth, falsity and logical equivalence
//! --------------------------------------
//! A `Logical` `x` is said to be _true-valued_, or sometimes also just
//! _true_ as an abuse of notation, if
//! @code
//! if_(x, true, false) == true
//! @endcode
//!
//! Similarly, `x` is _false-valued_, or sometimes just _false_, if
//! @code
//! if_(x, true, false) == false
//! @endcode
//!
//! This provides a standard way of converting any `Logical` to a straight
//! `bool`. The notion of truth value suggests another definition, which
//! is that of logical equivalence. We will say that two `Logical`s `x`
//! and `y` are _logically equivalent_ if they have the same truth value.
//! To denote that some expressions `p` and `q` of a Logical data type are
//! logically equivalent, we will sometimes also write
//! @code
//! p if and only if q
//! @endcode
//! which is very common in mathematics. The intuition behind this notation
//! is that whenever `p` is true-valued, then `q` should be; but when `p`
//! is false-valued, then `q` should be too. Hence, `p` should be
//! true-valued when (and only when) `q` is true-valued.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! `eval_if`, `not_` and `while_`
//!
//! All the other functions can be defined in those terms:
//! @code
//! if_(cond, x, y) = eval_if(cond, lazy(x), lazy(y))
//! and_(x, y) = if_(x, y, x)
//! or_(x, y) = if_(x, x, y)
//! etc...
//! @endcode
//!
//!
//! Laws
//! ----
//! As outlined above, the `Logical` concept almost represents a boolean
//! algebra. The rationale for this laxity is to allow things like integers
//! to act like `Logical`s, which is aligned with C++, even though they do
//! not form a boolean algebra. Even though we depart from the usual
//! axiomatization of boolean algebras, we have found through experience
//! that the definition of a Logical given here is largely compatible with
//! intuition.
//!
//! The following laws must be satisfied for any data type `L` modeling
//! the `Logical` concept. Let `a`, `b` and `c` be objects of a `Logical`
//! data type, and let `t` and `f` be arbitrary _true-valued_ and
//! _false-valued_ `Logical`s of that data type, respectively. Then,
//! @code
//! // associativity
//! or_(a, or_(b, c)) == or_(or_(a, b), c)
//! and_(a, and_(b, c)) == and_(and_(a, b), c)
//!
//! // equivalence through commutativity
//! or_(a, b) if and only if or_(b, a)
//! and_(a, b) if and only if and_(b, a)
//!
//! // absorption
//! or_(a, and_(a, b)) == a
//! and_(a, or_(a, b)) == a
//!
//! // left identity
//! or_(a, f) == a
//! and_(a, t) == a
//!
//! // distributivity
//! or_(a, and_(b, c)) == and_(or_(a, b), or_(a, c))
//! and_(a, or_(b, c)) == or_(and_(a, b), and_(a, c))
//!
//! // complements
//! or_(a, not_(a)) is true-valued
//! and_(a, not_(a)) is false-valued
//! @endcode
//!
//! > #### Why is the above not a boolean algebra?
//! > If you look closely, you will find that we depart from the usual
//! > boolean algebras because:
//! > 1. we do not require the elements representing truth and falsity to
//! > be unique
//! > 2. we do not enforce commutativity of the `and_` and `or_` operations
//! > 3. because we do not enforce commutativity, the identity laws become
//! > left-identity laws
//!
//!
//! Concrete models
//! ---------------
//! `hana::integral_constant`
//!
//!
//! Free model for arithmetic data types
//! ------------------------------------
//! A data type `T` is arithmetic if `std::is_arithmetic<T>::%value` is
//! true. For an arithmetic data type `T`, a model of `Logical` is
//! provided automatically by using the result of the builtin implicit
//! conversion to `bool` as a truth value. Specifically, the minimal
//! complete definition for those data types is
//! @code
//! eval_if(cond, then, else_) = cond ? then(id) : else(id)
//! not_(cond) = static_cast<T>(cond ? false : true)
//! while_(pred, state, f) = equivalent to a normal while loop
//! @endcode
//!
//! > #### Rationale for not providing a model for all contextually convertible to bool data types
//! > The `not_` method can not be implemented in a meaningful way for all
//! > of those types. For example, one can not cast a pointer type `T*`
//! > to bool and then back again to `T*` in a meaningful way. With an
//! > arithmetic type `T`, however, it is possible to cast from `T` to
//! > bool and then to `T` again; the result will be `0` or `1` depending
//! > on the truth value. If you want to use a pointer type or something
//! > similar in a conditional, it is suggested to explicitly convert it
//! > to bool by using `to<bool>`.
//!
//!
//! [1]: http://en.wikipedia.org/wiki/Boolean_algebra_(structure)
template <typename L>
struct Logical;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_LOGICAL_HPP
@@ -0,0 +1,99 @@
/*!
@file
Forward declares `boost::hana::Metafunction`.
@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)
*/
#ifndef BOOST_HANA_FWD_CONCEPT_METAFUNCTION_HPP
#define BOOST_HANA_FWD_CONCEPT_METAFUNCTION_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Metafunction Metafunction
//! A `Metafunction` is a function that takes `hana::type`s as inputs and
//! returns a `hana::type` as output.
//!
//! A `Metafunction` is an object satisfying the [FunctionObject][1]
//! concept, but with additional requirements. First, it must be possible
//! to apply a `Metafunction` to arguments whose tag is `type_tag`, and
//! the result of such an application must be an object whose tag is also
//! `type_tag`. Note that `hana::type` and `hana::basic_type` are the
//! only such types.
//!
//! Secondly, a `Metafunction` must provide a nested `::%apply` template
//! which allows performing the same type-level computation as is done by
//! the call operator. In Boost.MPL parlance, a `Metafunction` `F` is
//! hence a [MetafunctionClass][2] in addition to being a `FunctionObject`.
//! Rigorously, the following must be satisfied by any object `f` of type
//! `F` which is a `Metafunction`, and for arbitrary types `T...`:
//! @code
//! f(hana::type_c<T>...) == hana::type_c<F::apply<T...>::type>
//! @endcode
//!
//! Thirdly, to ease the inter-operation of values and types,
//! `Metafunction`s must also allow being called with arguments that
//! are not `hana::type`s. In that case, the result is equivalent to
//! calling the metafunction on the types of the arguments. Rigorously,
//! this means that for arbitrary objects `x...`,
//! @code
//! f(x...) == f(hana::type_c<decltype(x)>...)
//! @endcode
//!
//!
//! Minimal complete definition
//! ---------------------------
//! The `Metafunction` concept does not have a minimal complete definition
//! in terms of tag-dispatched methods. Instead, the syntactic requirements
//! documented above should be satisfied, and the `Metafunction` struct
//! should be specialized explicitly in Hana's namespace.
//!
//!
//! Concrete models
//! ---------------
//! `hana::metafunction`, `hana::metafunction_class`, `hana::template_`
//!
//!
//! Rationale: Why aren't `Metafunction`s `Comparable`?
//! ---------------------------------------------------
//! When seeing `hana::template_`, a question that naturally arises is
//! whether `Metafunction`s should be made `Comparable`. Indeed, it
//! would seem to make sense to compare two templates `F` and `G` with
//! `template_<F> == template_<G>`. However, in the case where `F` and/or
//! `G` are alias templates, it makes sense to talk about two types of
//! comparisons. The first one is _shallow_ comparison, and it determines
//! that two alias templates are equal if they are the same alias
//! template. The second one is _deep_ comparison, and it determines
//! that two template aliases are equal if they alias the same type for
//! any template argument. For example, given `F` and `G` defined as
//! @code
//! template <typename T>
//! using F = void;
//!
//! template <typename T>
//! using G = void;
//! @endcode
//!
//! shallow comparison would determine that `F` and `G` are different
//! because they are two different template aliases, while deep comparison
//! would determine that `F` and `G` are equal because they always
//! expand to the same type, `void`. Unfortunately, deep comparison is
//! impossible to implement because one would have to check `F` and `G`
//! on all possible types. On the other hand, shallow comparison is not
//! satisfactory because `Metafunction`s are nothing but functions on
//! `type`s, and the equality of two functions is normally defined with
//! deep comparison. Hence, we adopt a conservative stance and avoid
//! providing comparison for `Metafunction`s.
//!
//! [1]: http://en.cppreference.com/w/cpp/concept/FunctionObject
//! [2]: http://www.boost.org/doc/libs/release/libs/mpl/doc/refmanual/metafunction-class.html
template <typename F>
struct Metafunction;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_METAFUNCTION_HPP
@@ -0,0 +1,198 @@
/*!
@file
Forward declares `boost::hana::Monad`.
@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)
*/
#ifndef BOOST_HANA_FWD_CONCEPT_MONAD_HPP
#define BOOST_HANA_FWD_CONCEPT_MONAD_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Monad Monad
//! The `Monad` concept represents `Applicative`s with the ability to
//! flatten nested levels of structure.
//!
//! Historically, Monads are a construction coming from category theory,
//! an abstract branch of mathematics. The functional programming
//! community eventually discovered how Monads could be used to
//! formalize several useful things like side effects, which led
//! to the wide adoption of Monads in that community. However, even
//! in a multi-paradigm language like C++, there are several constructs
//! which turn out to be Monads, like `std::optional`, `std::vector` and
//! others.
//!
//! Everybody tries to introduce `Monad`s with a different analogy, and
//! most people fail. This is called the [Monad tutorial fallacy][1]. We
//! will try to avoid this trap by not presenting a specific intuition,
//! and we will instead present what monads are mathematically.
//! For specific intuitions, we will let readers who are new to this
//! concept read one of the many excellent tutorials available online.
//! Understanding Monads might take time at first, but once you get it,
//! a lot of patterns will become obvious Monads; this enlightening will
//! be your reward for the hard work.
//!
//! There are different ways of defining a Monad; Haskell uses a function
//! called `bind` (`>>=`) and another one called `return` (it has nothing
//! to do with C++'s `return` statement). They then introduce relationships
//! that must be satisfied for a type to be a Monad with those functions.
//! Mathematicians sometimes use a function called `join` and another one
//! called `unit`, or they also sometimes use other category theoretic
//! constructions like functor adjunctions and the Kleisli category.
//!
//! This library uses a composite approach. First, we use the `flatten`
//! function (equivalent to `join`) along with the `lift` function from
//! `Applicative` (equivalent to `unit`) to introduce the notion of
//! monadic function composition. We then write the properties that must
//! be satisfied by a Monad using this monadic composition operator,
//! because we feel it shows the link between Monads and Monoids more
//! clearly than other approaches.
//!
//! Roughly speaking, we will say that a `Monad` is an `Applicative` which
//! also defines a way to compose functions returning a monadic result,
//! as opposed to only being able to compose functions returning a normal
//! result. We will then ask for this composition to be associative and to
//! have a neutral element, just like normal function composition. For
//! usual composition, the neutral element is the identity function `id`.
//! For monadic composition, the neutral element is the `lift` function
//! defined by `Applicative`. This construction is made clearer in the
//! laws below.
//!
//! @note
//! Monads are known to be a big chunk to swallow. However, it is out of
//! the scope of this documentation to provide a full-blown explanation
//! of the concept. The [Typeclassopedia][2] is a nice Haskell-oriented
//! resource where more information about Monads can be found.
//!
//!
//! Minimal complete definitions
//! ----------------------------
//! First, a `Monad` must be both a `Functor` and an `Applicative`.
//! Also, an implementation of `flatten` or `chain` satisfying the
//! laws below for monadic composition must be provided.
//!
//! @note
//! The `ap` method for `Applicatives` may be derived from the minimal
//! complete definition of `Monad` and `Functor`; see below for more
//! information.
//!
//!
//! Laws
//! ----
//! To simplify writing the laws, we use the comparison between functions.
//! For two functions `f` and `g`, we define
//! @code
//! f == g if and only if f(x) == g(x) for all x
//! @endcode
//!
//! With the usual composition of functions, we are given two functions
//! @f$ f : A \to B @f$ and @f$ g : B \to C @f$, and we must produce a
//! new function @f$ compose(g, f) : A \to C @f$. This composition of
//! functions is associative, which means that
//! @code
//! compose(h, compose(g, f)) == compose(compose(h, g), f)
//! @endcode
//!
//! Also, this composition has an identity element, which is the identity
//! function. This simply means that
//! @code
//! compose(f, id) == compose(id, f) == f
//! @endcode
//!
//! This is probably nothing new if you are reading the `Monad` laws.
//! Now, we can observe that the above is equivalent to saying that
//! functions with the composition operator form a `Monoid`, where the
//! neutral element is the identity function.
//!
//! Given an `Applicative` `F`, what if we wanted to compose two functions
//! @f$ f : A \to F(B) @f$ and @f$ g : B \to F(C) @f$? When the
//! `Applicative` `F` is also a `Monad`, such functions taking normal
//! values but returning monadic values are called _monadic functions_.
//! To compose them, we obviously can't use normal function composition,
//! since the domains and codomains of `f` and `g` do not match properly.
//! Instead, we'll need a new operator -- let's call it `monadic_compose`:
//! @f[
//! \mathtt{monadic\_compose} :
//! (B \to F(C)) \times (A \to F(B)) \to (A \to F(C))
//! @f]
//!
//! How could we go about implementing this function? Well, since we know
//! `F` is an `Applicative`, the only functions we have are `transform`
//! (from `Functor`), and `lift` and `ap` (from `Applicative`). Hence,
//! the only thing we can do at this point while respecting the signatures
//! of `f` and `g` is to set (for `x` of type `A`)
//! @code
//! monadic_compose(g, f)(x) = transform(f(x), g)
//! @endcode
//!
//! Indeed, `f(x)` is of type `F(B)`, so we can map `g` (which takes `B`'s)
//! on it. Doing so will leave us with a result of type `F(F(C))`, but what
//! we wanted was a result of type `F(C)` to respect the signature of
//! `monadic_compose`. If we had a joker of type @f$ F(F(C)) \to F(C) @f$,
//! we could simply set
//! @code
//! monadic_compose(g, f)(x) = joker(transform(f(x), g))
//! @endcode
//!
//! and we would be happy. It turns out that `flatten` is precisely this
//! joker. Now, we'll want our joker to satisfy some properties to make
//! sure this composition is associative, just like our normal composition
//! was. These properties are slightly cumbersome to specify, so we won't
//! do it here. Also, we'll need some kind of neutral element for the
//! composition. This neutral element can't be the usual identity function,
//! because it does not have the right type: our neutral element needs to
//! be a function of type @f$ X \to F(X) @f$ but the identity function has
//! type @f$ X \to X @f$. It is now the right time to observe that `lift`
//! from `Applicative` has exactly the right signature, and so we'll take
//! this for our neutral element.
//!
//! We are now ready to formulate the `Monad` laws using this composition
//! operator. For a `Monad` `M` and functions @f$ f : A \to M(B) @f$,
//! @f$ g : B \to M(C) @f$ and @f$ h : C \to M(D) @f$, the following
//! must be satisfied:
//! @code
//! // associativity
//! monadic_compose(h, monadic_compose(g, f)) == monadic_compose(monadic_compose(h, g), f)
//!
//! // right identity
//! monadic_compose(f, lift<M(A)>) == f
//!
//! // left identity
//! monadic_compose(lift<M(B)>, f) == f
//! @endcode
//!
//! which is to say that `M` along with monadic composition is a Monoid
//! where the neutral element is `lift`.
//!
//!
//! Refined concepts
//! ----------------
//! 1. `Functor`
//! 2. `Applicative` (free implementation of `ap`)\n
//! When the minimal complete definition for `Monad` and `Functor` are
//! both satisfied, it is possible to implement `ap` by setting
//! @code
//! ap(fs, xs) = chain(fs, [](auto f) {
//! return transform(xs, f);
//! })
//! @endcode
//!
//!
//! Concrete models
//! ---------------
//! `hana::lazy`, `hana::optional`, `hana::tuple`
//!
//!
//! [1]: https://byorgey.wordpress.com/2009/01/12/abstraction-intuition-and-the-monad-tutorial-fallacy/
//! [2]: https://wiki.haskell.org/Typeclassopedia#Monad
template <typename M>
struct Monad;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_MONAD_HPP
@@ -0,0 +1,89 @@
/*!
@file
Forward declares `boost::hana::MonadPlus`.
@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)
*/
#ifndef BOOST_HANA_FWD_CONCEPT_MONAD_PLUS_HPP
#define BOOST_HANA_FWD_CONCEPT_MONAD_PLUS_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-MonadPlus MonadPlus
//! The `MonadPlus` concept represents Monads with a monoidal structure.
//!
//! Intuitively, whereas a Monad can be seen as some kind of container
//! or context, a MonadPlus can be seen as a container or a context that
//! can be concatenated with other containers or contexts. There must
//! also be an identity element for this combining operation. For example,
//! a tuple is a MonadPlus, because tuples can be concatenated and the
//! empty tuple would act as an identity for concatenation. How is this
//! different from a Monad which is also a Monoid? The answer is that the
//! monoidal structure on a MonadPlus must _not_ depend of the contents
//! of the structure; it must not require the contents to be a Monoid
//! in order to work.
//!
//! While sequences are not the only possible model for MonadPlus, the
//! method names used here refer to the MonadPlus of sequences under
//! concatenation. Several useful functions generalizing operations on
//! sequences are included with this concept, like `append`, `prepend`
//! and `filter`.
//!
//! @note
//! This documentation does not go into much details about the nature
//! of the MonadPlus concept. However, there is a nice Haskell-oriented
//! [WikiBook][1] going into further details.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! `concat` and `empty`
//!
//!
//! Laws
//! ----
//! First, a MonadPlus is required to have a monoidal structure. Hence, it
//! is no surprise that for any MonadPlus `M`, we require `M(T)` to be a
//! valid monoid. However, we do not enforce that `M(T)` actually models
//! the Monoid concept provided by Hana. Further, for all objects `a, b, c`
//! of data type `M(T)`,
//! @code
//! // identity
//! concat(empty<M(T)>(), a) == a
//! concat(a, empty<M(T)>()) == a
//!
//! // associativity
//! concat(a, concat(b, c)) == concat(concat(a, b), c)
//! @endcode
//!
//! Secondly, a MonadPlus is also required to obey the following laws,
//! which represent the fact that `empty<M(T)>()` must be some kind of
//! absorbing element for the `chain` operation. For all objects `a` of
//! data type `M(T)` and functions @f$ f : T \to M(U) @f$,
//! @code
//! chain(empty<M(T)>(), f) == empty<M(U)>()
//! chain(a, always(empty<M(T)>())) == empty<M(U)>()
//! @endcode
//!
//!
//! Refined concepts
//! ----------------
//! `Functor`, `Applicative` and `Monad`
//!
//!
//! Concrete models
//! ---------------
//! `hana::optional`, `hana::tuple`
//!
//! [1]: https://en.wikibooks.org/wiki/Haskell/MonadPlus
template <typename M>
struct MonadPlus;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_MONAD_PLUS_HPP
@@ -0,0 +1,101 @@
/*!
@file
Forward declares `boost::hana::Monoid`.
@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)
*/
#ifndef BOOST_HANA_FWD_CONCEPT_MONOID_HPP
#define BOOST_HANA_FWD_CONCEPT_MONOID_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Monoid Monoid
//! The `Monoid` concept represents data types with an associative
//! binary operation that has an identity.
//!
//! Specifically, a [Monoid][1] is a basic algebraic structure typically
//! used in mathematics to construct more complex algebraic structures
//! like `Group`s, `Ring`s and so on. They are useful in several contexts,
//! notably to define the properties of numbers in a granular way. At its
//! core, a `Monoid` is a set `S` of objects along with a binary operation
//! (let's say `+`) that is associative and that has an identity in `S`.
//! There are many examples of `Monoid`s:
//! - strings with concatenation and the empty string as the identity
//! - integers with addition and `0` as the identity
//! - integers with multiplication and `1` as the identity
//! - many others...
//!
//! As you can see with the integers, there are some sets that can be
//! viewed as a monoid in more than one way, depending on the choice
//! of the binary operation and identity. The method names used here
//! refer to the monoid of integers under addition; `plus` is the binary
//! operation and `zero` is the identity element of that operation.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! `plus` and `zero` satisfying the laws
//!
//!
//! Laws
//! ----
//! For all objects `x`, `y` and `z` of a `Monoid` `M`, the following
//! laws must be satisfied:
//! @code
//! plus(zero<M>(), x) == x // left zero
//! plus(x, zero<M>()) == x // right zero
//! plus(x, plus(y, z)) == plus(plus(x, y), z) // associativity
//! @endcode
//!
//!
//! Concrete models
//! ---------------
//! `hana::integral_constant`
//!
//!
//! Free model for non-boolean arithmetic data types
//! ------------------------------------------------
//! A data type `T` is arithmetic if `std::is_arithmetic<T>::%value` is
//! true. For a non-boolean arithmetic data type `T`, a model of `Monoid`
//! is automatically defined by setting
//! @code
//! plus(x, y) = (x + y)
//! zero<T>() = static_cast<T>(0)
//! @endcode
//!
//! > #### Rationale for not making `bool` a `Monoid` by default
//! > First, it makes no sense whatsoever to define an additive `Monoid`
//! > over the `bool` type. Also, it could make sense to define a `Monoid`
//! > with logical conjunction or disjunction. However, C++ allows `bool`s
//! > to be added, and the method names of this concept really suggest
//! > addition. In line with the principle of least surprise, no model
//! > is provided by default.
//!
//!
//! Structure-preserving functions
//! ------------------------------
//! Let `A` and `B` be two `Monoid`s. A function `f : A -> B` is said
//! to be a [Monoid morphism][2] if it preserves the monoidal structure
//! between `A` and `B`. Rigorously, for all objects `x, y` of data
//! type `A`,
//! @code
//! f(plus(x, y)) == plus(f(x), f(y))
//! f(zero<A>()) == zero<B>()
//! @endcode
//! Functions with these properties interact nicely with `Monoid`s, which
//! is why they are given such a special treatment.
//!
//!
//! [1]: http://en.wikipedia.org/wiki/Monoid
//! [2]: http://en.wikipedia.org/wiki/Monoid#Monoid_homomorphisms
template <typename M>
struct Monoid;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_MONOID_HPP
@@ -0,0 +1,187 @@
/*!
@file
Forward declares `boost::hana::Orderable`.
@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)
*/
#ifndef BOOST_HANA_FWD_CONCEPT_ORDERABLE_HPP
#define BOOST_HANA_FWD_CONCEPT_ORDERABLE_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Orderable Orderable
//! The `Orderable` concept represents totally ordered data types.
//!
//! Intuitively, `Orderable` objects must define a binary predicate named
//! `less` returning whether the first argument is to be considered less
//! than the second argument. The word "total" means that _distinct_
//! objects must always be ordered; if `a` and `b` are not equal, then
//! exactly one of `less(a, b)` and `less(b, a)` must be true. This is
//! a contrast with weaker kinds of orders that would allow some objects
//! to be incomparable (neither less than nor greater than). Also note
//! that a non-strict total order may always be obtained from a strict
//! total order (and vice-versa) by setting
//! @code
//! a <= b = !(b < a)
//! a < b = !(b <= a)
//! @endcode
//! The non-strict version is used in the description of the laws because
//! it makes them easier to parse for humans, but they could be formulated
//! equivalently using the strict order.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! `less`
//!
//! When `less` is defined, the other methods are defined from it using
//! the same definition as mandated in the laws below.
//!
//!
//! Laws
//! ----
//! Rigorously speaking, a [total order][1] `<=` on a set `S` is a binary
//! predicate @f$ <= \;: S \times S \to bool @f$ such that for all
//! `a`, `b`, `c` in `S`,
//! @code
//! if a <= b and b <= a then a == b // Antisymmetry
//! if a <= b and b <= c then a <= c // Transitivity
//! either a <= b or b <= a // Totality
//! @endcode
//! Additionally, the `less`, `greater` and `greater_equal` methods should
//! have the following intuitive meanings:
//! @code
//! a < b if and only if !(b <= a)
//! a > b if and only if b < a
//! a >= b if and only if !(a < b)
//! @endcode
//!
//!
//! Refined concept
//! ---------------
//! 1. `Comparable` (free model)\n
//! Since `Orderable` requires `less_equal` to be a total order, a model
//! of `Comparable` may always be obtained by setting
//! @code
//! equal(x, y) = less_equal(x, y) && less_equal(y, x)
//! @endcode
//!
//!
//! Concrete models
//! ---------------
//! `hana::integral_constant`, `hana::optional`, `hana::pair`,
//! `hana::string`, `hana::tuple`
//!
//!
//! Free model for `LessThanComparable` data types
//! ----------------------------------------------
//! Two data types `T` and `U` that model the cross-type version of the
//! usual [LessThanComparable][2] C++ concept are automatically a model
//! of `Orderable` by setting
//! @code
//! less(x, y) = (x < y)
//! @endcode
//! The cross-type version of the LessThanComparable concept is analogous
//! to the cross-type version of the EqualityComparable concept presented
//! in [N3351][3], which is compatible with the usual single type
//! definition.
//! However, note that the LessThanComparable concept only requires `<`
//! to be a [strict weak ordering][4], which is a weaker requirement
//! than being a total order. Hence, if `less` is used with objects
//! of a LessThanComparable data type that do not define a total order,
//! some algorithms may have an unexpected behavior. It is the author's
//! opinion that defining `operator<` as a non-total order is a bad idea,
//! but this is debatable and so the design choice of providing a model
//! for LessThanComparable data types is open to debate. Waiting for
//! some user input.
//!
//!
//! Order-preserving functions
//! --------------------------
//! Let `A` and `B` be two `Orderable` data types. A function
//! @f$ f : A \to B@f$ is said to be order-preserving (also called
//! monotone) if it preserves the structure of the `Orderable` concept,
//! which can be rigorously stated as follows. For all objects `x`, `y`
//! of data type `A`,
//! @code
//! if less(x, y) then less(f(x), f(y))
//! @endcode
//! Another important property is that of being order-reflecting, which
//! can be stated as
//! @code
//! if less(f(x), f(y)) then less(x, y)
//! @endcode
//! We say that a function is an order-embedding if it is both
//! order-preserving and order-reflecting, i.e. if
//! @code
//! less(x, y) if and only if less(f(x), f(y))
//! @endcode
//!
//!
//! Cross-type version of the methods
//! ---------------------------------
//! The comparison methods (`less`, `less_equal`, `greater` and
//! `greater_equal`) are "overloaded" to handle distinct data types
//! with certain properties. Specifically, they are defined for
//! _distinct_ data types `A` and `B` such that
//! 1. `A` and `B` share a common data type `C`, as determined by the
//! `common` metafunction
//! 2. `A`, `B` and `C` are all `Orderable` when taken individually
//! 3. @f$\mathrm{to<C>} : A \to C@f$ and @f$\mathrm{to<C>} : B \to C@f$
//! are both order-embeddings as determined by the `is_embedding`
//! metafunction.
//!
//! The method definitions for data types satisfying the above
//! properties are
//! @code
//! less(x, y) = less(to<C>(x), to<C>(y))
//! less_equal(x, y) = less_equal(to<C>(x), to<C>(y))
//! greater_equal(x, y) = greater_equal(to<C>(x), to<C>(y))
//! greater(x, y) = greater(to<C>(x), to<C>(y))
//! @endcode
//!
//!
//! Partial application of the methods
//! ----------------------------------
//! The `less`, `greater`, `less_equal` and `greater_equal` methods can
//! be called in two different ways. First, they can be called like
//! normal functions:
//! @code
//! less(x, y)
//! greater(x, y)
//!
//! less_equal(x, y)
//! greater_equal(x, y)
//! @endcode
//!
//! However, they may also be partially applied to an argument as follows:
//! @code
//! less.than(x)(y) == less(y, x)
//! greater.than(x)(y) == greater(y, x)
//!
//! less_equal.than(x)(y) == less_equal(y, x)
//! greater_equal.than(x)(y) == greater_equal(y, x)
//! @endcode
//!
//! Take good note that the order of the arguments is reversed, so
//! for example `less.than(x)(y)` is equivalent to `less(y, x)`, not
//! `less(x, y)`. This is because those variants are meant to be used
//! with higher order algorithms, where the chosen application order
//! makes sense.
//!
//!
//! [1]: http://en.wikipedia.org/wiki/Total_order
//! [2]: http://en.cppreference.com/w/cpp/concept/LessThanComparable
//! [3]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3351.pdf
//! [4]: http://en.wikipedia.org/wiki/Strict_weak_ordering
template <typename Ord>
struct Orderable;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_ORDERABLE_HPP
@@ -0,0 +1,103 @@
/*!
@file
Forward declares `boost::hana::Product`.
@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)
*/
#ifndef BOOST_HANA_FWD_CONCEPT_PRODUCT_HPP
#define BOOST_HANA_FWD_CONCEPT_PRODUCT_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Product Product
//! Represents types that are generic containers of two elements.
//!
//! This concept basically represents types that are like `std::pair`.
//! The motivation for making such a precise concept is similar to the
//! motivation behind the `Sequence` concept; there are many different
//! implementations of `std::pair` in different libraries, and we would
//! like to manipulate any of them generically.
//!
//! Since a `Product` is basically a pair, it is unsurprising that the
//! operations provided by this concept are getting the first and second
//! element of a pair, creating a pair from two elements and other
//! simmilar operations.
//!
//! @note
//! Mathematically, this concept represents types that are category
//! theoretical [products][1]. This is also where the name comes
//! from.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! `first`, `second` and `make`
//!
//! `first` and `second` must obviously return the first and the second
//! element of the pair, respectively. `make` must take two arguments `x`
//! and `y` representing the first and the second element of the pair,
//! and return a pair `p` such that `first(p) == x` and `second(p) == y`.
//! @include example/product/make.cpp
//!
//!
//! Laws
//! ----
//! For a model `P` of `Product`, the following laws must be satisfied.
//! For every data types `X` and `Y`, there must be a unique function
//! @f$ \mathtt{make} : X \times Y \to P @f$ such that for every `x`, `y`,
//! @code
//! x == first(make<P>(x, y))
//! y == second(make<P>(x, y))
//! @endcode
//!
//! @note
//! This law is less general than the universal property typically used to
//! define category theoretical products, but it is vastly enough for what
//! we need.
//!
//! This is basically saying that a `Product` must be the most general
//! object able to contain a pair of objects `(P1, P2)`, but nothing
//! more. Since the categorical product is defined by a universal
//! property, all the models of this concept are isomorphic, and
//! the isomorphism is unique. In other words, there is one and only
//! one way to convert one `Product` to another.
//!
//! Another property that must be satisfied by `first` and `second` is
//! that of @ref move-independence, which ensures that we can optimally
//! decompose a `Product` into its two members without making redundant
//! copies.
//!
//!
//! Refined concepts
//! ----------------
//! 1. `Comparable` (free model)\n
//! Two products `x` and `y` are equal iff they are equal element-wise,
//! by comparing the first element before the second element.
//! @include example/product/comparable.cpp
//!
//! 2. `Orderable` (free model)\n
//! Products are ordered using a lexicographical ordering as-if they
//! were 2-element tuples.
//!
//! 3. `Foldable` (free model)\n
//! Folding a `Product` `p` is equivalent to folding a list containing
//! `first(p)` and `second(p)`, in that order.
//!
//!
//! Concrete models
//! ---------------
//! `hana::pair`
//!
//!
//! [1]: http://en.wikipedia.org/wiki/Product_(category_theory)
template <typename P>
struct Product;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_PRODUCT_HPP
@@ -0,0 +1,106 @@
/*!
@file
Forward declares `boost::hana::Ring`.
@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)
*/
#ifndef BOOST_HANA_FWD_CONCEPT_RING_HPP
#define BOOST_HANA_FWD_CONCEPT_RING_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Ring Ring
//! The `Ring` concept represents `Group`s that also form a `Monoid`
//! under a second binary operation that distributes over the first.
//!
//! A [Ring][1] is an algebraic structure built on top of a `Group`
//! which requires a monoidal structure with respect to a second binary
//! operation. This second binary operation must distribute over the
//! first one. Specifically, a `Ring` is a triple `(S, +, *)` such that
//! `(S, +)` is a `Group`, `(S, *)` is a `Monoid` and `*` distributes
//! over `+`, i.e.
//! @code
//! x * (y + z) == (x * y) + (x * z)
//! @endcode
//!
//! The second binary operation is often written `*` with its identity
//! written `1`, in reference to the `Ring` of integers under
//! multiplication. The method names used here refer to this exact ring.
//!
//!
//! Minimal complete definintion
//! ----------------------------
//! `one` and `mult` satisfying the laws
//!
//!
//! Laws
//! ----
//! For all objects `x`, `y`, `z` of a `Ring` `R`, the following laws must
//! be satisfied:
//! @code
//! mult(x, mult(y, z)) == mult(mult(x, y), z) // associativity
//! mult(x, one<R>()) == x // right identity
//! mult(one<R>(), x) == x // left identity
//! mult(x, plus(y, z)) == plus(mult(x, y), mult(x, z)) // distributivity
//! @endcode
//!
//!
//! Refined concepts
//! ----------------
//! `Monoid`, `Group`
//!
//!
//! Concrete models
//! ---------------
//! `hana::integral_constant`
//!
//!
//! Free model for non-boolean arithmetic data types
//! ------------------------------------------------
//! A data type `T` is arithmetic if `std::is_arithmetic<T>::%value` is
//! true. For a non-boolean arithmetic data type `T`, a model of `Ring` is
//! automatically defined by using the provided `Group` model and setting
//! @code
//! mult(x, y) = (x * y)
//! one<T>() = static_cast<T>(1)
//! @endcode
//!
//! @note
//! The rationale for not providing a Ring model for `bool` is the same
//! as for not providing Monoid and Group models.
//!
//!
//! Structure-preserving functions
//! ------------------------------
//! Let `A` and `B` be two `Ring`s. A function `f : A -> B` is said to
//! be a [Ring morphism][2] if it preserves the ring structure between
//! `A` and `B`. Rigorously, for all objects `x, y` of data type `A`,
//! @code
//! f(plus(x, y)) == plus(f(x), f(y))
//! f(mult(x, y)) == mult(f(x), f(y))
//! f(one<A>()) == one<B>()
//! @endcode
//! Because of the `Ring` structure, it is easy to prove that the
//! following will then also be satisfied:
//! @code
//! f(zero<A>()) == zero<B>()
//! f(negate(x)) == negate(f(x))
//! @endcode
//! which is to say that `f` will then also be a `Group` morphism.
//! Functions with these properties interact nicely with `Ring`s,
//! which is why they are given such a special treatment.
//!
//!
//! [1]: http://en.wikipedia.org/wiki/Ring_(mathematics)
//! [2]: http://en.wikipedia.org/wiki/Ring_homomorphism
template <typename R>
struct Ring;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_RING_HPP
@@ -0,0 +1,143 @@
/*!
@file
Forward declares `boost::hana::Searchable`.
@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)
*/
#ifndef BOOST_HANA_FWD_CONCEPT_SEARCHABLE_HPP
#define BOOST_HANA_FWD_CONCEPT_SEARCHABLE_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Searchable Searchable
//! The `Searchable` concept represents structures that can be searched.
//!
//! Intuitively, a `Searchable` is any structure, finite or infinite,
//! containing elements that can be searched using a predicate. Sometimes,
//! `Searchable`s will associate keys to values; one can search for a key
//! with a predicate, and the value associated to it is returned. This
//! gives rise to map-like data structures. Other times, the elements of
//! the structure that are searched (i.e. those to which the predicate is
//! applied) are the same that are returned, which gives rise to set-like
//! data structures. In general, we will refer to the _keys_ of a
//! `Searchable` structure as those elements that are used for searching,
//! and to the _values_ of a `Searchable` as those elements that are
//! returned when a search is successful. As was explained, there is no
//! requirement that both notions differ, and it is often useful to have
//! keys and values coincide (think about `std::set`).
//!
//! Some methods like `any_of`, `all_of` and `none_of` allow simple queries
//! to be performed on the keys of the structure, while other methods like
//! `find` and `find_if` make it possible to find the value associated
//! to a key. The most specific method should always be used if one
//! cares about performance, because it is usually the case that heavy
//! optimizations can be performed in more specific methods. For example,
//! an associative data structure implemented as a hash table will be much
//! faster to access using `find` than `find_if`, because in the second
//! case it will have to do a linear search through all the entries.
//! Similarly, using `contains` will likely be much faster than `any_of`
//! with an equivalent predicate.
//!
//! > __Insight__\n
//! > In a lazy evaluation context, any `Foldable` can also become a model
//! > of `Searchable` because we can search lazily through the structure
//! > with `fold_right`. However, in the context of C++, some `Searchable`s
//! > can not be folded; think for example of an infinite set.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! `find_if` and `any_of`
//!
//! When `find_if` and `any_of` are provided, the other functions are
//! implemented according to the laws explained below.
//!
//! @note
//! We could implement `any_of(xs, pred)` by checking whether
//! `find_if(xs, pred)` is an empty `optional` or not, and then reduce
//! the minimal complete definition to `find_if`. However, this is not
//! done because that implementation requires the predicate of `any_of`
//! to return a compile-time `Logical`, which is more restrictive than
//! what we have right now.
//!
//!
//! Laws
//! ----
//! In order for the semantics of the methods to be consistent, some
//! properties must be satisfied by any model of the `Searchable` concept.
//! Rigorously, for any `Searchable`s `xs` and `ys` and any predicate `p`,
//! the following laws should be satisfied:
//! @code
//! any_of(xs, p) <=> !all_of(xs, negated p)
//! <=> !none_of(xs, p)
//!
//! contains(xs, x) <=> any_of(xs, equal.to(x))
//!
//! find(xs, x) == find_if(xs, equal.to(x))
//! find_if(xs, always(false_)) == nothing
//!
//! is_subset(xs, ys) <=> all_of(xs, [](auto x) { return contains(ys, x); })
//! is_disjoint(xs, ys) <=> none_of(xs, [](auto x) { return contains(ys, x); })
//! @endcode
//!
//! Additionally, if all the keys of the `Searchable` are `Logical`s,
//! the following laws should be satisfied:
//! @code
//! any(xs) <=> any_of(xs, id)
//! all(xs) <=> all_of(xs, id)
//! none(xs) <=> none_of(xs, id)
//! @endcode
//!
//!
//! Concrete models
//! ---------------
//! `hana::map`, `hana::optional`, `hana::range`, `hana::set`,
//! `hana::string`, `hana::tuple`
//!
//!
//! Free model for builtin arrays
//! -----------------------------
//! Builtin arrays whose size is known can be searched as-if they were
//! homogeneous tuples. However, since arrays can only hold objects of
//! a single type and the predicate to `find_if` must return a compile-time
//! `Logical`, the `find_if` method is fairly useless. For similar reasons,
//! the `find` method is also fairly useless. This model is provided mainly
//! because of the `any_of` method & friends, which are both useful and
//! compile-time efficient.
//!
//!
//! Structure preserving functions
//! ------------------------------
//! Given two `Searchables` `S1` and `S2`, a function
//! @f$ f : S_1(X) \to S_2(X) @f$ is said to preserve the `Searchable`
//! structure if for all `xs` of data type `S1(X)` and predicates
//! @f$ \mathtt{pred} : X \to Bool @f$ (for a `Logical` `Bool`),
//! @code
//! any_of(xs, pred) if and only if any_of(f(xs), pred)
//! find_if(xs, pred) == find_if(f(xs), pred)
//! @endcode
//!
//! This is really just a generalization of the following, more intuitive
//! requirements. For all `xs` of data type `S1(X)` and `x` of data type
//! `X`,
//! @code
//! x ^in^ xs if and only if x ^in^ f(xs)
//! find(xs, x) == find(f(xs), x)
//! @endcode
//!
//! These requirements can be understood as saying that `f` does not
//! change the content of `xs`, although it may reorder elements.
//! As usual, such a structure-preserving transformation is said to
//! be an embedding if it is also injective, i.e. if it is a lossless
//! transformation.
template <typename S>
struct Searchable;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_SEARCHABLE_HPP
@@ -0,0 +1,165 @@
/*!
@file
Forward declares `boost::hana::Sequence`.
@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)
*/
#ifndef BOOST_HANA_FWD_CONCEPT_SEQUENCE_HPP
#define BOOST_HANA_FWD_CONCEPT_SEQUENCE_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Sequence Sequence
//! The `Sequence` concept represents generic index-based sequences.
//!
//! Compared to other abstract concepts, the Sequence concept is very
//! specific. It represents generic index-based sequences. The reason
//! why such a specific concept is provided is because there are a lot
//! of models that behave exactly the same while being implemented in
//! wildly different ways. It is useful to regroup all those data types
//! under the same umbrella for the purpose of generic programming.
//!
//! In fact, models of this concept are not only _similar_. They are
//! actually _isomorphic_, in a sense that we define below, which is
//! a fancy way of rigorously saying that they behave exactly the same
//! to an external observer.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! `Iterable`, `Foldable`, and `make`
//!
//! The `Sequence` concept does not provide basic methods that could be
//! used as a minimal complete definition; instead, it borrows methods
//! from other concepts and add laws to them. For this reason, it is
//! necessary to specialize the `Sequence` metafunction in Hana's
//! namespace to tell Hana that a type is indeed a `Sequence`. Explicitly
//! specializing the `Sequence` metafunction can be seen like a seal
//! saying "this data type satisfies the additional laws of a `Sequence`",
//! since those can't be checked by Hana automatically.
//!
//!
//! Laws
//! ----
//! The laws for being a `Sequence` are simple, and their goal is to
//! restrict the semantics that can be associated to the functions
//! provided by other concepts. First, a `Sequence` must be a finite
//! `Iterable` (thus a `Foldable` too). Secondly, for a `Sequence` tag
//! `S`, `make<S>(x1, ..., xn)` must be an object of tag `S` and whose
//! linearization is `[x1, ..., xn]`. This basically ensures that objects
//! of tag `S` are equivalent to their linearization, and that they can
//! be created from such a linearization (with `make`).
//!
//! While it would be possible in theory to handle infinite sequences,
//! doing so complicates the implementation of many algorithms. For
//! simplicity, the current version of the library only handles finite
//! sequences. However, note that this does not affect in any way the
//! potential for having infinite `Searchable`s and `Iterable`s.
//!
//!
//! Refined concepts
//! ----------------
//! 1. `Comparable` (definition provided automatically)\n
//! Two `Sequence`s are equal if and only if they contain the same number
//! of elements and their elements at any given index are equal.
//! @include example/sequence/comparable.cpp
//!
//! 2. `Orderable` (definition provided automatically)\n
//! `Sequence`s are ordered using the traditional lexicographical ordering.
//! @include example/sequence/orderable.cpp
//!
//! 3. `Functor` (definition provided automatically)\n
//! `Sequence`s implement `transform` as the mapping of a function over
//! each element of the sequence. This is somewhat equivalent to what
//! `std::transform` does to ranges of iterators. Also note that mapping
//! a function over an empty sequence returns an empty sequence and never
//! applies the function, as would be expected.
//! @include example/sequence/functor.cpp
//!
//! 4. `Applicative` (definition provided automatically)\n
//! First, `lift`ing a value into a `Sequence` is the same as creating a
//! singleton sequence containing that value. Second, applying a sequence
//! of functions to a sequence of values will apply each function to
//! all the values in the sequence, and then return a list of all the
//! results. In other words,
//! @code
//! ap([f1, ..., fN], [x1, ..., xM]) == [
//! f1(x1), ..., f1(xM),
//! ...
//! fN(x1), ..., fN(xM)
//! ]
//! @endcode
//! Example:
//! @include example/sequence/applicative.cpp
//!
//! 5. `Monad` (definition provided automatically)\n
//! First, `flaten`ning a `Sequence` takes a sequence of sequences and
//! concatenates them to get a larger sequence. In other words,
//! @code
//! flatten([[a1, ..., aN], ..., [z1, ..., zM]]) == [
//! a1, ..., aN, ..., z1, ..., zM
//! ]
//! @endcode
//! This acts like a `std::tuple_cat` function, except it receives a
//! sequence of sequences instead of a variadic pack of sequences to
//! flatten.\n
//! __Example__:
//! @include example/sequence/monad.ints.cpp
//! Also note that the model of `Monad` for `Sequence`s can be seen as
//! modeling nondeterminism. A nondeterministic computation can be
//! modeled as a function which returns a sequence of possible results.
//! In this line of thought, `chain`ing a sequence of values into such
//! a function will return a sequence of all the possible output values,
//! i.e. a sequence of all the values applied to all the functions in
//! the sequences.\n
//! __Example__:
//! @include example/sequence/monad.types.cpp
//!
//! 6. `MonadPlus` (definition provided automatically)\n
//! `Sequence`s are models of the `MonadPlus` concept by considering the
//! empty sequence as the unit of `concat`, and sequence concatenation
//! as `concat`.
//! @include example/sequence/monad_plus.cpp
//!
//! 7. `Foldable`\n
//! The model of `Foldable` for `Sequence`s is uniquely determined by the
//! model of `Iterable`.
//! @include example/sequence/foldable.cpp
//!
//! 8. `Iterable`\n
//! The model of `Iterable` for `Sequence`s corresponds to iteration over
//! each element of the sequence, in order. This model is not provided
//! automatically, and it is in fact part of the minimal complete
//! definition for the `Sequence` concept.
//! @include example/sequence/iterable.cpp
//!
//! 9. `Searchable` (definition provided automatically)\n
//! Searching through a `Sequence` is equivalent to just searching through
//! a list of the values it contains. The keys and the values on which
//! the search is performed are both the elements of the sequence.
//! @include example/sequence/searchable.cpp
//!
//!
//! Concrete models
//! ---------------
//! `hana::tuple`
//!
//!
//! [1]: http://en.wikipedia.org/wiki/Isomorphism#Isomorphism_vs._bijective_morphism
#ifdef BOOST_HANA_DOXYGEN_INVOKED
template <typename S>
struct Sequence;
#else
template <typename S, typename = void>
struct Sequence : Sequence<S, when<true>> { };
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_SEQUENCE_HPP
@@ -0,0 +1,156 @@
/*!
@file
Forward declares `boost::hana::Struct`.
@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)
*/
#ifndef BOOST_HANA_FWD_CONCEPT_STRUCT_HPP
#define BOOST_HANA_FWD_CONCEPT_STRUCT_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-Struct Struct
//! The `Struct` concept represents `struct`-like user-defined types.
//!
//! The `Struct` concept allows restricted compile-time reflection over
//! user-defined types. In particular, it allows accessing the names of
//! the members of a user-defined type, and also the value of those
//! members. `Struct`s can also be folded, searched and converted to
//! some types of containers, where more advanced transformations can
//! be performed.
//!
//! While all types can _in theory_ be made `Struct`s, only a subset of
//! them are actually interesting to see as such. More precisely, it is
//! only interesting to make a type a `Struct` when it is conceptually
//! a C++ `struct`, i.e. a mostly dumb aggregate of named data. The way
//! this data is accessed is mostly unimportant to the `Struct` concept;
//! it could be through getters and setters, through public members,
//! through non-member functions or it could even be generated on-the-fly.
//! The important part, which is made precise below, is that those accessor
//! methods should be move-independent.
//!
//! Another way to see a `Struct` is as a map where the keys are the names
//! of the members and the values are the values of those members. However,
//! there are subtle differences like the fact that one can't add a member
//! to a `Struct`, and also that the order of the members inside a `Struct`
//! plays a role in determining the equality of `Struct`s, which is not
//! the case for maps.
//!
//!
//! Minimal complete definition
//! ---------------------------
//! `accessors`
//!
//! A model of `Struct` is created by specifying a sequence of key/value
//! pairs with the `accessors` function. The first element of a pair in
//! this sequence represents the "name" of a member of the `Struct`, while
//! the second element is a function which retrieves this member from an
//! object. The "names" do not have to be in any special form; they just
//! have to be compile-time `Comparable`. For example, it is common to
//! provide "names" that are `hana::string`s representing the actual names
//! of the members, but one could provide `hana::integral_constant`s just
//! as well. The values must be functions which, when given an object,
//! retrieve the appropriate member from it.
//!
//! There are several ways of providing the `accessors` method, some of
//! which are more flexible and others which are more convenient. First,
//! one can define it through tag-dispatching, as usual.
//! @snippet example/struct.mcd.tag_dispatching.cpp main
//!
//! Secondly, it is possible to provide a nested `hana_accessors_impl`
//! type, which should be equivalent to a specialization of
//! `accessors_impl` for tag-dispatching. However, for a type `S`, this
//! technique only works when the data type of `S` is `S` itself, which
//! is the case unless you explicitly asked for something else.
//! @snippet example/struct.mcd.nested.cpp main
//!
//! Finally, the most convenient (but least flexible) option is to use
//! the `BOOST_HANA_DEFINE_STRUCT`, the `BOOST_HANA_ADAPT_STRUCT` or the
//! `BOOST_HANA_ADAPT_ADT` macro, which provide a minimal syntactic
//! overhead. See the documentation of these macros for details on how
//! to use them.
//!
//! Also note that it is not important that the accessor functions retrieve
//! an actual member of the struct (e.g. `x.member`). Indeed, an accessor
//! function could call a custom getter or even compute the value of the
//! member on the fly:
//! @snippet example/struct.custom_accessor.cpp main
//!
//! The only important thing is that the accessor functions are
//! move-independent, a notion which is defined below.
//!
//!
//! @anchor move-independence
//! Move-independence
//! -----------------
//! The notion of move-independence presented here defines rigorously
//! when it is legitimate to "double-move" from an object.
//!
//! A collection of functions `f1, ..., fn` sharing the same domain is
//! said to be _move-independent_ if for every fresh (not moved-from)
//! object `x` in the domain, any permutation of the following statements
//! is valid and leaves the `zk` objects in a fresh (not moved-from) state:
//! @code
//! auto z1 = f1(std::move(x));
//! ...
//! auto zn = fn(std::move(x));
//! @endcode
//!
//! @note
//! In the special case where some functions return objects that can't be
//! bound to with `auto zk =` (like `void` or a non-movable, non-copyable
//! type), just pretend the return value is ignored.
//!
//! Intuitively, this ensures that we can treat `f1, ..., fn` as
//! "accessors" that decompose `x` into independent subobjects, and
//! that do so without moving from `x` more than that subobject. This
//! is important because it allows us to optimally decompose `Struct`s
//! into their subparts inside the library.
//!
//!
//! Laws
//! ----
//! For any `Struct` `S`, the accessors in the `accessors<S>()` sequence
//! must be move-independent, as defined above.
//!
//!
//! Refined concepts
//! ----------------
//! 1. `Comparable` (free model)\n
//! `Struct`s are required to be `Comparable`. Specifically, two `Struct`s
//! of the same data type `S` must be equal if and only if all of their
//! members are equal. By default, a model of `Comparable` doing just that
//! is provided for models of `Struct`. In particular, note that the
//! comparison of the members is made in the same order as they appear in
//! the `hana::members` sequence.
//! @include example/struct/comparable.cpp
//!
//! 2. `Foldable` (free model)\n
//! A `Struct` can be folded by considering it as a list of pairs each
//! containing the name of a member and the value associated to that
//! member, in the same order as they appear in the `hana::members`
//! sequence. By default, a model of `Foldable` doing just that is
//! provided for models of the `Struct` concept.
//! @include example/struct/foldable.cpp
//! Being a model of `Foldable` makes it possible to turn a `Struct`
//! into basically any `Sequence`, but also into a `hana::map` by simply
//! using the `to<...>` function!
//! @include example/struct/to.cpp
//!
//! 3. `Searchable` (free model)\n
//! A `Struct` can be searched by considering it as a map where the keys
//! are the names of the members of the `Struct`, and the values are the
//! members associated to those names. By default, a model of `Searchable`
//! is provided for any model of the `Struct` concept.
//! @include example/struct/searchable.cpp
template <typename S>
struct Struct;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONCEPT_STRUCT_HPP
@@ -0,0 +1,73 @@
/*!
@file
Forward declares `boost::hana::contains` and `boost::hana::in`.
@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)
*/
#ifndef BOOST_HANA_FWD_CONTAINS_HPP
#define BOOST_HANA_FWD_CONTAINS_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
#include <boost/hana/functional/flip.hpp>
#include <boost/hana/functional/infix.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Returns whether the key occurs in the structure.
//! @ingroup group-Searchable
//!
//! Given a `Searchable` structure `xs` and a `key`, `contains` returns
//! whether any of the keys of the structure is equal to the given `key`.
//! If the structure is not finite, an equal key has to appear at a finite
//! position in the structure for this method to finish. For convenience,
//! `contains` can also be applied in infix notation.
//!
//!
//! @param xs
//! The structure to search.
//!
//! @param key
//! A key to be searched for in the structure. The key has to be
//! `Comparable` with the other keys of the structure.
//!
//!
//! Example
//! -------
//! @include example/contains.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto contains = [](auto&& xs, auto&& key) {
return tag-dispatched;
};
#else
template <typename S, typename = void>
struct contains_impl : contains_impl<S, when<true>> { };
struct contains_t {
template <typename Xs, typename Key>
constexpr auto operator()(Xs&& xs, Key&& key) const;
};
constexpr auto contains = hana::infix(contains_t{});
#endif
//! Return whether the key occurs in the structure.
//! @ingroup group-Searchable
//!
//! Specifically, this is equivalent to `contains`, except `in` takes its
//! arguments in reverse order. Like `contains`, `in` can also be applied
//! in infix notation for increased expressiveness. This function is not a
//! method that can be overriden; it is just a convenience function
//! provided with the concept.
//!
//!
//! Example
//! -------
//! @include example/in.cpp
constexpr auto in = hana::infix(hana::flip(hana::contains));
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CONTAINS_HPP
@@ -0,0 +1,21 @@
/*!
@file
Forward declares the @ref group-core module.
@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)
*/
#ifndef BOOST_HANA_FWD_CORE_HPP
#define BOOST_HANA_FWD_CORE_HPP
#include <boost/hana/fwd/core/common.hpp>
#include <boost/hana/fwd/core/to.hpp>
#include <boost/hana/fwd/core/default.hpp>
#include <boost/hana/fwd/core/is_a.hpp>
#include <boost/hana/fwd/core/make.hpp>
#include <boost/hana/fwd/core/tag_of.hpp>
#include <boost/hana/fwd/core/when.hpp>
#endif // !BOOST_HANA_FWD_CORE_HPP
@@ -0,0 +1,103 @@
/*!
@file
Forward declares `boost::hana::common` and `boost::hana::common_t`.
@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)
*/
#ifndef BOOST_HANA_FWD_CORE_COMMON_HPP
#define BOOST_HANA_FWD_CORE_COMMON_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-core
//! %Metafunction returning the common data type between two data types.
//!
//! `common` is a natural extension of the `std::common_type` metafunction
//! to data types. Given two data types `T` and `U`, we say that they share
//! a common type `C` if both objects of data type `T` and objects of data
//! type `U` may be converted (using `to`) to an object of data type `C`,
//! and if that conversion is equality preserving. In other words, this
//! means that for any objects `t1, t2` of data type `T` and `u1, u2` of
//! data type `U`, the following law is satisfied:
//! @code
//! to<C>(t1) == to<C>(t2) if and only if t1 == t2
//! to<C>(u1) == to<C>(u2) if and only if u1 == u2
//! @endcode
//!
//! The role of `common` is to provide an alias to such a `C` if it exists.
//! In other words, if `T` and `U` have a common data type `C`,
//! `common<T, U>::%type` is an alias to `C`. Otherwise, `common<T, U>`
//! has no nested `type` and can be used in dependent contexts to exploit
//! SFINAE. By default, the exact steps followed by `common` to determine
//! the common type `C` of `T` and `U` are
//! 1. If `T` and `U` are the same, then `C` is `T`.
//! 2. Otherwise, if `true ? std::declval<T>() : std::declval<U>()` is
//! well-formed, then `C` is the type of this expression after using
//! `std::decay` on it. This is exactly the type that would have been
//! returned by `std::common_type`, except that custom specializations
//! of `std::common_type` are not taken into account.
//! 3. Otherwise, no common data type is detected and `common<T, U>` does
//! not have a nested `type` alias, unless it is specialized explicitly.
//!
//! As point 3 suggests, it is also possible (and sometimes necessary) to
//! specialize `common` in the `boost::hana` namespace for pairs of custom
//! data types when the default behavior of `common` is not sufficient.
//! Note that `when`-based specialization is supported when specializing
//! `common` in the `boost::hana` namespace.
//!
//! > #### Rationale for requiring the conversion to be equality-preserving
//! > This decision is aligned with a proposed concept design for the
//! > standard library ([N3351][1]). Also, if we did not require this,
//! > then all data types would trivially share the common data type
//! > `void`, since all objects can be converted to it.
//!
//!
//! Example
//! -------
//! @include example/core/common/common.cpp
//!
//!
//! [1]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3351.pdf
#ifdef BOOST_HANA_DOXYGEN_INVOKED
template <typename T, typename U, optional when-based enabler>
struct common { see documentation };
#else
template <typename T, typename U, typename = void>
struct common;
#endif
//! @ingroup group-core
//! %Metafunction returning whether two data types share a common data type.
//!
//! Given two data types `T` and `U`, this metafunction simply returns
//! whether `common<T, U>::%type` is well-formed.
//!
//!
//! Example
//! -------
//! @include example/core/common/has_common.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
template <typename T, typename U>
struct has_common { whether common<T, U>::type is well-formed };
#else
template <typename T, typename U, typename = void>
struct has_common;
#endif
//! @ingroup group-core
//! Alias to `common<T, U>::%type`, provided for convenience.
//!
//!
//! Example
//! -------
//! @include example/core/common/common_t.cpp
template <typename T, typename U>
using common_t = typename common<T, U>::type;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CORE_COMMON_HPP
@@ -0,0 +1,56 @@
/*!
@file
Forward declares `boost::hana::default_` and `boost::hana::is_default`.
@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)
*/
#ifndef BOOST_HANA_FWD_CORE_DEFAULT_HPP
#define BOOST_HANA_FWD_CORE_DEFAULT_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-core
//! Mark a tag-dispatched method implementation as a default implementation.
//!
//! When defining a new concept with tag-dispatched methods, it is
//! sometimes possible to provide a default implementation for some
//! method(s). Making `default_` a base class of such a default
//! implementation makes it possible to detect whether the method
//! was dispatched to the default implementation afterwards.
//!
//!
//! Example
//! -------
//! @include example/core/default.cpp
struct default_ { };
//! @ingroup group-core
//! Returns whether a tag-dispatched method implementation is a default
//! implementation.
//!
//! Given a tag-dispatched method implementation `method_impl<T...>`,
//! `is_default<method_impl<T...>>` returns whether `method_impl<T...>`
//! is a default implementation. Note that if there is no default
//! implementation for the method, then `is_default` should not be
//! used unless a static assertion saying that "the method is not
//! implemented" is acceptable.
//!
//!
//! Example
//! -------
//! @include example/core/default.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
template <typename Method>
struct is_default { see documentation };
#else
template <typename T, typename = void>
struct is_default;
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CORE_DEFAULT_HPP
@@ -0,0 +1,61 @@
/*!
@file
Forward declares `boost::hana::is_a` and `boost::hana::is_an`.
@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)
*/
#ifndef BOOST_HANA_FWD_CORE_IS_A_HPP
#define BOOST_HANA_FWD_CORE_IS_A_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-core
//! Returns whether the tag of an object matches a given tag.
//!
//! Given a tag `Tag` and a C++ type `T`, `is_a<Tag, T>` is a compile-time
//! Logical representing whether the tag of `T` is exactly `Tag`. In other
//! words, it is equivalent to
//! @code
//! std::is_same<Tag, tag_of<T>::type>
//! @endcode
//!
//! For convenience, an alternate syntax is provided for using `is_a`.
//! Specifically, `is_a<Tag>` is a function object returning whether the
//! argument it is passed has the given tag. In other words,
//! @code
//! is_a<Tag>(x) == is_a<Tag, decltype(x)>
//! @endcode
//!
//!
//! Example
//! -------
//! @include example/core/is_a.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
template <typename Tag, typename optional_T>
constexpr auto is_a = see-documentation;
#else
template <typename Tag, typename ...T>
struct is_a_t;
template <typename Tag, typename ...T>
constexpr is_a_t<Tag, T...> is_a{};
#endif
//! @ingroup group-core
//! Equivalent to `is_a`; provided for consistency with the rules of the
//! English language.
#ifdef BOOST_HANA_DOXYGEN_INVOKED
template <typename Tag, typename ...T>
constexpr auto is_an = is_a<Tag, T...>;
#else
template <typename Tag, typename ...T>
constexpr is_a_t<Tag, T...> is_an{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CORE_IS_A_HPP
@@ -0,0 +1,70 @@
/*!
@file
Forward declares `boost::hana::make`.
@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)
*/
#ifndef BOOST_HANA_FWD_CORE_MAKE_HPP
#define BOOST_HANA_FWD_CORE_MAKE_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-core
//! Create an object of the given tag with the given arguments.
//!
//! This function serves the same purpose as constructors in usual C++.
//! However, instead of creating an object of a specific C++ type, it
//! creates an object of a specific tag, regardless of the C++ type
//! of that object.
//!
//! This function is actually a variable template, so `make<T>` can be
//! passed around as a function object creating an object of tag `T`.
//! Also, it uses tag-dispatching so this is how it should be customized
//! for user-defined tags.
//!
//! Finally, the default implementation of `make` is equivalent to calling
//! the constructor of the given tag with the corresponding arguments.
//! In other words, by default,
//! @code
//! make<T>(args...) == T(args...)
//! @endcode
//!
//! Note that the arguments are perfectly forwarded and the form of
//! construction which is used is exactly as documented, i.e. `T(args...)`.
//! However, if `T(args...)` is not a valid expression, a compilation
//! error is triggered. This default behavior is useful because it makes
//! foreign C++ types that have no notion of tag constructible with `make`
//! out-of-the-box, since their tag is exactly themselves.
//!
//!
//! Example
//! -------
//! @include example/core/make.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
template <typename Tag>
constexpr auto make = [](auto&& ...x) -> decltype(auto) {
return tag-dispatched;
};
#else
template <typename Tag, typename = void>
struct make_impl;
template <typename Tag>
struct make_t {
template <typename ...X>
constexpr decltype(auto) operator()(X&& ...x) const {
return make_impl<Tag>::apply(static_cast<X&&>(x)...);
}
};
template <typename Tag>
constexpr make_t<Tag> make{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CORE_MAKE_HPP
@@ -0,0 +1,120 @@
/*!
@file
Forward declares `boost::hana::tag_of` and `boost::hana::tag_of_t`.
@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)
*/
#ifndef BOOST_HANA_FWD_CORE_TAG_OF_HPP
#define BOOST_HANA_FWD_CORE_TAG_OF_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-core
//! %Metafunction returning the tag associated to `T`.
//!
//! There are several ways to specify the tag of a C++ type. If it's a
//! user-defined type, one can define a nested `hana_tag` alias:
//! @code
//! struct MyUserDefinedType {
//! using hana_tag = MyTag;
//! };
//! @endcode
//!
//! Sometimes, however, the C++ type can't be modified (if it's in a
//! foreign library) or simply can't have nested types (if it's not a
//! struct or class). In those cases, using a nested alias is impossible
//! and so ad-hoc customization is also supported by specializing
//! `tag_of` in the `boost::hana` namespace:
//! @code
//! struct i_cant_modify_this;
//!
//! namespace boost { namespace hana {
//! template <>
//! struct tag_of<i_cant_modify_this> {
//! using type = MyTag;
//! };
//! }}
//! @endcode
//!
//! `tag_of` can also be specialized for all C++ types satisfying some
//! boolean condition using `when`. `when` accepts a single compile-time
//! boolean and enables the specialization of `tag_of` if and only if
//! that boolean is `true`. This is similar to the well known C++ idiom
//! of using a dummy template parameter with `std::enable_if` and relying
//! on SFINAE. For example, we could specify the tag of all
//! `fusion::vector`s by doing:
//! @code
//! struct BoostFusionVector;
//!
//! namespace boost { namespace hana {
//! template <typename T>
//! struct tag_of<T, when<
//! std::is_same<
//! typename fusion::traits::tag_of<T>::type,
//! fusion::traits::tag_of<fusion::vector<>>::type
//! >{}
//! >> {
//! using type = BoostFusionVector;
//! };
//! }}
//! @endcode
//!
//! Also, when it is not specialized and when the given C++ type does not
//! have a nested `hana_tag` alias, `tag_of<T>` returns `T` itself. This
//! makes tags a simple extension of normal C++ types. This is _super_
//! useful, mainly for two reasons. First, this allows Hana to adopt a
//! reasonable default behavior for some operations involving types that
//! have no notion of tags. For example, Hana allows comparing with `equal`
//! any two objects for which a valid `operator==` is defined, and that
//! without any work on the user side. Second, it also means that you can
//! ignore tags completely if you don't need their functionality; just use
//! the normal C++ type of your objects and everything will "just work".
//!
//! Finally, also note that `tag_of<T>` is always equivalent to `tag_of<U>`,
//! where `U` is the type `T` after being stripped of all references and
//! cv-qualifiers. This makes it unnecessary to specialize `tag_of` for
//! all reference and cv combinations, which would be a real pain. Also,
//! `tag_of` is required to be idempotent. In other words, it must always
//! be the case that `tag_of<tag_of<T>::%type>::%type` is equivalent to
//! `tag_of<T>::%type`.
//!
//! > __Tip 1__\n
//! > If compile-time performance is a serious concern, consider
//! > specializing the `tag_of` metafunction in Hana's namespace.
//! > When unspecialized, the metafunction has to use SFINAE, which
//! > tends to incur a larger compile-time overhead. For heavily used
//! > templated types, this can potentially make a difference.
//!
//! > __Tip 2__\n
//! > Consider using `tag_of_t` alias instead of `tag_of`, which
//! > reduces the amount of typing in dependent contexts.
//!
//!
//! Example
//! -------
//! @include example/core/tag_of.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
template <typename T, optional when-based enabler>
struct tag_of { unspecified };
#else
template <typename T, typename = void>
struct tag_of;
#endif
//! @ingroup group-core
//! Alias to `tag_of<T>::%type`, provided for convenience.
//!
//!
//! Example
//! -------
//! @include example/core/tag_of_t.cpp
template <typename T>
using tag_of_t = typename hana::tag_of<T>::type;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CORE_TAG_OF_HPP
@@ -0,0 +1,174 @@
/*!
@file
Forward declares `boost::hana::to` and related utilities.
@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)
*/
#ifndef BOOST_HANA_FWD_CORE_TO_HPP
#define BOOST_HANA_FWD_CORE_TO_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-core
//! Converts an object from one data type to another.
//!
//! `to` is a natural extension of the `static_cast` language construct to
//! data types. Given a destination data type `To` and an object `x`, `to`
//! creates a new object of data type `To` from `x`. Note, however, that
//! `to` is not required to actually create a new object, and may return a
//! reference to the original object (for example when trying to convert
//! an object to its own data type).
//!
//! As a natural extension to `static_cast`, `to` provides a default
//! behavior. For the purpose of what follows, let `To` be the destination
//! data type and `From` be the data type of `x`, i.e. the source data type.
//! Then, `to` has the following default behavior:
//! 1. If the `To` and `From` data types are the same, then the object
//! is forwarded as-is.
//! 2. Otherwise, if `From` is convertible to `To` using `static_cast`,
//! `x` is converted to `From` using `static_cast`.
//! 3. Otherwise, calling `to<From>(x)` triggers a static assertion.
//!
//! However, `to` is a tag-dispatched function, which means that `to_impl`
//! may be specialized in the `boost::hana` namespace to customize its
//! behavior for arbitrary data types. Also note that `to` is tag-dispatched
//! using both the `To` and the `From` data types, which means that `to_impl`
//! is called as `to_impl<To, From>::%apply(x)`. Also note that some
//! concepts provide conversions to or from their models. For example,
//! any `Foldable` may be converted into a `Sequence`. This is achieved
//! by specializing `to_impl<To, From>` whenever `To` is a `Sequence` and
//! `From` is a `Foldable`. When such conversions are provided, they are
//! documented in the source concept, in this case `Foldable`.
//!
//!
//! Hana-convertibility
//! -------------------
//! When an object `x` of data type `From` can be converted to a data type
//! `To` using `to`, we say that `x` is Hana-convertible to the data type
//! `To`. We also say that there is a Hana-conversion from `From` to `To`.
//! This bit of terminology is useful to avoid mistaking the various kinds
//! of conversions C++ offers.
//!
//!
//! Embeddings
//! ----------
//! As you might have seen by now, Hana uses algebraic and category-
//! theoretical structures all around the place to help specify concepts
//! in a rigorous way. These structures always have operations associated
//! to them, which is why they are useful. The notion of embedding captures
//! the idea of injecting a smaller structure into a larger one while
//! preserving the operations of the structure. In other words, an
//! embedding is an injective mapping that is also structure-preserving.
//! Exactly what it means for a structure's operations to be preserved is
//! left to explain by the documentation of each structure. For example,
//! when we talk of a Monoid-embedding from a Monoid `A` to a Monoid `B`,
//! we simply mean an injective transformation that preserves the identity
//! and the associative operation, as documented in `Monoid`.
//!
//! But what does this have to do with the `to` function? Quite simply,
//! the `to` function is a mapping between two data types, which will
//! sometimes be some kind of structure, and it is sometimes useful to
//! know whether such a mapping is well-behaved, i.e. lossless and
//! structure preserving. The criterion for this conversion to be well-
//! behaved is exactly that of being an embedding. To specify that a
//! conversion is an embedding, simply use the `embedding` type as a
//! base class of the corresponding `to_impl` specialization. Obviously,
//! you should make sure the conversion is really an embedding, unless
//! you want to shoot yourself in the foot.
//!
//!
//! @tparam To
//! The data type to which `x` should be converted.
//!
//! @param x
//! The object to convert to the given data type.
//!
//!
//! Example
//! -------
//! @include example/core/convert/to.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
template <typename To>
constexpr auto to = [](auto&& x) -> decltype(auto) {
return tag-dispatched;
};
#else
template <typename To, typename From, typename = void>
struct to_impl;
template <typename To>
struct to_t {
template <typename X>
constexpr decltype(auto) operator()(X&& x) const;
};
template <typename To>
constexpr to_t<To> to{};
#endif
//! @ingroup group-core
//! Returns whether there is a Hana-conversion from a data type to another.
//!
//! Specifically, `is_convertible<From, To>` is whether calling `to<To>`
//! with an object of data type `From` would _not_ trigger a static
//! assertion.
//!
//!
//! Example
//! -------
//! @include example/core/convert/is_convertible.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
template <typename From, typename To>
struct is_convertible { see documentation };
#else
template <typename From, typename To, typename = void>
struct is_convertible;
#endif
//! @ingroup group-core
//! Marks a conversion between data types as being an embedding.
//!
//! To mark a conversion between two data types `To` and `From` as
//! an embedding, simply use `embedding<true>` (or simply `embedding<>`)
//! as a base class of the corresponding `to_impl` specialization.
//! If a `to_impl` specialization does not inherit `embedding<true>`
//! or `embedding<>`, then it is not considered an embedding by the
//! `is_embedded` metafunction.
//!
//! > #### Tip
//! > The boolean template parameter is useful for marking a conversion
//! > as an embedding only when some condition is satisfied.
//!
//!
//! Example
//! -------
//! @include example/core/convert/embedding.cpp
template <bool = true>
struct embedding { };
//! @ingroup group-core
//! Returns whether a data type can be embedded into another data type.
//!
//! Given two data types `To` and `From`, `is_embedded<From, To>` returns
//! whether `From` is convertible to `To`, and whether that conversion is
//! also an embedding, as signaled by the `embedding` type.
//!
//!
//! Example
//! -------
//! @include example/core/convert/is_embedded.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
template <typename From, typename To>
struct is_embedded { see documentation };
#else
template <typename From, typename To, typename = void>
struct is_embedded;
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CORE_TO_HPP
@@ -0,0 +1,74 @@
/*!
@file
Forward declares `boost::hana::when` and `boost::hana::when_valid`.
@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)
*/
#ifndef BOOST_HANA_FWD_CORE_WHEN_HPP
#define BOOST_HANA_FWD_CORE_WHEN_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-core
//! Enable a partial specialization only if a boolean condition is true.
//!
//! You might also want to take a look at `when_valid`, which provides
//! similar functionality but enables a specialziation only when some
//! expression is well-formed.
//!
//! > #### Rationale for using `when` instead of `std::enable_if`
//! > `when` is used to control the priority of partial specializations
//! > in a finer grained manner than what can be achieved with the usual
//! > `typename Enable = void` and `std::enable_if` pattern. For example,
//! > a partially specialized tag-dispatched method will have a higher
//! > priority than an equivalent specialization that uses `when`. For
//! > more details, see the tutorial section on [tag-dispatching][1].
//!
//!
//! Example
//! -------
//! @include example/core/when.cpp
//!
//! [1]: @ref tutorial-core-tag_dispatching
template <bool condition>
struct when;
namespace core_detail {
template <typename ...>
struct always_true { static constexpr bool value = true; };
}
//! @ingroup group-core
//! Variant of `when` allowing specializations to be enabled only if an
//! expression is well-formed.
//!
//! `when_valid<...>` is always equivalent to `when<true>`. However, when
//! used inside a partial specialization, SFINAE will cause the partial
//! specialization to be ignored when the expression is ill-formed.
//!
//!
//! Example
//! -------
//! @include example/core/when_valid.cpp
//!
//!
//! @bug
//! Using `when_valid` seems to trigger ambiguous partial specializations
//! on GCC.
#ifdef BOOST_HANA_DOXYGEN_INVOKED
template <typename ...>
using when_valid = when<true>;
#else
template <typename ...Dummy>
using when_valid = when<
core_detail::always_true<Dummy...>::value
>;
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CORE_WHEN_HPP
@@ -0,0 +1,57 @@
/*!
@file
Forward declares `boost::hana::count`.
@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)
*/
#ifndef BOOST_HANA_FWD_COUNT_HPP
#define BOOST_HANA_FWD_COUNT_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Return the number of elements in the structure that compare equal to
//! a given value.
//! @ingroup group-Foldable
//!
//! Given a Foldable structure `xs` and a value `value`, `count` returns
//! an unsigned integral, or a Constant thereof, representing the number
//! of elements of `xs` that compare equal to `value`. For this method to
//! be well-defined, all the elements of the structure must be Comparable
//! with the given value.
//!
//!
//! @param xs
//! The structure whose elements are counted.
//!
//! @param value
//! A value compared with each element in the structure. Elements
//! that compare equal to this value are counted, others are not.
//!
//!
//! Example
//! -------
//! @include example/count.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto count = [](auto&& xs, auto&& value) {
return tag-dispatched;
};
#else
template <typename T, typename = void>
struct count_impl : count_impl<T, when<true>> { };
struct count_t {
template <typename Xs, typename Value>
constexpr auto operator()(Xs&& xs, Value&& value) const;
};
constexpr count_t count{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_COUNT_HPP
@@ -0,0 +1,56 @@
/*!
@file
Forward declares `boost::hana::count_if`.
@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)
*/
#ifndef BOOST_HANA_FWD_COUNT_IF_HPP
#define BOOST_HANA_FWD_COUNT_IF_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Return the number of elements in the structure for which the
//! `predicate` is satisfied.
//! @ingroup group-Foldable
//!
//! Specifically, returns an object of an unsigned integral type, or
//! a `Constant` holding such an object, which represents the number
//! of elements in the structure satisfying the given `predicate`.
//!
//!
//! @param xs
//! The structure whose elements are counted.
//!
//! @param predicate
//! A function called as `predicate(x)`, where `x` is an element of the
//! structure, and returning a `Logical` representing whether `x` should
//! be counted.
//!
//!
//! Example
//! -------
//! @include example/count_if.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto count_if = [](auto&& xs, auto&& predicate) {
return tag-dispatched;
};
#else
template <typename T, typename = void>
struct count_if_impl : count_if_impl<T, when<true>> { };
struct count_if_t {
template <typename Xs, typename Pred>
constexpr auto operator()(Xs&& xs, Pred&& pred) const;
};
constexpr count_if_t count_if{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_COUNT_IF_HPP
@@ -0,0 +1,76 @@
/*!
@file
Forward declares `boost::hana::cycle`.
@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)
*/
#ifndef BOOST_HANA_FWD_CYCLE_HPP
#define BOOST_HANA_FWD_CYCLE_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Combine a monadic structure with itself `n` times.
//! @ingroup group-MonadPlus
//!
//! Given a monadic structure `xs` and a non-negative number `n`,
//! `cycle` returns a new monadic structure which is the result of
//! combining `xs` with itself `n` times using the `concat` operation.
//! In other words,
//! @code
//! cycle(xs, n) == concat(xs, concat(xs, ... concat(xs, xs)))
//! // ^^^^^ n times total
//! @endcode
//!
//! Also note that since `concat` is required to be associative, we
//! could also have written
//! @code
//! cycle(xs, n) == concat(concat(... concat(xs, xs), xs), xs)
//! // ^^^^^ n times total
//! @endcode
//!
//! If `n` is zero, then the identity of `concat`, `empty`, is returned.
//! In the case of sequences, this boils down to returning a sequence
//! containing `n` copies of itself; for other models it might differ.
//!
//!
//! Signature
//! ---------
//! Given an `IntegralConstant` `C` and a `MonadPlus` `M`, the signature is
//! @f$ \mathrm{cycle} : M(T) \times C \to M(T) @f$.
//!
//! @param xs
//! A monadic structure to combine with itself a certain number of times.
//!
//! @param n
//! A non-negative `IntegralConstant` representing the number of times to
//! combine the monadic structure with itself. If `n` is zero, `cycle`
//! returns `empty`.
//!
//!
//! Example
//! -------
//! @include example/cycle.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto cycle = [](auto&& xs, auto const& n) {
return tag-dispatched;
};
#else
template <typename M, typename = void>
struct cycle_impl : cycle_impl<M, when<true>> { };
struct cycle_t {
template <typename Xs, typename N>
constexpr auto operator()(Xs&& xs, N const& n) const;
};
constexpr cycle_t cycle{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_CYCLE_HPP
@@ -0,0 +1,48 @@
/*!
@file
Documents the `BOOST_HANA_DEFINE_STRUCT` macro.
@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)
*/
#ifndef BOOST_HANA_FWD_DEFINE_STRUCT_HPP
#define BOOST_HANA_FWD_DEFINE_STRUCT_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
// Note:
// The weird definition as a variable seems to exploit a glitch in Doxygen
// which makes the macro appear in the related objects of Struct (as we
// want it to).
//! Defines members of a structure, while at the same time
//! modeling `Struct`.
//! @ingroup group-Struct
//!
//! Using this macro in the body of a user-defined type will define the
//! given members inside that type, and will also provide a model of the
//! `Struct` concept for that user-defined type. This macro is often the
//! easiest way to define a model of the `Struct` concept.
//!
//! @note
//! This macro only works if the tag of the user-defined type `T` is `T`
//! itself. This is the case unless you specifically asked for something
//! different; see `tag_of`'s documentation.
//!
//!
//! Example
//! -------
//! @include example/define_struct.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
auto BOOST_HANA_DEFINE_STRUCT(...) = ;
#define BOOST_HANA_DEFINE_STRUCT(Name, ...) see documentation
#else
// defined in <boost/hana/define_struct.hpp>
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_DEFINE_STRUCT_HPP
@@ -0,0 +1,64 @@
/*!
@file
Forward declares `boost::hana::difference`.
@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)
*/
#ifndef BOOST_HANA_FWD_DIFFERENCE_HPP
#define BOOST_HANA_FWD_DIFFERENCE_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Returns the set-theoretic difference of two sets.
//! @relates hana::set
//!
//! Given two sets `xs` and `ys`, `difference(xs, ys)` is a new set
//! containing all the elements of `xs` that are _not_ contained in `ys`.
//! For any object `x`, the following holds:
//! @code
//! x ^in^ difference(xs, ys) if and only if x ^in^ xs && !(x ^in^ ys)
//! @endcode
//!
//!
//! @note
//! This operation is not commutative, i.e. `difference(xs, ys)` is not
//! necessarily the same as `difference(ys, xs)`. Indeed, consider the
//! case where `xs` is empty and `ys` isn't. Then, `difference(xs, ys)`
//! is empty but `difference(ys, xs)` is equal to `ys`. For the symmetric
//! version of this operation, see `symmetric_difference`.
//!
//!
//! @param xs
//! A set to remove values from.
//!
//! @param ys
//! The set whose values are removed from `xs`.
//!
//!
//! Example
//! -------
//! @include example/difference.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto difference = [](auto&& xs, auto&& ys) {
return tag-dispatched;
};
#else
template <typename S, typename = void>
struct difference_impl : difference_impl<S, when<true>> { };
struct difference_t {
template <typename Xs, typename Ys>
constexpr auto operator()(Xs&& xs, Ys&& ys) const;
};
constexpr difference_t difference{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_DIFFERENCE_HPP
@@ -0,0 +1,59 @@
/*!
@file
Forward declares `boost::hana::div`.
@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)
*/
#ifndef BOOST_HANA_FWD_DIV_HPP
#define BOOST_HANA_FWD_DIV_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Generalized integer division.
//! @ingroup group-EuclideanRing
//!
//!
//! Cross-type version of the method
//! --------------------------------
//! The `div` method is "overloaded" to handle distinct data types
//! with certain properties. Specifically, `div` is defined for
//! _distinct_ data types `A` and `B` such that
//! 1. `A` and `B` share a common data type `C`, as determined by the
//! `common` metafunction
//! 2. `A`, `B` and `C` are all `EuclideanRing`s when taken individually
//! 3. `to<C> : A -> B` and `to<C> : B -> C` are `Ring`-embeddings, as
//! determined by the `is_embedding` metafunction.
//!
//! In that case, the `div` method is defined as
//! @code
//! div(x, y) = div(to<C>(x), to<C>(y))
//! @endcode
//!
//!
//! Example
//! -------
//! @include example/div.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto div = [](auto&& x, auto&& y) -> decltype(auto) {
return tag-dispatched;
};
#else
template <typename T, typename U, typename = void>
struct div_impl : div_impl<T, U, when<true>> { };
struct div_t {
template <typename X, typename Y>
constexpr decltype(auto) operator()(X&& x, Y&& y) const;
};
constexpr div_t div{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_DIV_HPP
@@ -0,0 +1,63 @@
/*!
@file
Forward declares `boost::hana::drop_back`.
@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)
*/
#ifndef BOOST_HANA_FWD_DROP_BACK_HPP
#define BOOST_HANA_FWD_DROP_BACK_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Drop the last `n` elements of a finite sequence, and return the rest.
//! @ingroup group-Sequence
//!
//! Given a finite `Sequence` `xs` with a linearization of `[x1, ..., xm]`
//! and a non-negative `IntegralConstant` `n`, `drop_back(xs, n)` is a
//! sequence with the same tag as `xs` whose linearization is
//! `[x1, ..., xm-n]`. If `n` is not given, it defaults to an
//! `IntegralConstant` with a value equal to `1`.
//!
//! In case `length(xs) <= n`, `drop_back` will simply drop the whole
//! sequence without failing, thus returning an empty sequence.
//!
//!
//! @param xs
//! The sequence from which elements are dropped.
//!
//! @param n
//! A non-negative `IntegralConstant` representing the number of elements
//! to be dropped from the end of the sequence. If `n` is not given, it
//! defaults to an `IntegralConstant` with a value equal to `1`.
//!
//!
//! Example
//! -------
//! @include example/drop_back.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto drop_back = [](auto&& xs[, auto const& n]) {
return tag-dispatched;
};
#else
template <typename S, typename = void>
struct drop_back_impl : drop_back_impl<S, when<true>> { };
struct drop_back_t {
template <typename Xs, typename N>
constexpr auto operator()(Xs&& xs, N const& n) const;
template <typename Xs>
constexpr auto operator()(Xs&& xs) const;
};
constexpr drop_back_t drop_back{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_DROP_BACK_HPP
@@ -0,0 +1,66 @@
/*!
@file
Forward declares `boost::hana::drop_front`.
@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)
*/
#ifndef BOOST_HANA_FWD_DROP_FRONT_HPP
#define BOOST_HANA_FWD_DROP_FRONT_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Drop the first `n` elements of an iterable, and return the rest.
//! @ingroup group-Iterable
//!
//! Given an `Iterable` `xs` with a linearization of `[x1, x2, ...]` and
//! a non-negative `IntegralConstant` `n`, `drop_front(xs, n)` is an
//! iterable with the same tag as `xs` whose linearization is
//! `[xn+1, xn+2, ...]`. In particular, note that this function does not
//! mutate the original iterable in any way. If `n` is not given, it
//! defaults to an `IntegralConstant` with a value equal to `1`.
//!
//! In case `length(xs) <= n`, `drop_front` will simply drop the whole
//! iterable without failing, thus returning an empty iterable. This is
//! different from `drop_front_exactly`, which expects `n <= length(xs)`
//! but can be better optimized because of this additional guarantee.
//!
//!
//! @param xs
//! The iterable from which elements are dropped.
//!
//! @param n
//! A non-negative `IntegralConstant` representing the number of elements
//! to be dropped from the iterable. If `n` is not given, it defaults to
//! an `IntegralConstant` with a value equal to `1`.
//!
//!
//! Example
//! -------
//! @include example/drop_front.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto drop_front = [](auto&& xs[, auto const& n]) {
return tag-dispatched;
};
#else
template <typename It, typename = void>
struct drop_front_impl : drop_front_impl<It, when<true>> { };
struct drop_front_t {
template <typename Xs, typename N>
constexpr auto operator()(Xs&& xs, N const& n) const;
template <typename Xs>
constexpr auto operator()(Xs&& xs) const;
};
constexpr drop_front_t drop_front{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_DROP_FRONT_HPP
@@ -0,0 +1,67 @@
/*!
@file
Forward declares `boost::hana::drop_front_exactly`.
@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)
*/
#ifndef BOOST_HANA_FWD_DROP_FRONT_EXACTLY_HPP
#define BOOST_HANA_FWD_DROP_FRONT_EXACTLY_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Drop the first `n` elements of an iterable, and return the rest.
//! @ingroup group-Iterable
//!
//! Given an `Iterable` `xs` with a linearization of `[x1, x2, ...]` and
//! a non-negative `IntegralConstant` `n`, `drop_front_exactly(xs, n)` is
//! an iterable with the same tag as `xs` whose linearization is
//! `[xn+1, xn+2, ...]`. In particular, note that this function does not
//! mutate the original iterable in any way. If `n` is not given, it
//! defaults to an `IntegralConstant` with a value equal to `1`.
//!
//! It is an error to use `drop_front_exactly` with `n > length(xs)`. This
//! additional guarantee allows `drop_front_exactly` to be better optimized
//! than the `drop_front` function, which allows `n > length(xs)`.
//!
//!
//! @param xs
//! The iterable from which elements are dropped.
//!
//! @param n
//! A non-negative `IntegralConstant` representing the number of elements
//! to be dropped from the iterable. In addition to being non-negative,
//! `n` must be less than or equal to the number of elements in `xs`.
//! If `n` is not given, it defaults to an `IntegralConstant` with a value
//! equal to `1`.
//!
//!
//! Example
//! -------
//! @include example/drop_front_exactly.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto drop_front_exactly = [](auto&& xs[, auto const& n]) {
return tag-dispatched;
};
#else
template <typename It, typename = void>
struct drop_front_exactly_impl : drop_front_exactly_impl<It, when<true>> { };
struct drop_front_exactly_t {
template <typename Xs, typename N>
constexpr auto operator()(Xs&& xs, N const& n) const;
template <typename Xs>
constexpr auto operator()(Xs&& xs) const;
};
constexpr drop_front_exactly_t drop_front_exactly{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_DROP_FRONT_EXACTLY_HPP
@@ -0,0 +1,60 @@
/*!
@file
Forward declares `boost::hana::drop_while`.
@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)
*/
#ifndef BOOST_HANA_FWD_DROP_WHILE_HPP
#define BOOST_HANA_FWD_DROP_WHILE_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Drop elements from an iterable up to, but excluding, the first
//! element for which the `predicate` is not satisfied.
//! @ingroup group-Iterable
//!
//! Specifically, `drop_while` returns an iterable containing all the
//! elements of the original iterable except for those in the range
//! delimited by [`head`, `e`), where `head` is the first element and
//! `e` is the first element for which the `predicate` is not satisfied.
//! If the iterable is not finite, the `predicate` has to return a false-
//! valued `Logical` at a finite index for this method to return.
//!
//!
//! @param iterable
//! The iterable from which elements are dropped.
//!
//! @param predicate
//! A function called as `predicate(x)`, where `x` is an element of the
//! structure, and returning a `Logical` representing whether `x` should
//! be dropped from the structure. In the current version of the library,
//! `predicate` should return a compile-time `Logical`.
//!
//!
//! Example
//! -------
//! @include example/drop_while.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto drop_while = [](auto&& iterable, auto&& predicate) {
return tag-dispatched;
};
#else
template <typename It, typename = void>
struct drop_while_impl : drop_while_impl<It, when<true>> { };
struct drop_while_t {
template <typename Xs, typename Pred>
constexpr auto operator()(Xs&& xs, Pred&& pred) const;
};
constexpr drop_while_t drop_while{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWDDROP_WHILE_HPP
@@ -0,0 +1,57 @@
/*!
@file
Forward declares `boost::hana::duplicate`.
@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)
*/
#ifndef BOOST_HANA_FWD_DUPLICATE_HPP
#define BOOST_HANA_FWD_DUPLICATE_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Add an extra layer of comonadic context to a comonadic value.
//! @ingroup group-Comonad
//!
//! Given a value already in a comonadic context, `duplicate` wraps this
//! value with an additional layer of comonadic context. This can be seen
//! as the dual operation to `flatten` from the Monad concept.
//!
//!
//! Signature
//! ---------
//! Given a Comonad `W`, the signature is
//! \f$
//! \mathtt{duplicate} : W(T) \to W(W(T))
//! \f$
//!
//! @param w
//! The value to wrap in an additional level of comonadic context.
//!
//!
//! Example
//! -------
//! @include example/duplicate.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto duplicate = [](auto&& w) -> decltype(auto) {
return tag-dispatched;
};
#else
template <typename W, typename = void>
struct duplicate_impl : duplicate_impl<W, when<true>> { };
struct duplicate_t {
template <typename W_>
constexpr decltype(auto) operator()(W_&& w) const;
};
constexpr duplicate_t duplicate{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_DUPLICATE_HPP
@@ -0,0 +1,51 @@
/*!
@file
Forward declares `boost::hana::empty`.
@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)
*/
#ifndef BOOST_HANA_FWD_EMPTY_HPP
#define BOOST_HANA_FWD_EMPTY_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Identity of the monadic combination `concat`.
//! @ingroup group-MonadPlus
//!
//! Signature
//! ---------
//! Given a MonadPlus `M`, the signature is
//! @f$ \mathtt{empty}_M : \emptyset \to M(T) @f$.
//!
//! @tparam M
//! The tag of the monadic structure to return. This must be
//! a model of the MonadPlus concept.
//!
//!
//! Example
//! -------
//! @include example/empty.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
template <typename M>
constexpr auto empty = []() {
return tag-dispatched;
};
#else
template <typename M, typename = void>
struct empty_impl : empty_impl<M, when<true>> { };
template <typename M>
struct empty_t;
template <typename M>
constexpr empty_t<M> empty{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_EMPTY_HPP
@@ -0,0 +1,80 @@
/*!
@file
Forward declares `boost::hana::equal`.
@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)
*/
#ifndef BOOST_HANA_FWD_EQUAL_HPP
#define BOOST_HANA_FWD_EQUAL_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
#include <boost/hana/detail/nested_to_fwd.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Returns a `Logical` representing whether `x` is equal to `y`.
//! @ingroup group-Comparable
//!
//! The `equal` function can be called in two different ways. First, it
//! can be called like a normal function:
//! @code
//! equal(x, y)
//! @endcode
//!
//! However, it may also be partially applied to an argument by using
//! `equal.to`:
//! @code
//! equal.to(x)(y) == equal(x, y)
//! @endcode
//!
//! In other words, `equal.to(x)` is a function object that is equivalent
//! to `partial(equal, x)`. This is provided to enhance the readability of
//! some constructs, especially when using higher order algorithms.
//!
//!
//! Signature
//! ---------
//! Given a Logical `Bool` and two Comparables `A` and `B` that
//! share a common embedding, the signature is
//! @f$ \mathtt{equal} : A \times B \to Bool @f$.
//!
//! @param x, y
//! Two objects to compare for equality.
//!
//!
//! Example
//! -------
//! @include example/equal.cpp
//!
//!
//! > #### Rationale for the arity of `equal`
//! > It is a valid question whether `equal` should accept more than 2
//! > arguments and have semantics matching those of Python's `==`. This
//! > is not supported right now for the following reasons:
//! > - It was implemented in the MPL11, but it was not shown to be useful
//! > so far.
//! > - It does not make sense for `not_equal` to have an arity of more
//! > than 2, only `equal` could maybe have those semantics, which would
//! > break symmetry.
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto equal = [](auto&& x, auto&& y) {
return tag-dispatched;
};
#else
template <typename T, typename U, typename = void>
struct equal_impl : equal_impl<T, U, when<true>> { };
struct equal_t : detail::nested_to<equal_t> {
template <typename X, typename Y>
constexpr auto operator()(X&& x, Y&& y) const;
};
constexpr equal_t equal{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_EQUAL_HPP
@@ -0,0 +1,32 @@
/*!
@file
Forward declares `boost::hana::erase_key`.
@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)
*/
#ifndef BOOST_HANA_FWD_ERASE_KEY_HPP
#define BOOST_HANA_FWD_ERASE_KEY_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
// Note: This function is documented per datatype/concept only.
//! @cond
template <typename T, typename = void>
struct erase_key_impl : erase_key_impl<T, when<true>> { };
//! @endcond
struct erase_key_t {
template <typename Set, typename ...Args>
constexpr decltype(auto) operator()(Set&& set, Args&& ...args) const;
};
constexpr erase_key_t erase_key{};
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_ERASE_KEY_HPP
@@ -0,0 +1,58 @@
/*!
@file
Forward declares `boost::hana::eval`.
@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)
*/
#ifndef BOOST_HANA_FWD_EVAL_HPP
#define BOOST_HANA_FWD_EVAL_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Evaluate a lazy value and return it.
//! @relates hana::lazy
//!
//! Given a lazy expression `expr`, `eval` evaluates `expr` and returns
//! the result as a normal value. However, for convenience, `eval` can
//! also be used with nullary and unary function objects. Specifically,
//! if `expr` is not a `hana::lazy`, it is called with no arguments at
//! all and the result of that call (`expr()`) is returned. Otherwise,
//! if `expr()` is ill-formed, then `expr(hana::id)` is returned instead.
//! If that expression is ill-formed, then a compile-time error is
//! triggered.
//!
//! The reason for allowing nullary callables in `eval` is because this
//! allows using nullary lambdas as lazy branches to `eval_if`, which
//! is convenient. The reason for allowing unary callables and calling
//! them with `hana::id` is because this allows deferring the
//! compile-time evaluation of selected expressions inside the callable.
//! How this can be achieved is documented by `hana::eval_if`.
//!
//!
//! Example
//! -------
//! @include example/eval.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto eval = [](auto&& see_documentation) -> decltype(auto) {
return tag-dispatched;
};
#else
template <typename T, typename = void>
struct eval_impl : eval_impl<T, when<true>> { };
struct eval_t {
template <typename Expr>
constexpr decltype(auto) operator()(Expr&& expr) const;
};
constexpr eval_t eval{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_EVAL_HPP
@@ -0,0 +1,155 @@
/*!
@file
Forward declares `boost::hana::eval_if`.
@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)
*/
#ifndef BOOST_HANA_FWD_EVAL_IF_HPP
#define BOOST_HANA_FWD_EVAL_IF_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Conditionally execute one of two branches based on a condition.
//! @ingroup group-Logical
//!
//! Given a condition and two branches in the form of lambdas or
//! `hana::lazy`s, `eval_if` will evaluate the branch selected by the
//! condition with `eval` and return the result. The exact requirements
//! for what the branches may be are the same requirements as those for
//! the `eval` function.
//!
//!
//! Deferring compile-time evaluation inside `eval_if`
//! --------------------------------------------------
//! By passing a unary callable to `eval_if`, it is possible to defer
//! the compile-time evaluation of selected expressions inside the
//! lambda. This is useful when instantiating a branch would trigger
//! a compile-time error; we only want the branch to be instantiated
//! when that branch is selected. Here's how it can be achieved.
//!
//! For simplicity, we'll use a unary lambda as our unary callable.
//! Our lambda must accept a parameter (usually called `_`), which
//! can be used to defer the compile-time evaluation of expressions
//! as required. For example,
//! @code
//! template <typename N>
//! auto fact(N n) {
//! return hana::eval_if(n == hana::int_c<0>,
//! [] { return hana::int_c<1>; },
//! [=](auto _) { return n * fact(_(n) - hana::int_c<1>); }
//! );
//! }
//! @endcode
//!
//! What happens here is that `eval_if` will call `eval` on the selected
//! branch. In turn, `eval` will call the selected branch either with
//! nothing -- for the _then_ branch -- or with `hana::id` -- for the
//! _else_ branch. Hence, `_(x)` is always the same as `x`, but the
//! compiler can't tell until the lambda has been called! Hence, the
//! compiler has to wait before it instantiates the body of the lambda
//! and no infinite recursion happens. However, this trick to delay the
//! instantiation of the lambda's body can only be used when the condition
//! is known at compile-time, because otherwise both branches have to be
//! instantiated inside the `eval_if` anyway.
//!
//! There are several caveats to note with this approach to lazy branching.
//! First, because we're using lambdas, it means that the function's
//! result can't be used in a constant expression. This is a limitation
//! of the current language.
//!
//! The second caveat is that compilers currently have several bugs
//! regarding deeply nested lambdas with captures. So you always risk
//! crashing the compiler, but this is a question of time before it is
//! not a problem anymore.
//!
//! Finally, it means that conditionals can't be written directly inside
//! unevaluated contexts. The reason is that a lambda can't appear in an
//! unevaluated context, for example in `decltype`. One way to workaround
//! this is to completely lift your type computations into variable
//! templates instead. For example, instead of writing
//! @code
//! template <typename T>
//! struct pointerize : decltype(
//! hana::eval_if(hana::traits::is_pointer(hana::type_c<T>),
//! [] { return hana::type_c<T>; },
//! [](auto _) { return _(hana::traits::add_pointer)(hana::type_c<T>); }
//! ))
//! { };
//! @endcode
//!
//! you could instead write
//!
//! @code
//! template <typename T>
//! auto pointerize_impl(T t) {
//! return hana::eval_if(hana::traits::is_pointer(t),
//! [] { return hana::type_c<T>; },
//! [](auto _) { return _(hana::traits::add_pointer)(hana::type_c<T>); }
//! );
//! }
//!
//! template <typename T>
//! using pointerize = decltype(pointerize_impl(hana::type_c<T>));
//! @endcode
//!
//! > __Note__: This example would actually be implemented more easily
//! > with partial specializations, but my bag of good examples is empty
//! > at the time of writing this.
//!
//! Now, this hoop-jumping only has to be done in one place, because
//! you should use normal function notation everywhere else in your
//! metaprogram to perform type computations. So the syntactic
//! cost is amortized over the whole program.
//!
//! Another way to work around this limitation of the language would be
//! to use `hana::lazy` for the branches. However, this is only suitable
//! when the branches are not too complicated. With `hana::lazy`, you
//! could write the previous example as
//! @code
//! template <typename T>
//! struct pointerize : decltype(
//! hana::eval_if(hana::traits::is_pointer(hana::type_c<T>),
//! hana::make_lazy(hana::type_c<T>),
//! hana::make_lazy(hana::traits::add_pointer)(hana::type_c<T>)
//! ))
//! { };
//! @endcode
//!
//!
//! @param cond
//! The condition determining which of the two branches is selected.
//!
//! @param then
//! An expression called as `eval(then)` if `cond` is true-valued.
//!
//! @param else_
//! A function called as `eval(else_)` if `cond` is false-valued.
//!
//!
//! Example
//! -------
//! @include example/eval_if.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto eval_if = [](auto&& cond, auto&& then, auto&& else_) -> decltype(auto) {
return tag-dispatched;
};
#else
template <typename L, typename = void>
struct eval_if_impl : eval_if_impl<L, when<true>> { };
struct eval_if_t {
template <typename Cond, typename Then, typename Else>
constexpr decltype(auto) operator()(Cond&& cond, Then&& then, Else&& else_) const;
};
constexpr eval_if_t eval_if{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_EVAL_IF_HPP
@@ -0,0 +1,62 @@
/*!
@file
Forward declares `boost::hana::extend`.
@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)
*/
#ifndef BOOST_HANA_FWD_EXTEND_HPP
#define BOOST_HANA_FWD_EXTEND_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Comonadic application of a function to a comonadic value.
//! @ingroup group-Comonad
//!
//! Given a comonadic value and a function accepting a comonadic input,
//! `extend` returns the result of applying the function to that input
//! inside the comonadic context.
//!
//!
//! Signature
//! ---------
//! Given a Comonad `W` and a function of type \f$ W(T) \to U \f$, the
//! signature is
//! \f$
//! \mathtt{extend} : W(T) \times (W(T) \to U) \to W(U)
//! \f$
//!
//! @param w
//! A comonadic value to call the function with.
//!
//! @param f
//! A function of signature \f$ W(T) \to U \f$ to be applied to its
//! comonadic argument inside the comonadic context.
//!
//!
//! Example
//! -------
//! @include example/extend.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto extend = [](auto&& w, auto&& f) -> decltype(auto) {
return tag-dispatched;
};
#else
template <typename W, typename = void>
struct extend_impl : extend_impl<W, when<true>> { };
struct extend_t {
template <typename W_, typename F>
constexpr decltype(auto) operator()(W_&& w, F&& f) const;
};
constexpr extend_t extend{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_EXTEND_HPP
@@ -0,0 +1,58 @@
/*!
@file
Forward declares `boost::hana::extract`.
@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)
*/
#ifndef BOOST_HANA_FWD_EXTRACT_HPP
#define BOOST_HANA_FWD_EXTRACT_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Extract a value in a given comonadic context.
//! @ingroup group-Comonad
//!
//! Given a value inside a comonadic context, extract it from that
//! context, performing whatever effects are mandated by that context.
//! This can be seen as the dual operation to the `lift` method of the
//! Applicative concept.
//!
//!
//! Signature
//! ---------
//! Given a Comonad `W`, the signature is
//! \f$
//! \mathtt{extract} : W(T) \to T
//! \f$
//!
//! @param w
//! The value to be extracted inside a comonadic context.
//!
//!
//! Example
//! -------
//! @include example/extract.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto extract = [](auto&& w) -> decltype(auto) {
return tag-dispatched;
};
#else
template <typename W, typename = void>
struct extract_impl : extract_impl<W, when<true>> { };
struct extract_t {
template <typename W_>
constexpr decltype(auto) operator()(W_&& w) const;
};
constexpr extract_t extract{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_EXTRACT_HPP
@@ -0,0 +1,57 @@
/*!
@file
Forward declares `boost::hana::fill`.
@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)
*/
#ifndef BOOST_HANA_FWD_FILL_HPP
#define BOOST_HANA_FWD_FILL_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Replace all the elements of a structure with a fixed value.
//! @ingroup group-Functor
//!
//!
//! Signature
//! ---------
//! Given `F` a Functor, the signature is
//! \f$
//! \mathtt{fill} : F(T) \times U \to F(U)
//! \f$
//!
//! @param xs
//! The structure to fill with a `value`.
//!
//! @param value
//! A value by which every element `x` of the structure is replaced,
//! unconditionally.
//!
//!
//! Example
//! -------
//! @include example/fill.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto fill = [](auto&& xs, auto&& value) {
return tag-dispatched;
};
#else
template <typename Xs, typename = void>
struct fill_impl : fill_impl<Xs, when<true>> { };
struct fill_t {
template <typename Xs, typename Value>
constexpr auto operator()(Xs&& xs, Value&& value) const;
};
constexpr fill_t fill{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_FILL_HPP
@@ -0,0 +1,81 @@
/*!
@file
Forward declares `boost::hana::filter`.
@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)
*/
#ifndef BOOST_HANA_FWD_FILTER_HPP
#define BOOST_HANA_FWD_FILTER_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Filter a monadic structure using a custom predicate.
//! @ingroup group-MonadPlus
//!
//! Given a monadic structure and a predicate, `filter` returns a new
//! monadic structure containing only those elements that satisfy the
//! predicate. This is a generalization of the usual `filter` function
//! for sequences; it works for any MonadPlus. Intuitively, `filter` is
//! somewhat equivalent to:
//! @code
//! filter(xs, pred) == flatten(transform(xs, [](auto x) {
//! return pred(x) ? lift<Xs>(x) : empty<Xs>();
//! })
//! @endcode
//! In other words, we basically turn a monadic structure containing
//! `[x1, ..., xn]` into a monadic structure containing
//! @code
//! [
//! pred(x1) ? [x1] : [],
//! pred(x2) ? [x2] : [],
//! ...
//! pred(xn) ? [xn] : []
//! ]
//! @endcode
//! and we then `flatten` that.
//!
//!
//! Signature
//! ---------
//! Given a `MonadPlus` `M` and an `IntegralConstant` `Bool` holding a
//! value of type `bool`, the signature is
//! @f$ \mathtt{filter} : M(T) \times (T \to \mathtt{Bool}) \to M(T) @f$.
//!
//! @param xs
//! The monadic structure to filter.
//!
//! @param pred
//! A function called as `pred(x)` for each element `x` in the monadic
//! structure and returning whether that element should be __kept__ in
//! the resulting structure. In the current version of the library, the
//! predicate has to return an `IntegralConstant` holding a value
//! convertible to a `bool`.
//!
//!
//! Example
//! -------
//! @include example/filter.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto filter = [](auto&& xs, auto&& pred) {
return tag-dispatched;
};
#else
template <typename M, typename = void>
struct filter_impl : filter_impl<M, when<true>> { };
struct filter_t {
template <typename Xs, typename Pred>
constexpr auto operator()(Xs&& xs, Pred&& pred) const;
};
constexpr filter_t filter{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_FILTER_HPP
@@ -0,0 +1,60 @@
/*!
@file
Forward declares `boost::hana::find`.
@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)
*/
#ifndef BOOST_HANA_FWD_FIND_HPP
#define BOOST_HANA_FWD_FIND_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Finds the value associated to the given key in a structure.
//! @ingroup group-Searchable
//!
//! Given a `key` and a `Searchable` structure, `find` returns the `just`
//! the first value whose key is equal to the given `key`, or `nothing` if
//! there is no such key. Comparison is done with `equal`. `find` satisfies
//! the following:
//! @code
//! find(xs, key) == find_if(xs, equal.to(key))
//! @endcode
//!
//!
//! @param xs
//! The structure to be searched.
//!
//! @param key
//! A key to be searched for in the structure. The key has to be
//! `Comparable` with the other keys of the structure. In the current
//! version of the library, the comparison of `key` with any other key
//! of the structure must return a compile-time `Logical`.
//!
//!
//! Example
//! -------
//! @include example/find.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto find = [](auto&& xs, auto const& key) {
return tag-dispatched;
};
#else
template <typename S, typename = void>
struct find_impl : find_impl<S, when<true>> { };
struct find_t {
template <typename Xs, typename Key>
constexpr auto operator()(Xs&& xs, Key const& key) const;
};
constexpr find_t find{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_FIND_HPP
@@ -0,0 +1,57 @@
/*!
@file
Forward declares `boost::hana::find_if`.
@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)
*/
#ifndef BOOST_HANA_FWD_FIND_IF_HPP
#define BOOST_HANA_FWD_FIND_IF_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Finds the value associated to the first key satisfying a predicate.
//! @ingroup group-Searchable
//!
//! Given a `Searchable` structure `xs` and a predicate `pred`,
//! `find_if(xs, pred)` returns `just` the first element whose key
//! satisfies the predicate, or `nothing` if there is no such element.
//!
//!
//! @param xs
//! The structure to be searched.
//!
//! @param predicate
//! A function called as `predicate(k)`, where `k` is a key of the
//! structure, and returning whether `k` is the key of the element
//! being searched for. In the current version of the library, the
//! predicate has to return an `IntegralConstant` holding a value
//! that can be converted to `bool`.
//!
//!
//! Example
//! -------
//! @include example/find_if.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto find_if = [](auto&& xs, auto&& predicate) {
return tag-dispatched;
};
#else
template <typename S, typename = void>
struct find_if_impl : find_if_impl<S, when<true>> { };
struct find_if_t {
template <typename Xs, typename Pred>
constexpr auto operator()(Xs&& xs, Pred&& pred) const;
};
constexpr find_if_t find_if{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_FIND_IF_HPP
@@ -0,0 +1,49 @@
/*!
@file
Forward declares `boost::hana::first`.
@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)
*/
#ifndef BOOST_HANA_FWD_FIRST_HPP
#define BOOST_HANA_FWD_FIRST_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Returns the first element of a pair.
//! @ingroup group-Product
//!
//! Note that if the `Product` actually stores the elements it contains,
//! `hana::first` is required to return a lvalue reference, a lvalue
//! reference to const or a rvalue reference to the first element, where
//! the type of reference must match that of the pair passed to `first`.
//! If the `Product` does not store the elements it contains (i.e. it
//! generates them on demand), this requirement is dropped.
//!
//!
//! Example
//! -------
//! @include example/first.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto first = [](auto&& product) -> decltype(auto) {
return tag-dispatched;
};
#else
template <typename P, typename = void>
struct first_impl : first_impl<P, when<true>> { };
struct first_t {
template <typename Pair>
constexpr decltype(auto) operator()(Pair&& pair) const;
};
constexpr first_t first{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_FIRST_HPP
@@ -0,0 +1,63 @@
/*!
@file
Forward declares `boost::hana::flatten`.
@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)
*/
#ifndef BOOST_HANA_FWD_FLATTEN_HPP
#define BOOST_HANA_FWD_FLATTEN_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Collapse two levels of monadic structure into a single level.
//! @ingroup group-Monad
//!
//! Given a monadic value wrapped into two levels of monad, `flatten`
//! removes one such level. An implementation of `flatten` must satisfy
//! @code
//! flatten(xs) == chain(xs, id)
//! @endcode
//!
//! For `Sequence`s, this simply takes a `Sequence` of `Sequence`s, and
//! returns a (non-recursively) flattened `Sequence`.
//!
//!
//! Signature
//! ---------
//! For a `Monad` `M`, the signature of `flatten` is
//! @f$
//! \mathtt{flatten} : M(M(T)) \to M(T)
//! @f$
//!
//! @param xs
//! A value with two levels of monadic structure, which should be
//! collapsed into a single level of structure.
//!
//!
//! Example
//! -------
//! @include example/flatten.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto flatten = [](auto&& xs) {
return tag-dispatched;
};
#else
template <typename M, typename = void>
struct flatten_impl : flatten_impl<M, when<true>> { };
struct flatten_t {
template <typename Xs>
constexpr auto operator()(Xs&& xs) const;
};
constexpr flatten_t flatten{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_FLATTEN_HPP
@@ -0,0 +1,38 @@
/*!
@file
Forward declares `boost::hana::fold`.
@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)
*/
#ifndef BOOST_HANA_FWD_FOLD_HPP
#define BOOST_HANA_FWD_FOLD_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/fwd/fold_left.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Equivalent to `fold_left`; provided for convenience.
//! @ingroup group-Foldable
//!
//! `fold` is equivalent to `fold_left`. However, it is not tag-dispatched
//! on its own because it is just an alias to `fold_left`. Also note that
//! `fold` can be called with or without an initial state, just like
//! `fold_left`:
//!
//! @code
//! fold(xs, state, f) == fold_left(xs, state, f)
//! fold(xs, f) == fold_left(xs, f)
//! @endcode
//!
//!
//! Example
//! -------
//! @include example/fold.cpp
constexpr auto fold = fold_left;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_FOLD_HPP
@@ -0,0 +1,88 @@
/*!
@file
Forward declares `boost::hana::fold_left`.
@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)
*/
#ifndef BOOST_HANA_FWD_FOLD_LEFT_HPP
#define BOOST_HANA_FWD_FOLD_LEFT_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Left-fold of a structure using a binary operation and an optional
//! initial reduction state.
//! @ingroup group-Foldable
//!
//! `fold_left` is a left-associative fold using a binary operation.
//! Given a structure containing `x1, ..., xn`, a function `f` and
//! an optional initial state, `fold_left` applies `f` as follows
//! @code
//! f(... f(f(f(x1, x2), x3), x4) ..., xn) // without state
//! f(... f(f(f(f(state, x1), x2), x3), x4) ..., xn) // with state
//! @endcode
//!
//! When the structure is empty, two things may arise. If an initial
//! state was provided, it is returned as-is. Otherwise, if the no-state
//! version of the function was used, an error is triggered. When the
//! stucture contains a single element and the no-state version of the
//! function was used, that single element is returned as is.
//!
//!
//! Signature
//! ---------
//! Given a `Foldable` `F` and an optional initial state of tag `S`,
//! the signatures for `fold_left` are
//! \f[
//! \mathtt{fold\_left} : F(T) \times S \times (S \times T \to S) \to S
//! \f]
//!
//! for the variant with an initial state, and
//! \f[
//! \mathtt{fold\_left} : F(T) \times (T \times T \to T) \to T
//! \f]
//!
//! for the variant without an initial state.
//!
//! @param xs
//! The structure to fold.
//!
//! @param state
//! The initial value used for folding.
//!
//! @param f
//! A binary function called as `f(state, x)`, where `state` is the
//! result accumulated so far and `x` is an element in the structure.
//! For left folds without an initial state, the function is called as
//! `f(x1, x2)`, where `x1` and `x2` are elements of the structure.
//!
//!
//! Example
//! -------
//! @include example/fold_left.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto fold_left = [](auto&& xs[, auto&& state], auto&& f) -> decltype(auto) {
return tag-dispatched;
};
#else
template <typename T, typename = void>
struct fold_left_impl : fold_left_impl<T, when<true>> { };
struct fold_left_t {
template <typename Xs, typename State, typename F>
constexpr decltype(auto) operator()(Xs&& xs, State&& state, F&& f) const;
template <typename Xs, typename F>
constexpr decltype(auto) operator()(Xs&& xs, F&& f) const;
};
constexpr fold_left_t fold_left{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_FOLD_LEFT_HPP
@@ -0,0 +1,92 @@
/*!
@file
Forward declares `boost::hana::fold_right`.
@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)
*/
#ifndef BOOST_HANA_FWD_FOLD_RIGHT_HPP
#define BOOST_HANA_FWD_FOLD_RIGHT_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Right-fold of a structure using a binary operation and an optional
//! initial reduction state.
//! @ingroup group-Foldable
//!
//! `fold_right` is a right-associative fold using a binary operation.
//! Given a structure containing `x1, ..., xn`, a function `f` and
//! an optional initial state, `fold_right` applies `f` as follows
//! @code
//! f(x1, f(x2, f(x3, f(x4, ... f(xn-1, xn) ... )))) // without state
//! f(x1, f(x2, f(x3, f(x4, ... f(xn, state) ... )))) // with state
//! @endcode
//!
//! @note
//! It is worth noting that the order in which the binary function should
//! expect its arguments is reversed from `fold_left`.
//!
//! When the structure is empty, two things may arise. If an initial
//! state was provided, it is returned as-is. Otherwise, if the no-state
//! version of the function was used, an error is triggered. When the
//! stucture contains a single element and the no-state version of the
//! function was used, that single element is returned as is.
//!
//!
//! Signature
//! ---------
//! Given a `Foldable` `F` and an optional initial state of tag `S`,
//! the signatures for `fold_right` are
//! \f[
//! \mathtt{fold\_right} : F(T) \times S \times (T \times S \to S) \to S
//! \f]
//!
//! for the variant with an initial state, and
//! \f[
//! \mathtt{fold\_right} : F(T) \times (T \times T \to T) \to T
//! \f]
//!
//! for the variant without an initial state.
//!
//! @param xs
//! The structure to fold.
//!
//! @param state
//! The initial value used for folding.
//!
//! @param f
//! A binary function called as `f(x, state)`, where `state` is the
//! result accumulated so far and `x` is an element in the structure.
//! For right folds without an initial state, the function is called as
//! `f(x1, x2)`, where `x1` and `x2` are elements of the structure.
//!
//!
//! Example
//! -------
//! @include example/fold_right.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto fold_right = [](auto&& xs[, auto&& state], auto&& f) -> decltype(auto) {
return tag-dispatched;
};
#else
template <typename T, typename = void>
struct fold_right_impl : fold_right_impl<T, when<true>> { };
struct fold_right_t {
template <typename Xs, typename State, typename F>
constexpr decltype(auto) operator()(Xs&& xs, State&& state, F&& f) const;
template <typename Xs, typename F>
constexpr decltype(auto) operator()(Xs&& xs, F&& f) const;
};
constexpr fold_right_t fold_right{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_FOLD_RIGHT_HPP
@@ -0,0 +1,55 @@
/*!
@file
Forward declares `boost::hana::for_each`.
@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)
*/
#ifndef BOOST_HANA_FWD_FOR_EACH_HPP
#define BOOST_HANA_FWD_FOR_EACH_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Perform an action on each element of a foldable, discarding
//! the result each time.
//! @ingroup group-Foldable
//!
//! Iteration is done from left to right, i.e. in the same order as when
//! using `fold_left`. If the structure is not finite, this method will
//! not terminate.
//!
//!
//! @param xs
//! The structure to iterate over.
//!
//! @param f
//! A function called as `f(x)` for each element `x` of the structure.
//! The result of `f(x)`, whatever it is, is ignored.
//!
//!
//! Example
//! -------
//! @include example/for_each.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto for_each = [](auto&& xs, auto&& f) -> void {
tag-dispatched;
};
#else
template <typename T, typename = void>
struct for_each_impl : for_each_impl<T, when<true>> { };
struct for_each_t {
template <typename Xs, typename F>
constexpr void operator()(Xs&& xs, F&& f) const;
};
constexpr for_each_t for_each{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_FOR_EACH_HPP
@@ -0,0 +1,48 @@
/*!
@file
Forward declares `boost::hana::front`.
@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)
*/
#ifndef BOOST_HANA_FWD_FRONT_HPP
#define BOOST_HANA_FWD_FRONT_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Returns the first element of a non-empty iterable.
//! @ingroup group-Iterable
//!
//! Given a non-empty Iterable `xs` with a linearization of `[x1, ..., xN]`,
//! `front(xs)` is equal to `x1`. If `xs` is empty, it is an error to
//! use this function. Equivalently, `front(xs)` must be equivalent to
//! `at_c<0>(xs)`, and that regardless of the value category of `xs`
//! (`front` must respect the reference semantics of `at`).
//!
//!
//! Example
//! -------
//! @include example/front.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto front = [](auto&& xs) -> decltype(auto) {
return tag-dispatched;
};
#else
template <typename It, typename = void>
struct front_impl : front_impl<It, when<true>> { };
struct front_t {
template <typename Xs>
constexpr decltype(auto) operator()(Xs&& xs) const;
};
constexpr front_t front{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_FRONT_HPP
@@ -0,0 +1,55 @@
/*!
@file
Forward declares `boost::hana::fuse`.
@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)
*/
#ifndef BOOST_HANA_FWD_FUSE_HPP
#define BOOST_HANA_FWD_FUSE_HPP
#include <boost/hana/config.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Transform a function taking multiple arguments into a function that
//! can be called with a compile-time `Foldable`.
//! @ingroup group-Foldable
//!
//!
//! This function is provided for convenience as a different way of
//! calling `unpack`. Specifically, `fuse(f)` is a function such that
//! @code
//! fuse(f)(foldable) == unpack(foldable, f)
//! == f(x...)
//! @endcode
//! where `x...` are the elements in the foldable. This function is
//! useful when one wants to create a function that accepts a foldable
//! which is not known yet.
//!
//! @note
//! This function is not tag-dispatched; customize `unpack` instead.
//!
//!
//! Example
//! -------
//! @include example/fuse.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto fuse = [](auto&& f) {
return [perfect-capture](auto&& xs) -> decltype(auto) {
return unpack(forwarded(xs), forwarded(f));
};
};
#else
struct fuse_t {
template <typename F>
constexpr auto operator()(F&& f) const;
};
constexpr fuse_t fuse{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_FUSE_HPP
@@ -0,0 +1,53 @@
/*!
@file
Forward declares `boost::hana::greater`.
@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)
*/
#ifndef BOOST_HANA_FWD_GREATER_HPP
#define BOOST_HANA_FWD_GREATER_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
#include <boost/hana/detail/nested_than_fwd.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Returns a `Logical` representing whether `x` is greater than `y`.
//! @ingroup group-Orderable
//!
//!
//! Signature
//! ---------
//! Given a Logical `Bool` and two Orderables `A` and `B` with a common
//! embedding, the signature is
//! @f$ \mathrm{greater} : A \times B \to Bool @f$.
//!
//! @param x, y
//! Two objects to compare.
//!
//!
//! Example
//! -------
//! @include example/greater.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto greater = [](auto&& x, auto&& y) -> decltype(auto) {
return tag-dispatched;
};
#else
template <typename T, typename U, typename = void>
struct greater_impl : greater_impl<T, U, when<true>> { };
struct greater_t : detail::nested_than<greater_t> {
template <typename X, typename Y>
constexpr decltype(auto) operator()(X&& x, Y&& y) const;
};
constexpr greater_t greater{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_GREATER_HPP
@@ -0,0 +1,54 @@
/*!
@file
Forward declares `boost::hana::greater_equal`.
@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)
*/
#ifndef BOOST_HANA_FWD_GREATER_EQUAL_HPP
#define BOOST_HANA_FWD_GREATER_EQUAL_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
#include <boost/hana/detail/nested_than_fwd.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Returns a `Logical` representing whether `x` is greater than or
//! equal to `y`.
//! @ingroup group-Orderable
//!
//!
//! Signature
//! ---------
//! Given a Logical `Bool` and two Orderables `A` and `B` with a common
//! embedding, the signature is
//! @f$ \mathrm{greater\_equal} : A \times B \to Bool @f$.
//!
//! @param x, y
//! Two objects to compare.
//!
//!
//! Example
//! -------
//! @include example/greater_equal.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto greater_equal = [](auto&& x, auto&& y) -> decltype(auto) {
return tag-dispatched;
};
#else
template <typename T, typename U, typename = void>
struct greater_equal_impl : greater_equal_impl<T, U, when<true>> { };
struct greater_equal_t : detail::nested_than<greater_equal_t> {
template <typename X, typename Y>
constexpr decltype(auto) operator()(X&& x, Y&& y) const;
};
constexpr greater_equal_t greater_equal{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_GREATER_EQUAL_HPP
@@ -0,0 +1,103 @@
/*!
@file
Forward declares `boost::hana::group`.
@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)
*/
#ifndef BOOST_HANA_FWD_GROUP_HPP
#define BOOST_HANA_FWD_GROUP_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
#include <boost/hana/detail/nested_by_fwd.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Group adjacent elements of a sequence that all respect a binary
//! predicate, by default equality.
//! @ingroup group-Sequence
//!
//! Given a _finite_ Sequence and an optional predicate (by default
//! `equal`), `group` returns a sequence of subsequences representing
//! groups of adjacent elements that are "equal" with respect to the
//! predicate. In other words, the groups are such that the predicate is
//! satisfied when it is applied to any two adjacent elements in that
//! group. The sequence returned by `group` is such that the concatenation
//! of its elements is equal to the original sequence, which is equivalent
//! to saying that the order of the elements is not changed.
//!
//! If no predicate is provided, adjacent elements in the sequence must
//! all be compile-time `Comparable`.
//!
//!
//! Signature
//! ---------
//! Given a Sequence `s` with tag `S(T)`, an `IntegralConstant` `Bool`
//! holding a value of type `bool`, and a predicate
//! \f$ pred : T \times T \to Bool \f$, `group` has the following
//! signatures. For the variant with a provided predicate,
//! \f[
//! \mathtt{group} : S(T) \times (T \times T \to Bool) \to S(S(T))
//! \f]
//!
//! for the variant without a custom predicate, `T` is required to be
//! Comparable. The signature is then
//! \f[
//! \mathtt{group} : S(T) \to S(S(T))
//! \f]
//!
//! @param xs
//! The sequence to split into groups.
//!
//! @param predicate
//! A binary function called as `predicate(x, y)`, where `x` and `y` are
//! _adjacent_ elements in the sequence, whether both elements should be
//! in the same group (subsequence) of the result. In the current version
//! of the library, the result returned by `predicate` must be an
//! `IntegralConstant` holding a value of a type convertible to `bool`.
//! Also, `predicate` has to define an equivalence relation as defined by
//! the `Comparable` concept. When this predicate is not provided, it
//! defaults to `equal`, which requires the comparison of any two adjacent
//! elements in the sequence to return a boolean `IntegralConstant`.
//!
//!
//! Syntactic sugar (`group.by`)
//! ----------------------------
//! `group` can be called in a third way, which provides a nice syntax
//! especially when working with the `comparing` combinator:
//! @code
//! group.by(predicate, xs) == group(xs, predicate)
//! group.by(predicate) == group(-, predicate)
//! @endcode
//!
//! where `group(-, predicate)` denotes the partial application of
//! `group` to `predicate`.
//!
//!
//! Example
//! -------
//! @include example/group.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto group = [](auto&& xs[, auto&& predicate]) {
return tag-dispatched;
};
#else
template <typename S, typename = void>
struct group_impl : group_impl<S, when<true>> { };
struct group_t : detail::nested_by<group_t> {
template <typename Xs>
constexpr auto operator()(Xs&& xs) const;
template <typename Xs, typename Predicate>
constexpr auto operator()(Xs&& xs, Predicate&& pred) const;
};
constexpr group_t group{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_GROUP_HPP
@@ -0,0 +1,68 @@
/*!
@file
Forward declares `boost::hana::hash`.
@copyright Louis Dionne 2016
@copyright Jason Rice 2016
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
#ifndef BOOST_HANA_FWD_HASH_HPP
#define BOOST_HANA_FWD_HASH_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Returns a `hana::type` representing the compile-time hash of an object.
//! @ingroup group-Hashable
//!
//! Given an arbitrary object `x`, `hana::hash` returns a `hana::type`
//! representing the hash of `x`. In normal programming, hashes are
//! usually numerical values that can be used e.g. as indices in an
//! array as part of the implementation of a hash table. In the context
//! of metaprogramming, we are interested in type-level hashes instead.
//! Thus, `hana::hash` must return a `hana::type` object instead of an
//! integer. This `hana::type` must somehow summarize the object being
//! hashed, but that summary may of course lose some information.
//!
//! In order for the `hash` function to be defined properly, it must be
//! the case that whenever `x` is equal to `y`, then `hash(x)` is equal
//! to `hash(y)`. This ensures that `hana::hash` is a function in the
//! mathematical sense of the term.
//!
//!
//! Signature
//! ---------
//! Given a `Hashable` `H`, the signature is
//! \f$
//! \mathtt{hash} : H \to \mathtt{type\_tag}
//! \f$
//!
//! @param x
//! An object whose hash is to be computed.
//!
//!
//! Example
//! -------
//! @include example/hash.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto hash = [](auto const& x) {
return tag-dispatched;
};
#else
template <typename T, typename = void>
struct hash_impl : hash_impl<T, when<true>> { };
struct hash_t {
template <typename X>
constexpr auto operator()(X const& x) const;
};
constexpr hash_t hash{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_HASH_HPP
@@ -0,0 +1,57 @@
/*!
@file
Forward declares `boost::hana::if_`.
@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)
*/
#ifndef BOOST_HANA_FWD_IF_HPP
#define BOOST_HANA_FWD_IF_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Conditionally return one of two values based on a condition.
//! @ingroup group-Logical
//!
//! Specifically, `then` is returned iff `cond` is true-valued, and
//! `else_` is returned otherwise. Note that some `Logical` models may
//! allow `then` and `else_` to have different types, while others may
//! require both values to have the same type.
//!
//!
//! @param cond
//! The condition determining which of the two values is returned.
//!
//! @param then
//! The value returned when `cond` is true-valued.
//!
//! @param else_
//! The value returned when `cond` is false-valued.
//!
//!
//! Example
//! -------
//! @include example/if.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto if_ = [](auto&& cond, auto&& then, auto&& else_) -> decltype(auto) {
return tag-dispatched;
};
#else
template <typename L, typename = void>
struct if_impl : if_impl<L, when<true>> { };
struct if_t {
template <typename Cond, typename Then, typename Else>
constexpr decltype(auto) operator()(Cond&& cond, Then&& then, Else&& else_) const;
};
constexpr if_t if_{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_IF_HPP
@@ -0,0 +1,60 @@
/*!
@file
Forward declares `boost::hana::insert`.
@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)
*/
#ifndef BOOST_HANA_FWD_INSERT_HPP
#define BOOST_HANA_FWD_INSERT_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
// Note: This function is documented per datatype/concept only.
//! @cond
template <typename T, typename = void>
struct insert_impl : insert_impl<T, when<true>> { };
//! @endcond
struct insert_t {
template <typename Set, typename ...Args>
constexpr decltype(auto) operator()(Set&& set, Args&& ...args) const;
};
constexpr insert_t insert{};
//! Insert a value at a given index in a sequence.
//! @ingroup group-Sequence
//!
//! Given a sequence, an index and an element to insert, `insert` inserts
//! the element at the given index.
//!
//! @param xs
//! The sequence in which a value should be inserted.
//!
//! @param n
//! The index at which an element should be inserted. This must be a
//! non-negative `Constant` of an integral type, and it must also be
//! true that `n < length(xs)` if `xs` is a finite sequence.
//!
//! @param element
//! The element to insert in the sequence.
//!
//!
//! Example
//! -------
//! @include example/insert.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto insert = [](auto&& xs, auto&& n, auto&& element) {
return tag-dispatched;
};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_INSERT_HPP
@@ -0,0 +1,57 @@
/*!
@file
Forward declares `boost::hana::insert_range`.
@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)
*/
#ifndef BOOST_HANA_FWD_INSERT_RANGE_HPP
#define BOOST_HANA_FWD_INSERT_RANGE_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Insert several values at a given index in a sequence.
//! @ingroup group-Sequence
//!
//! Given a sequence, an index and any `Foldable` containing elements to
//! insert, `insert_range` inserts the elements in the `Foldable` at the
//! given index of the sequence.
//!
//! @param xs
//! The sequence in which values should be inserted.
//!
//! @param n
//! The index at which elements should be inserted. This must be a
//! non-negative `Constant` of an integral type, and it must also be
//! true that `n < length(xs)` if `xs` is a finite sequence.
//!
//! @param elements
//! A `Foldable` containing elements to insert in the sequence.
//!
//!
//! Example
//! -------
//! @include example/insert_range.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto insert_range = [](auto&& xs, auto&& n, auto&& elements) {
return tag-dispatched;
};
#else
template <typename S, typename = void>
struct insert_range_impl : insert_range_impl<S, when<true>> { };
struct insert_range_t {
template <typename Xs, typename N, typename Elements>
constexpr auto operator()(Xs&& xs, N&& n, Elements&& elements) const;
};
constexpr insert_range_t insert_range{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_INSERT_RANGE_HPP
@@ -0,0 +1,175 @@
/*!
@file
Forward declares `boost::hana::integral_constant`.
@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)
*/
#ifndef BOOST_HANA_FWD_INTEGRAL_CONSTANT_HPP
#define BOOST_HANA_FWD_INTEGRAL_CONSTANT_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/detail/integral_constant.hpp>
#include <cstddef>
BOOST_HANA_NAMESPACE_BEGIN
//! Creates an `integral_constant` holding the given compile-time value.
//! @relates hana::integral_constant
//!
//! Specifically, `integral_c<T, v>` is a `hana::integral_constant`
//! holding the compile-time value `v` of an integral type `T`.
//!
//!
//! @tparam T
//! The type of the value to hold in the `integral_constant`.
//! It must be an integral type.
//!
//! @tparam v
//! The integral value to hold in the `integral_constant`.
//!
//!
//! Example
//! -------
//! @snippet example/integral_constant.cpp integral_c
template <typename T, T v>
constexpr integral_constant<T, v> integral_c{};
//! @relates hana::integral_constant
template <bool b>
using bool_ = integral_constant<bool, b>;
//! @relates hana::integral_constant
template <bool b>
constexpr bool_<b> bool_c{};
//! @relates hana::integral_constant
using true_ = bool_<true>;
//! @relates hana::integral_constant
constexpr auto true_c = bool_c<true>;
//! @relates hana::integral_constant
using false_ = bool_<false>;
//! @relates hana::integral_constant
constexpr auto false_c = bool_c<false>;
//! @relates hana::integral_constant
template <char c>
using char_ = integral_constant<char, c>;
//! @relates hana::integral_constant
template <char c>
constexpr char_<c> char_c{};
//! @relates hana::integral_constant
template <short i>
using short_ = integral_constant<short, i>;
//! @relates hana::integral_constant
template <short i>
constexpr short_<i> short_c{};
//! @relates hana::integral_constant
template <unsigned short i>
using ushort_ = integral_constant<unsigned short, i>;
//! @relates hana::integral_constant
template <unsigned short i>
constexpr ushort_<i> ushort_c{};
//! @relates hana::integral_constant
template <int i>
using int_ = integral_constant<int, i>;
//! @relates hana::integral_constant
template <int i>
constexpr int_<i> int_c{};
//! @relates hana::integral_constant
template <unsigned int i>
using uint = integral_constant<unsigned int, i>;
//! @relates hana::integral_constant
template <unsigned int i>
constexpr uint<i> uint_c{};
//! @relates hana::integral_constant
template <long i>
using long_ = integral_constant<long, i>;
//! @relates hana::integral_constant
template <long i>
constexpr long_<i> long_c{};
//! @relates hana::integral_constant
template <unsigned long i>
using ulong = integral_constant<unsigned long, i>;
//! @relates hana::integral_constant
template <unsigned long i>
constexpr ulong<i> ulong_c{};
//! @relates hana::integral_constant
template <long long i>
using llong = integral_constant<long long, i>;
//! @relates hana::integral_constant
template <long long i>
constexpr llong<i> llong_c{};
//! @relates hana::integral_constant
template <unsigned long long i>
using ullong = integral_constant<unsigned long long, i>;
//! @relates hana::integral_constant
template <unsigned long long i>
constexpr ullong<i> ullong_c{};
//! @relates hana::integral_constant
template <std::size_t i>
using size_t = integral_constant<std::size_t, i>;
//! @relates hana::integral_constant
template <std::size_t i>
constexpr size_t<i> size_c{};
namespace literals {
//! Creates a `hana::integral_constant` from a literal.
//! @relatesalso boost::hana::integral_constant
//!
//! The literal is parsed at compile-time and the result is returned
//! as a `llong<...>`.
//!
//! @note
//! We use `llong<...>` instead of `ullong<...>` because using an
//! unsigned type leads to unexpected behavior when doing stuff like
//! `-1_c`. If we used an unsigned type, `-1_c` would be something
//! like `ullong<-1>` which is actually `ullong<something huge>`.
//!
//!
//! Example
//! -------
//! @snippet example/integral_constant.cpp literals
template <char ...c>
constexpr auto operator"" _c();
}
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_INTEGRAL_CONSTANT_HPP
@@ -0,0 +1,53 @@
/*!
@file
Forward declares `boost::hana::intersection`.
@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)
*/
#ifndef BOOST_HANA_FWD_INTERSECTION_HPP
#define BOOST_HANA_FWD_INTERSECTION_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Returns the intersection of two sets.
//! @relates hana::set
//!
//! Given two sets `xs` and `ys`, `intersection(xs, ys)` is a new set
//! containing exactly those elements that are present both in `xs` and
//! in `ys`. In other words, the following holds for any object `x`:
//! @code
//! x ^in^ intersection(xs, ys) if and only if x ^in^ xs && x ^in^ ys
//! @endcode
//!
//!
//! @param xs, ys
//! Two sets to intersect.
//!
//!
//! Example
//! -------
//! @include example/intersection.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto intersection = [](auto&& xs, auto&& ys) {
return tag-dispatched;
};
#else
template <typename S, typename = void>
struct intersection_impl : intersection_impl<S, when<true>> { };
struct intersection_t {
template <typename Xs, typename Ys>
constexpr auto operator()(Xs&& xs, Ys&& ys) const;
};
constexpr intersection_t intersection{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_INTERSECTION_HPP
@@ -0,0 +1,57 @@
/*!
@file
Forward declares `boost::hana::intersperse`.
@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)
*/
#ifndef BOOST_HANA_FWD_INTERSPERSE_HPP
#define BOOST_HANA_FWD_INTERSPERSE_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Insert a value between each pair of elements in a finite sequence.
//! @ingroup group-Sequence
//!
//! Given a finite `Sequence` `xs` with a linearization of
//! `[x1, x2, ..., xn]`, `intersperse(xs, z)` is a new sequence with a
//! linearization of `[x1, z, x2, z, x3, ..., xn-1, z, xn]`. In other
//! words, it inserts the `z` element between every pair of elements of
//! the original sequence. If the sequence is empty or has a single
//! element, `intersperse` returns the sequence as-is. In all cases,
//! the sequence must be finite.
//!
//!
//! @param xs
//! The sequence in which a value is interspersed.
//!
//! @param z
//! The value to be inserted between every pair of elements of the sequence.
//!
//!
//! Example
//! -------
//! @include example/intersperse.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto intersperse = [](auto&& xs, auto&& z) {
return tag-dispatched;
};
#else
template <typename S, typename = void>
struct intersperse_impl : intersperse_impl<S, when<true>> { };
struct intersperse_t {
template <typename Xs, typename Z>
constexpr auto operator()(Xs&& xs, Z&& z) const;
};
constexpr intersperse_t intersperse{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_INTERSPERSE_HPP
@@ -0,0 +1,50 @@
/*!
@file
Forward declares `boost::hana::is_disjoint`.
@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)
*/
#ifndef BOOST_HANA_FWD_IS_DISJOINT_HPP
#define BOOST_HANA_FWD_IS_DISJOINT_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Returns whether two `Searchable`s are disjoint.
//! @ingroup group-Searchable
//!
//! Given two `Searchable`s `xs` and `ys`, `is_disjoint` returns a
//! `Logical` representing whether the keys in `xs` are disjoint from
//! the keys in `ys`, i.e. whether both structures have no keys in common.
//!
//!
//! @param xs, ys
//! Two `Searchable`s to test for disjointness.
//!
//!
//! Example
//! -------
//! @include example/is_disjoint.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto is_disjoint = [](auto const& xs, auto const& ys) {
return tag-dispatched;
};
#else
template <typename S1, typename S2, typename = void>
struct is_disjoint_impl : is_disjoint_impl<S1, S2, when<true>> { };
struct is_disjoint_t {
template <typename Xs, typename Ys>
constexpr auto operator()(Xs&& xs, Ys&& ys) const;
};
constexpr is_disjoint_t is_disjoint{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_IS_DISJOINT_HPP
@@ -0,0 +1,49 @@
/*!
@file
Forward declares `boost::hana::is_empty`.
@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)
*/
#ifndef BOOST_HANA_FWD_IS_EMPTY_HPP
#define BOOST_HANA_FWD_IS_EMPTY_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Returns whether the iterable is empty.
//! @ingroup group-Iterable
//!
//! Given an `Iterable` `xs`, `is_empty` returns whether `xs` contains
//! no more elements. In other words, it returns whether trying to
//! extract the tail of `xs` would be an error. In the current version
//! of the library, `is_empty` must return an `IntegralConstant` holding
//! a value convertible to `bool`. This is because only compile-time
//! `Iterable`s are supported right now.
//!
//!
//! Example
//! -------
//! @include example/is_empty.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto is_empty = [](auto const& xs) {
return tag-dispatched;
};
#else
template <typename It, typename = void>
struct is_empty_impl : is_empty_impl<It, when<true>> { };
struct is_empty_t {
template <typename Xs>
constexpr auto operator()(Xs const& xs) const;
};
constexpr is_empty_t is_empty{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_IS_EMPTY_HPP
@@ -0,0 +1,79 @@
/*!
@file
Forward declares `boost::hana::is_subset`.
@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)
*/
#ifndef BOOST_HANA_FWD_IS_SUBSET_HPP
#define BOOST_HANA_FWD_IS_SUBSET_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
#include <boost/hana/functional/infix.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Returns whether a structure contains a subset of the keys of
//! another structure.
//! @ingroup group-Searchable
//!
//! Given two `Searchable`s `xs` and `ys`, `is_subset` returns a `Logical`
//! representing whether `xs` is a subset of `ys`. In other words, it
//! returns whether all the keys of `xs` are also present in `ys`. This
//! method does not return whether `xs` is a _strict_ subset of `ys`; if
//! `xs` and `ys` are equal, all the keys of `xs` are also present in
//! `ys`, and `is_subset` returns true.
//!
//! @note
//! For convenience, `is_subset` can also be applied in infix notation.
//!
//!
//! Cross-type version of the method
//! --------------------------------
//! This method is tag-dispatched using the tags of both arguments.
//! It can be called with any two `Searchable`s sharing a common
//! `Searchable` embedding, as defined in the main documentation
//! of the `Searchable` concept. When `Searchable`s with two different
//! tags but sharing a common embedding are sent to `is_subset`, they
//! are first converted to this common `Searchable` and the `is_subset`
//! method of the common embedding is then used. Of course, the method
//! can be overriden for custom `Searchable`s for efficieny.
//!
//! @note
//! While cross-type dispatching for `is_subset` is supported, it is
//! not currently used by the library because there are no models
//! of `Searchable` with a common embedding.
//!
//!
//! @param xs
//! The structure to check whether it is a subset of `ys`.
//!
//! @param ys
//! The structure to check whether it is a superset of `xs`.
//!
//!
//! Example
//! -------
//! @include example/is_subset.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto is_subset = [](auto&& xs, auto&& ys) {
return tag-dispatched;
};
#else
template <typename S1, typename S2, typename = void>
struct is_subset_impl : is_subset_impl<S1, S2, when<true>> { };
struct is_subset_t {
template <typename Xs, typename Ys>
constexpr auto operator()(Xs&& xs, Ys&& ys) const;
};
constexpr auto is_subset = hana::infix(is_subset_t{});
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_IS_SUBSET_HPP
@@ -0,0 +1,50 @@
/*!
@file
Forward declares `boost::hana::keys`.
@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)
*/
#ifndef BOOST_HANA_FWD_KEYS_HPP
#define BOOST_HANA_FWD_KEYS_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
// Note: This function is documented per datatype/concept only.
//! @cond
template <typename T, typename = void>
struct keys_impl : keys_impl<T, when<true>> { };
//! @endcond
struct keys_t {
template <typename Map>
constexpr auto operator()(Map&& map) const;
};
constexpr keys_t keys{};
//! Returns a `Sequence` containing the name of the members of
//! the data structure.
//! @ingroup group-Struct
//!
//! Given a `Struct` object, `keys` returns a `Sequence` containing the
//! name of all the members of the `Struct`, in the same order as they
//! appear in the `accessors` sequence.
//!
//!
//! Example
//! -------
//! @include example/struct/keys.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto keys = [](auto&& object) {
return implementation_defined;
};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_KEYS_HPP
@@ -0,0 +1,124 @@
/*!
@file
Forward declares `boost::hana::lazy`.
@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)
*/
#ifndef BOOST_HANA_FWD_LAZY_HPP
#define BOOST_HANA_FWD_LAZY_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/fwd/core/make.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-datatypes
//! `hana::lazy` implements superficial laziness via a monadic interface.
//!
//! It is important to understand that the laziness implemented by `lazy`
//! is only superficial; only function applications made inside the `lazy`
//! monad can be made lazy, not all their subexpressions.
//!
//!
//! @note
//! The actual representation of `hana::lazy` is completely
//! implementation-defined. Lazy values may only be created through
//! `hana::make_lazy`, and they can be stored in variables using
//! `auto`, but any other assumption about the representation of
//! `hana::lazy<...>` should be avoided. In particular, one should
//! not rely on the fact that `hana::lazy<...>` can be pattern-matched
//! on, because it may be a dependent type.
//!
//!
//! Modeled concepts
//! ----------------
//! 1. `Functor`\n
//! Applying a function over a lazy value with `transform` returns the
//! result of applying the function, as a lazy value.
//! @include example/lazy/functor.cpp
//!
//! 2. `Applicative`\n
//! A normal value can be lifted into a lazy value by using `lift<lazy_tag>`.
//! A lazy function can be lazily applied to a lazy value by using `ap`.
//!
//! 3. `Monad`\n
//! The `lazy` monad allows combining lazy computations into larger
//! lazy computations. Note that the `|` operator can be used in place
//! of the `chain` function.
//! @include example/lazy/monad.cpp
//!
//! 4. `Comonad`\n
//! The `lazy` comonad allows evaluating a lazy computation to get its
//! result and lazily applying functions taking lazy inputs to lazy
//! values. This [blog post][1] goes into more details about lazy
//! evaluation and comonads.
//! @include example/lazy/comonad.cpp
//!
//!
//! @note
//! `hana::lazy` only models a few concepts because providing more
//! functionality would require evaluating the lazy values in most cases.
//! Since this raises some issues such as side effects and memoization,
//! the interface is kept minimal.
//!
//!
//! [1]: http://ldionne.com/2015/03/16/laziness-as-a-comonad
#ifdef BOOST_HANA_DOXYGEN_INVOKED
template <typename implementation_defined>
struct lazy {
//! Equivalent to `hana::chain`.
template <typename ...T, typename F>
friend constexpr auto operator|(lazy<T...>, F);
};
#else
// We do not _actually_ define the lazy<...> type. Per the documentation,
// users can't rely on it being anything, and so they should never use
// it explicitly. The implementation in <boost/hana/lazy.hpp> is much
// simpler if we use different types for lazy calls and lazy values.
#endif
//! Tag representing `hana::lazy`.
//! @relates hana::lazy
struct lazy_tag { };
//! Lifts a normal value to a lazy one.
//! @relates hana::lazy
//!
//! `make<lazy_tag>` can be used to lift a normal value or a function call
//! into a lazy expression. Precisely, `make<lazy_tag>(x)` is a lazy value
//! equal to `x`, and `make<lazy_tag>(f)(x1, ..., xN)` is a lazy function
//! call that is equal to `f(x1, ..., xN)` when it is `eval`uated.
//!
//! @note
//! It is interesting to note that `make<lazy_tag>(f)(x1, ..., xN)` is
//! equivalent to
//! @code
//! ap(make<lazy_tag>(f), lift<lazy_tag>(x1), ..., lift<lazy_tag>(xN))
//! @endcode
//! which in turn is equivalent to `make<lazy_tag>(f(x1, ..., xN))`, except
//! for the fact that the inner call to `f` is evaluated lazily.
//!
//!
//! Example
//! -------
//! @include example/lazy/make.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
template <>
constexpr auto make<lazy_tag> = [](auto&& x) {
return lazy<implementation_defined>{forwarded(x)};
};
#endif
//! Alias to `make<lazy_tag>`; provided for convenience.
//! @relates hana::lazy
//!
//! Example
//! -------
//! @include example/lazy/make.cpp
constexpr auto make_lazy = make<lazy_tag>;
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_LAZY_HPP
@@ -0,0 +1,50 @@
/*!
@file
Forward declares `boost::hana::length`.
@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)
*/
#ifndef BOOST_HANA_FWD_LENGTH_HPP
#define BOOST_HANA_FWD_LENGTH_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Return the number of elements in a foldable structure.
//! @ingroup group-Foldable
//!
//! Given a `Foldable` `xs`, `length(xs)` must return an object of an
//! unsigned integral type, or an `IntegralConstant` holding such an
//! object, which represents the number of elements in the structure.
//!
//! @note
//! Since only compile-time `Foldable`s are supported in the library
//! right now, `length` must always return an `IntegralConstant`.
//!
//!
//! Example
//! -------
//! @include example/length.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto length = [](auto const& xs) {
return tag-dispatched;
};
#else
template <typename T, typename = void>
struct length_impl : length_impl<T, when<true>> { };
struct length_t {
template <typename Xs>
constexpr auto operator()(Xs const& xs) const;
};
constexpr length_t length{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_LENGTH_HPP
@@ -0,0 +1,53 @@
/*!
@file
Forward declares `boost::hana::less`.
@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)
*/
#ifndef BOOST_HANA_FWD_LESS_HPP
#define BOOST_HANA_FWD_LESS_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
#include <boost/hana/detail/nested_than_fwd.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Returns a `Logical` representing whether `x` is less than `y`.
//! @ingroup group-Orderable
//!
//!
//! Signature
//! ---------
//! Given a Logical `Bool` and two Orderables `A` and `B` with a common
//! embedding, the signature is
//! @f$ \mathrm{less} : A \times B \to Bool @f$.
//!
//! @param x, y
//! Two objects to compare.
//!
//!
//! Example
//! -------
//! @include example/less.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto less = [](auto&& x, auto&& y) {
return tag-dispatched;
};
#else
template <typename T, typename U, typename = void>
struct less_impl : less_impl<T, U, when<true>> { };
struct less_t : detail::nested_than<less_t> {
template <typename X, typename Y>
constexpr auto operator()(X&& x, Y&& y) const;
};
constexpr less_t less{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_LESS_HPP
@@ -0,0 +1,54 @@
/*!
@file
Forward declares `boost::hana::less_equal`.
@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)
*/
#ifndef BOOST_HANA_FWD_LESS_EQUAL_HPP
#define BOOST_HANA_FWD_LESS_EQUAL_HPP
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
#include <boost/hana/detail/nested_than_fwd.hpp>
BOOST_HANA_NAMESPACE_BEGIN
//! Returns a `Logical` representing whether `x` is less than or
//! equal to `y`.
//! @ingroup group-Orderable
//!
//!
//! Signature
//! ---------
//! Given a Logical `Bool` and two Orderables `A` and `B` with a common
//! embedding, the signature is
//! @f$ \mathrm{less\_equal} : A \times B \to Bool @f$.
//!
//! @param x, y
//! Two objects to compare.
//!
//!
//! Example
//! -------
//! @include example/less_equal.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
constexpr auto less_equal = [](auto&& x, auto&& y) {
return tag-dispatched;
};
#else
template <typename T, typename U, typename = void>
struct less_equal_impl : less_equal_impl<T, U, when<true>> { };
struct less_equal_t : detail::nested_than<less_equal_t> {
template <typename X, typename Y>
constexpr auto operator()(X&& x, Y&& y) const;
};
constexpr less_equal_t less_equal{};
#endif
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_FWD_LESS_EQUAL_HPP

Some files were not shown because too many files have changed in this diff Show More