stabilize build system: depends, installer, boost/bdb fixes, cross targets groundwork
This commit is contained in:
@@ -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
Reference in New Issue
Block a user