based

Opinionated utility library
git clone git://git.dimitrijedobrota.com/based.git
Log | Files | Refs | README | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING |

commit2562c3261807b3e74ffbae8ea7228e5a5d98359d
parent81c55b179c512909f1c786dbabe411898fb0a93e
authorDimitrije Dobrota <mail@dimitrijedobrota.com>
dateFri, 28 Mar 2025 13:33:12 +0100

Homogenous (in turn unary) funcs have type domain * Improve readiblity and consistency

Diffstat:
Mexample/type_traits.cpp|++---
Minclude/based/functional.hpp|++++++++++++++++++++--------------------
Minclude/based/type_traits.hpp|++++++++++++++++++++++++++++--------------------

3 files changed, 50 insertions(+), 43 deletions(-)


diff --git a/example/type_traits.cpp b/example/type_traits.cpp

@@ -57,7 +57,7 @@ int main()

using id = identity<double>;
using ii = identity<irregular>;
static_assert(std::same_as<based::domaind>, std::tuple<double>>);
static_assert(std::same_as<based::domain_t<id>, double>);
static_assert(std::same_as<based::codomain_t<id>, double>);
static_assert(based::arity_v<id> == 1);

@@ -75,8 +75,7 @@ int main()

using aid = add<irregular, double>;
using adi = add<double, irregular>;
static_assert(std::same_as<based::domaind>,
std::tuple<const double&, const double&>>);
static_assert(std::same_as<based::domain_t<ad>, double>);
static_assert(std::same_as<based::codomain_t<ad>, double>);
static_assert(based::arity_v<ad> == 2);

diff --git a/include/based/functional.hpp b/include/based/functional.hpp

@@ -8,7 +8,7 @@ namespace based

{
template<Transformation F>
distance_t<F> distance(codomain_t<F> x, codomain_t<F> y, F f)
distance_t<F> distance(domain_t<F> x, domain_t<F> y, F f)
{
// Precondition: y is reachable from x under f
using N = distance_t<F>;

@@ -22,7 +22,7 @@ distance_t<F> distance(codomain_t<F> x, codomain_t<F> y, F f)

}
template<Transformation F>
codomain_t<F> convergant_point(codomain_t<F> x0, codomain_t<F> x1, F f)
domain_t<F> convergant_point(domain_t<F> x0, domain_t<F> x1, F f)
{
// Precondition: (exists n from distance_t<F>) n>= 0 ^ f^n(x0) = f^n(x1)
while (x0 != x1) {

@@ -34,7 +34,7 @@ codomain_t<F> convergant_point(codomain_t<F> x0, codomain_t<F> x1, F f)

template<Transformation F, UnaryPredicate P>
requires SameAs<domain_t<F>, domain_t<P>>
codomain_t<F> collision_point(const codomain_t<F>& x, F f, P p)
domain_t<F> collision_point(const domain_t<F>& x, F f, P p)
{
// Precondition p(x) <=> f(x) is defined
if (!p(x)) {

@@ -60,7 +60,7 @@ codomain_t<F> collision_point(const codomain_t<F>& x, F f, P p)

template<Transformation F, UnaryPredicate P>
requires SameAs<domain_t<F>, domain_t<P>>
bool terminating(const codomain_t<F>& x, F f, P p)
bool terminating(const domain_t<F>& x, F f, P p)
{
// Precondition: p(x) <=> F(x) is defined
return !p(collision_point(x, f, p));

@@ -68,7 +68,7 @@ bool terminating(const codomain_t<F>& x, F f, P p)

template<Transformation F, UnaryPredicate P>
requires SameAs<domain_t<F>, domain_t<P>>
bool circular(const codomain_t<F>& x, F f, P p)
bool circular(const domain_t<F>& x, F f, P p)
{
// Precondition: p(x) <=> F(x) is defined
const auto y = collision_point(x, f, p);

@@ -77,7 +77,7 @@ bool circular(const codomain_t<F>& x, F f, P p)

template<Transformation F, UnaryPredicate P>
requires SameAs<domain_t<F>, domain_t<P>>
bool connection_point(const codomain_t<F>& x, F f, P p)
bool connection_point(const domain_t<F>& x, F f, P p)
{
// Precondition: p(x) <=> F(x) is defined
const auto y = collision_point(x, f, p);

@@ -90,7 +90,7 @@ bool connection_point(const codomain_t<F>& x, F f, P p)

template<Transformation F, UnaryPredicate P>
requires SameAs<domain_t<F>, domain_t<P>>
std::tuple<distance_t<F>, distance_t<F>, domain_t<F>> orbit_structure(
const codomain_t<F>& x, F f, P p)
const domain_t<F>& x, F f, P p)
{
// Precondition: p(x) <=> F(x) is defined
const auto y = connection_point(x, f, p);

@@ -100,7 +100,7 @@ std::tuple<distance_t<F>, distance_t<F>, domain_t<F>> orbit_structure(

}
template<Transformation F>
codomain_t<F> collision_point_nonterminating_orbit(const codomain_t<F>& x, F f)
domain_t<F> collision_point_nonterminating_orbit(const domain_t<F>& x, F f)
{
auto slow = x;
auto fast = f(x);

@@ -114,13 +114,13 @@ codomain_t<F> collision_point_nonterminating_orbit(const codomain_t<F>& x, F f)

}
template<Transformation F>
bool circular_nonterminating_orbit(const codomain_t<F>& x, F f)
bool circular_nonterminating_orbit(const domain_t<F>& x, F f)
{
return x == f(collision_point_nonterminating_orbit(x, f));
}
template<Transformation F>
codomain_t<F> connection_point_nonterminating_orbit(const codomain_t<F>& x, F f)
domain_t<F> connection_point_nonterminating_orbit(const domain_t<F>& x, F f)
{
return convergant_point(x, f(collision_point_nonterminating_orbit(x, f)), f);
}

@@ -134,7 +134,7 @@ orbit_structure_nonterminating_orbit(const domain_t<F>& x, F f)

}
template<Transformation F, Integer N>
codomain_t<F> power_unary(codomain_t<F> x, N n, F f)
domain_t<F> power_unary(domain_t<F> x, N n, F f)
{
while (!zero(n)) {
n = predecesor(n);

@@ -144,24 +144,24 @@ codomain_t<F> power_unary(codomain_t<F> x, N n, F f)

}
template<Integer I, BinaryOperation Op>
codomain_t<Op> power_left_associated(codomain_t<Op> a, I n, Op op)
domain_t<Op> power_left_associated(domain_t<Op> a, I n, Op op)
{
assert(n > 0);
return one(n) ? a : op(power_left_associated(a, predecesor(n), op), a);
}
template<Integer I, BinaryOperation Op>
codomain_t<Op> power_right_associated(codomain_t<Op> a, I n, Op op)
domain_t<Op> power_right_associated(domain_t<Op> a, I n, Op op)
{
assert(n > 0);
return one(n) ? a : op(a, power_right_associated(a, predecesor(n), op));
}
template<Integer I, AssociativeBinaryOperation Op>
codomain_t<Op> power_accumulate_positive(codomain_t<Op> r,
codomain_t<Op> a,
I n,
Op op)
domain_t<Op> power_accumulate_positive(domain_t<Op> r,
domain_t<Op> a,
I n,
Op op)
{
assert(n > 0);
while (true) {

@@ -177,14 +177,14 @@ codomain_t<Op> power_accumulate_positive(codomain_t<Op> r,

}
template<Integer I, AssociativeBinaryOperation Op>
codomain_t<Op> power_accumulate(codomain_t<Op> r, codomain_t<Op> a, I n, Op op)
domain_t<Op> power_accumulate(domain_t<Op> r, domain_t<Op> a, I n, Op op)
{
assert(n >= 0);
return zero(n) ? r : power_accumulate_positive(r, a, n, op);
}
template<Integer I, AssociativeBinaryOperation Op>
codomain_t<Op> power(codomain_t<Op> a, I n, Op op)
domain_t<Op> power(domain_t<Op> a, I n, Op op)
{
assert(n > 0);
while (even(n)) {

@@ -197,7 +197,7 @@ codomain_t<Op> power(codomain_t<Op> a, I n, Op op)

}
template<Integer I, AssociativeBinaryOperation Op>
codomain_t<Op> power(codomain_t<Op> a, I n, Op op, codomain_t<Op> id)
domain_t<Op> power(domain_t<Op> a, I n, Op op, domain_t<Op> id)
{
assert(n >= 0);
return !zero(n) ? power(a, n, op) : id;

diff --git a/include/based/type_traits.hpp b/include/based/type_traits.hpp

@@ -64,9 +64,6 @@ struct is_regular_tuple<Tuple<Types...>> : std::true_type

template<class T>
inline constexpr bool is_regular_tuple_v = is_regular_tuple<T>::value;
template<class T>
concept RegularTuple = is_regular_tuple_v<T>;
template<class>
struct is_input_tuple : std::false_type
{

@@ -81,9 +78,6 @@ struct is_input_tuple<Tuple<Types...>> : std::true_type

template<class T>
inline constexpr bool is_input_tuple_v = is_input_tuple<T>::value;
template<class T>
concept InputTuple = is_input_tuple_v<T>;
template<class>
struct is_homogenous_tuple : std::false_type
{

@@ -98,9 +92,6 @@ struct is_homogenous_tuple<Tuple<Head, Tail...>> : std::true_type

template<class T>
inline constexpr bool is_homogenous_tuple_v = is_homogenous_tuple<T>::value;
template<class T>
concept HomogenousTuple = is_input_tuple_v<T>;
template<typename>
struct signature;

@@ -196,20 +187,38 @@ struct codomain<P>

using type = signature<std::decay_t<P>>::ret_type;
};
} // namespace detail
template<typename P>
using domain_t = detail::domain<P>::type;
using domain_t = domain<P>::type;
template<typename P>
using codomain_t = typename detail::codomain<P>::type;
using codomain_t = codomain<P>::type;
template<class T>
concept RegularDomain = is_regular_tuple_v<domain_t<T>>;
template<class T>
concept InputDomain = is_input_tuple_v<domain_t<T>>;
template<class T>
concept HomogenousDomain = is_input_tuple_v<domain_t<T>>;
} // namespace detail
template<typename P>
inline constexpr auto arity_v = std::tuple_size<domain_t<P>>::value;
inline constexpr auto arity_v = std::tuple_size<detail::domain_t<P>>::value;
template<typename P, std::size_t Idx>
requires requires { Idx < arity_v<P>; }
using domain_elem_t = std::tuple_element_t<Idx, domain_t<P>>;
using domain_elem_t =
std::decay_t<std::tuple_element_t<Idx, detail::domain_t<P>>>;
template<typename P>
using domain_t =
std::conditional_t<detail::is_homogenous_tuple_v<detail::domain_t<P>>,
domain_elem_t<P, 0>,
detail::domain_t<P>>;
template<typename P>
using codomain_t = detail::codomain_t<P>;
template<typename P>
using distance_t = std::uint64_t;

@@ -221,14 +230,14 @@ concept Procedure = detail::FreeProcedure<P> || detail::MemberProcedure<P>

template<typename P>
concept RegularProcedure = requires {
requires(Procedure<P>);
requires(detail::RegularTuple<domain_t<P>>);
requires(detail::RegularDomain<P>);
requires(Regular<codomain_t<P>>);
};
template<typename P>
concept FunctionalProcedure = requires {
requires(RegularProcedure<P>);
requires(detail::InputTuple<domain_t<P>>);
requires(detail::InputDomain<P>);
};
template<typename P>

@@ -241,7 +250,7 @@ template<typename P>

concept HomogeneousFunction = requires {
requires(FunctionalProcedure<P>);
requires(arity_v<P> > 0);
requires(detail::HomogenousTuple<domain_t<P>>);
requires(detail::HomogenousDomain<P>);
};
template<typename P>

@@ -283,8 +292,7 @@ concept BinaryOperation = requires {

template<typename P>
concept AssociativeBinaryOperation = requires {
requires(Operation<P>);
requires(arity_v<P> == 2);
requires(BinaryOperation<P>);
// requires(P is associative)
};