Skip to content

Commit

Permalink
establishes the basis for numeric ranges
Browse files Browse the repository at this point in the history
This commit does all the necessary groundwork to get a basis for
accumulate to be a ranges citizen. We achieve this by introducing:

* the concept Magma
* the concept IndirectMagma
* a new set of arithmetic operation function objects
* an accumulate niebloid
* accumulate tests

== Notes

std::multiplies and std::divides have been renamed to `product` and
`quotient`, respectively.

Each arithmetic operation has its own detail concept that effectively
check things like "has plus". Care was taken to ensure that the
requirements for each operator were as complete as possible. For
example, since subtraction is the inverse of addition, anything that
supports ranges::ext::minus should also support ranges::ext::plus.

== Known issues

It's believed that each of the detail concepts are ill-specified with
respect to references. For example, most expressions are checked à la
`{ std::forward<T>(t) + std::forward<T>(t) } -> Common<T>;`, but the
type of `t` is `__uncvref(t)` due to difficulties getting some
expressions to compile. Reviewers should note this problem when
evaluating the design of the detail concepts.
  • Loading branch information
Christopher Di Bella committed Jun 22, 2019
1 parent 2c74dfb commit ac25864
Show file tree
Hide file tree
Showing 14 changed files with 593 additions and 0 deletions.
18 changes: 18 additions & 0 deletions include/stl2/detail/algorithm/results.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,24 @@
#include <stl2/detail/concepts/core.hpp>

STL2_OPEN_NAMESPACE {
template<class I, class T>
struct __in_value_result {
STL2_NO_UNIQUE_ADDRESS I in;
STL2_NO_UNIQUE_ADDRESS T value;

// Extension: the dangling story actually works.
template<class I2, class T2>
requires ConvertibleTo<const I&, I2> && ConvertibleTo<const T&, T2>
operator __in_value_result<I2, T2>() const& {
return {in, value};
}
template<class I2, class T2>
requires ConvertibleTo<I, I2> && ConvertibleTo<T, T2>
operator __in_value_result<I2, T2>() && {
return {std::move(in), std::move(value)};
}
};

template<class I, class O>
struct __in_out_result {
STL2_NO_UNIQUE_ADDRESS I in;
Expand Down
14 changes: 14 additions & 0 deletions include/stl2/detail/concepts/callable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <stl2/type_traits.hpp>
#include <stl2/detail/concepts/compare.hpp>
#include <stl2/detail/concepts/function.hpp>
#include <stl2/detail/concepts/numeric/magma.hpp>
#include <stl2/detail/concepts/object.hpp>
#include <stl2/detail/functional/invoke.hpp>
#include <stl2/detail/iterator/concepts.hpp>
Expand Down Expand Up @@ -185,6 +186,19 @@ STL2_OPEN_NAMESPACE {
template<class I, class R = less, class P = identity>
META_CONCEPT Sortable = Permutable<I> &&
IndirectStrictWeakOrder<R, projected<I, P>>;

namespace ext {
template<class BOp, class I1, class I2, class O>
META_CONCEPT IndirectMagma =
Readable<I1> &&
Readable<I2> &&
Writable<O, indirect_result_t<BOp&, I1, I2>> &&
Magma<BOp&, iter_value_t<I1>&, iter_value_t<I2>&> &&
Magma<BOp&, iter_value_t<I1>&, iter_reference_t<I2>&> &&
Magma<BOp&, iter_reference_t<I1>, iter_value_t<I2>&> &&
Magma<BOp&, iter_reference_t<I1>, iter_reference_t<I2>> &&
Magma<BOp&, iter_common_reference_t<I1>, iter_common_reference_t<I2>>;
} // namespace ext
} STL2_CLOSE_NAMESPACE

#endif
39 changes: 39 additions & 0 deletions include/stl2/detail/concepts/numeric/magma.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// cmcstl2 - A concept-enabled C++ standard library
//
// Copyright Casey Carter
// Copyright Christopher Di Bella
//
// Use, modification and distribution is subject to the
// Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// Project home: https://github.com/caseycarter/cmcstl2
//
#ifndef STL2_DETAIL_CONCEPTS_NUMERIC_MAGMA_HPP
#define STL2_DETAIL_CONCEPTS_NUMERIC_MAGMA_HPP

#include <stl2/detail/concepts/core.hpp>
#include <stl2/detail/concepts/callable.hpp>
#include <stl2/detail/fwd.hpp>

STL2_OPEN_NAMESPACE {
namespace ext {
template<class BOp, class T, class U>
META_CONCEPT Magma =
Common<T, U> &&
RegularInvocable<BOp, T, T> &&
RegularInvocable<BOp, U, U> &&
RegularInvocable<BOp, T, U> &&
RegularInvocable<BOp, U, T> &&
Common<invoke_result_t<BOp&, T, U>, T> &&
Common<invoke_result_t<BOp&, T, U>, U> &&
Same<invoke_result_t<BOp&, T, U>, invoke_result_t<BOp&, U, T>>;
// axiom: Let `bop` be an object of type `BOp`, `t` be an object of type `T`, and `u` be an
// object of type `U`. The expression `invoke(bop, t, u)` must return a result that is
// representable by `common_type_t<T, U>`.
// axiom: The result of `invoke(bop, t, u)` needn't be the same as `invoke(bop, u, t)`.
} // namespace ext
} STL2_CLOSE_NAMESPACE

#endif // STL2_DETAIL_CONCEPTS_NUMERIC_MAGMA_HPP
22 changes: 22 additions & 0 deletions include/stl2/detail/functional/arithmetic.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// cmcstl2 - A concept-enabled C++ standard library
//
// Copyright Casey Carter
// Copyright Christopher Di Bella
//
// Use, modification and distribution is subject to the
// Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// Project home: https://github.com/caseycarter/cmcstl2
//
#ifndef STL2_DETAIL_FUNCTIONAL_ARITHMETIC_HPP
#define STL2_DETAIL_FUNCTIONAL_ARITHMETIC_HPP

#include <stl2/detail/functional/arithmetic/plus.hpp>
#include <stl2/detail/functional/arithmetic/minus.hpp>
#include <stl2/detail/functional/arithmetic/product.hpp>
#include <stl2/detail/functional/arithmetic/quotient.hpp>
#include <stl2/detail/functional/arithmetic/modulus.hpp>

#endif // STL2_DETAIL_FUNCTIONAL_ARITHMETIC_HPP
56 changes: 56 additions & 0 deletions include/stl2/detail/functional/arithmetic/minus.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// cmcstl2 - A concept-enabled C++ standard library
//
// Copyright Casey Carter
// Copyright Christopher Di Bella
//
// Use, modification and distribution is subject to the
// Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// Project home: https://github.com/caseycarter/cmcstl2
//
#ifndef STL2_DETAIL_FUNCTIONAL_ARITHMETIC_MINUS_HPP
#define STL2_DETAIL_FUNCTIONAL_ARITHMETIC_MINUS_HPP

#include <stl2/detail/concepts/core.hpp>
#include <stl2/detail/functional/arithmetic/plus.hpp>
#include <stl2/detail/fwd.hpp>
#include <type_traits>
#include <utility>

STL2_OPEN_NAMESPACE {
namespace ext {
template<class T, class U>
META_CONCEPT __differenceable_with = __summable_with<T, U> &&
requires(__uncvref<T> t, __uncvref<U> u) {
{ +std::forward<T>(t) } -> Same<T>;
{ -std::forward<T>(t) } -> Same<T>;
{ +std::forward<U>(u) } -> Same<U>;
{ -std::forward<U>(u) } -> Same<U>;
{ t -= std::forward<U>(u) } -> CommonReference<T&>;
{ u -= std::forward<T>(t) } -> CommonReference<U&>;
{ std::forward<T>(t) - std::forward<T>(t) } -> Common<T>;
{ std::forward<U>(u) - std::forward<U>(u) } -> Common<U>;
{ std::forward<T>(t) - std::forward<U>(u) } -> Common<T>;
{ std::forward<T>(t) - std::forward<U>(u) } -> Common<U>;
requires Same<decltype(std::forward<T>(t) - std::forward<U>(u)),
decltype(std::forward<U>(t) - std::forward<T>(u))>;
};
// axiom: `t - t` is equivalent to `T{}`
// axiom: `t - (-t)` is equivalent to `t + t`
// axiom: `-t - t` is equivalent to `-(t + t)`
// axiom: `t + t - t` is equivalent to `t`

struct minus {
template<class T, __differenceable_with<T> U>
constexpr decltype(auto) operator()(T&& t, U&& u) const {
return std::forward<T>(t) - std::forward<U>(u);
}

using is_transparent = std::true_type;
};
} // namespace ext
} STL2_CLOSE_NAMESPACE

#endif // STL2_DETAIL_FUNCTIONAL_ARITHMETIC_MINUS_HPP
49 changes: 49 additions & 0 deletions include/stl2/detail/functional/arithmetic/modulus.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// cmcstl2 - A concept-enabled C++ standard library
//
// Copyright Casey Carter
// Copyright Christopher Di Bella
//
// Use, modification and distribution is subject to the
// Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// Project home: https://github.com/caseycarter/cmcstl2
//
#ifndef STL2_DETAIL_FUNCTIONAL_ARITHMETIC_MODULUS_HPP
#define STL2_DETAIL_FUNCTIONAL_ARITHMETIC_MODULUS_HPP

#include <stl2/detail/concepts/core.hpp>
#include <stl2/detail/functional/arithmetic/plus.hpp>
#include <stl2/detail/functional/arithmetic/quotient.hpp>
#include <stl2/detail/fwd.hpp>
#include <type_traits>
#include <utility>

STL2_OPEN_NAMESPACE {
namespace ext {
template<class T, class U>
META_CONCEPT __modulo_with = __summable_with<T, U> && __divisible_with<T, U> &&
requires(__uncvref<T> t, __uncvref<U> u) {
{ t %= std::forward<U>(u) } -> CommonReference<T&>;
{ u %= std::forward<T>(t) } -> CommonReference<U&>;
{ std::forward<T>(t) % std::forward<T>(t) } -> Common<T>;
{ std::forward<U>(u) % std::forward<U>(u) } -> Common<U>;
{ std::forward<T>(t) % std::forward<U>(u) } -> Common<T>;
{ std::forward<T>(t) % std::forward<U>(u) } -> Common<U>;
requires Same<decltype(std::forward<T>(t) / std::forward<U>(u)),
decltype(std::forward<U>(t) / std::forward<T>(u))>;
};
// Let n, q, r, t all be distinct objects of type T.
// axiom: `t % q == q * r + n`

struct modulus {
template<class T, __modulo_with<T> U>
constexpr decltype(auto) operator()(T&& t, U&& u) const {
return std::forward<T>(t) % std::forward<U>(u);
}
};
} // namespace ext
} STL2_CLOSE_NAMESPACE

#endif // STL2_DETAIL_FUNCTIONAL_ARITHMETIC_MODULUS_HPP
50 changes: 50 additions & 0 deletions include/stl2/detail/functional/arithmetic/plus.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// cmcstl2 - A concept-enabled C++ standard library
//
// Copyright Casey Carter
// Copyright Christopher Di Bella
//
// Use, modification and distribution is subject to the
// Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// Project home: https://github.com/caseycarter/cmcstl2
//
#ifndef STL2_DETAIL_FUNCTIONAL_ARITHMETIC_PLUS_HPP
#define STL2_DETAIL_FUNCTIONAL_ARITHMETIC_PLUS_HPP

#include <stl2/detail/concepts/core.hpp>
#include <stl2/detail/fwd.hpp>
#include <type_traits>
#include <utility>

STL2_OPEN_NAMESPACE {
namespace ext {
template<class T, class U>
META_CONCEPT __summable_with =
DefaultConstructible<remove_reference_t<T>> &&
DefaultConstructible<remove_reference_t<U>> &&
CommonReference<T, U> &&
requires(__uncvref<T> t, __uncvref<U> u) {
{ t += std::forward<U>(u) } -> CommonReference<T&>;
{ u += std::forward<T>(t) } -> CommonReference<U&>;
{ std::forward<T>(t) + std::forward<T>(t) } -> Common<T>;
{ std::forward<U>(u) + std::forward<U>(u) } -> Common<U>;
{ std::forward<T>(t) + std::forward<U>(u) } -> Common<T>;
{ std::forward<T>(t) + std::forward<U>(u) } -> Common<U>;
requires Same<decltype(std::forward<T>(t) + std::forward<U>(u)),
decltype(std::forward<U>(t) + std::forward<T>(u))>;
};

struct plus {
template<class T, __summable_with<T> U>
constexpr decltype(auto) operator()(T&& t, U&& u) const {
return std::forward<T>(t) + std::forward<U>(u);
}

using is_transparent = std::true_type;
};
} // namespace ext
} STL2_CLOSE_NAMESPACE

#endif // STL2_DETAIL_FUNCTIONAL_ARITHMETIC_PLUS_HPP
55 changes: 55 additions & 0 deletions include/stl2/detail/functional/arithmetic/product.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// cmcstl2 - A concept-enabled C++ standard library
//
// Copyright Casey Carter
// Copyright Christopher Di Bella
//
// Use, modification and distribution is subject to the
// Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// Project home: https://github.com/caseycarter/cmcstl2
//
#ifndef STL2_DETAIL_FUNCTIONAL_ARITHMETIC_PRODUCT_HPP
#define STL2_DETAIL_FUNCTIONAL_ARITHMETIC_PRODUCT_HPP

#include <stl2/detail/concepts/core.hpp>
#include <stl2/detail/fwd.hpp>
#include <type_traits>
#include <utility>

STL2_OPEN_NAMESPACE {
namespace ext {
template<class T, class U>
META_CONCEPT __multiplicable_with =
DefaultConstructible<remove_reference_t<T>> &&
DefaultConstructible<remove_reference_t<U>> &&
Constructible<remove_reference_t<T>, int> && // specifically T{0} and T{1}
Constructible<remove_reference_t<T>, int> && // specifically U{0} and U{1}
CommonReference<T, U> &&
requires(__uncvref<T> t, __uncvref<U> u) {
{ t *= std::forward<U>(u) } -> CommonReference<T&>;
{ u *= std::forward<T>(t) } -> CommonReference<U&>;
{ std::forward<T>(t) * std::forward<T>(t) } -> Common<T>;
{ std::forward<U>(u) * std::forward<U>(u) } -> Common<U>;
{ std::forward<T>(t) * std::forward<U>(u) } -> Common<T>;
{ std::forward<T>(t) * std::forward<U>(u) } -> Common<U>;
requires Same<decltype(std::forward<T>(t) * std::forward<U>(u)),
decltype(std::forward<U>(t) * std::forward<T>(u))>;
};
// axiom: T{0} is equivalent to T{}, and similarly for U
// axiom: `t * T{1} == t` and `T{1} * t == t`, and similarly for U

// std::multiplies renamed to std::ranges::product
struct product {
template<class T, __multiplicable_with<T> U>
constexpr decltype(auto) operator()(T&& t, U&& u) const {
return std::forward<T>(t) * std::forward<U>(u);
}

using is_transparent = std::true_type;
};
} // namespace ext
} STL2_CLOSE_NAMESPACE

#endif // STL2_DETAIL_FUNCTIONAL_ARITHMETIC_PRODUCT_HPP
49 changes: 49 additions & 0 deletions include/stl2/detail/functional/arithmetic/quotient.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// cmcstl2 - A concept-enabled C++ standard library
//
// Copyright Casey Carter
// Copyright Christopher Di Bella
//
// Use, modification and distribution is subject to the
// Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// Project home: https://github.com/caseycarter/cmcstl2
//
#ifndef STL2_DETAIL_FUNCTIONAL_ARITHMETIC_QUOTIENT_HPP
#define STL2_DETAIL_FUNCTIONAL_ARITHMETIC_QUOTIENT_HPP

#include <stl2/detail/concepts/core.hpp>
#include <stl2/detail/functional/arithmetic/product.hpp>
#include <stl2/detail/fwd.hpp>
#include <type_traits>
#include <utility>

STL2_OPEN_NAMESPACE {
namespace ext {
template<class T, class U>
META_CONCEPT __divisible_with = __multiplicable_with<T, U> &&
requires(__uncvref<T> t, __uncvref<U> u) {
{ t /= std::forward<U>(u) } -> CommonReference<T&>;
{ u /= std::forward<T>(t) } -> CommonReference<U&>;
{ std::forward<T>(t) / std::forward<T>(t) } -> Common<T>;
{ std::forward<U>(u) / std::forward<U>(u) } -> Common<U>;
{ std::forward<T>(t) / std::forward<U>(u) } -> Common<T>;
{ std::forward<T>(t) / std::forward<U>(u) } -> Common<U>;
requires Same<decltype(std::forward<T>(t) / std::forward<U>(u)),
decltype(std::forward<U>(t) / std::forward<T>(u))>;
};
// axiom: `t / t` is equivalent to `T{1}`
// axiom: `(t * t) / t` is equivalent to `t`

// std::divides renamed to std::ranges::quotient
struct quotient {
template<class T, __divisible_with<T> U>
constexpr decltype(auto) operator()(T&& t, U&& u) const {
return std::forward<T>(t) / std::forward<U>(u);
}
};
} // namespace ext
} STL2_CLOSE_NAMESPACE

#endif // STL2_DETAIL_FUNCTIONAL_ARITHMETIC_QUOTIENT_HPP
Loading

0 comments on commit ac25864

Please sign in to comment.