concepts: split and remove C++20 re-implementations
This commit is contained in:
parent
e96ee81c03
commit
6ed70a4839
@ -294,6 +294,7 @@ list (
|
||||
colour.hpp
|
||||
concepts.hpp
|
||||
concepts/clock.hpp
|
||||
concepts/string.hpp
|
||||
container.hpp
|
||||
coord.hpp
|
||||
coord/fwd.hpp
|
||||
|
14
cast.hpp
14
cast.hpp
@ -9,7 +9,7 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "concepts.hpp"
|
||||
#include "concepts/traits.hpp"
|
||||
#include "debug/assert.hpp"
|
||||
#include "platform.hpp"
|
||||
|
||||
@ -74,8 +74,8 @@ namespace cruft::cast {
|
||||
/// Identity casts are allowed so as to simplify the use of this routine
|
||||
/// in template code.
|
||||
template <
|
||||
concepts::arithmetic NarrowT,
|
||||
concepts::arithmetic WideT
|
||||
concepts::traits::arithmetic NarrowT,
|
||||
concepts::traits::arithmetic WideT
|
||||
>
|
||||
requires
|
||||
(std::is_signed_v<NarrowT> == std::is_signed_v<WideT>) &&
|
||||
@ -150,8 +150,8 @@ namespace cruft::cast {
|
||||
///
|
||||
/// Runtime checks will be compiled out if NDEBUG is defined.
|
||||
template <
|
||||
concepts::pointer DstT,
|
||||
concepts::pointer SrcT
|
||||
concepts::traits::pointer DstT,
|
||||
concepts::traits::pointer SrcT
|
||||
>
|
||||
DstT
|
||||
alignment (SrcT src)
|
||||
@ -172,7 +172,7 @@ namespace cruft::cast {
|
||||
/// the converted value. Note: this is only a debug-time check and is
|
||||
/// compiled out in optimised builds.
|
||||
template <
|
||||
concepts::pointer T,
|
||||
concepts::traits::pointer T,
|
||||
typename V
|
||||
>
|
||||
T
|
||||
@ -188,7 +188,7 @@ namespace cruft::cast {
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
template <
|
||||
concepts::reference T,
|
||||
concepts::traits::reference T,
|
||||
typename V
|
||||
>
|
||||
T
|
||||
|
@ -38,7 +38,7 @@ namespace cruft::cmdopt2 {
|
||||
bind (ValueT &ref)
|
||||
{
|
||||
CHECK (!acceptor1);
|
||||
if constexpr (std::is_same_v<ValueT, std::string>) {
|
||||
if constexpr (std::is_same_v<ValueT, std::string> or std::is_same_v<ValueT, char const*>) {
|
||||
acceptor1 = [&ref] (std::string_view str) { ref = str; };
|
||||
} else {
|
||||
acceptor1 = [&ref] (std::string_view str) { ref = parse::from_string<ValueT> (str); };
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "./parser.hpp"
|
||||
|
||||
#include "./arg.hpp"
|
||||
|
||||
using cruft::cmdopt2::parser;
|
||||
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "./arg.hpp"
|
||||
#include "./fwd.hpp"
|
||||
|
||||
#include <iosfwd>
|
||||
#include <vector>
|
||||
|
280
concepts.hpp
280
concepts.hpp
@ -8,268 +8,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
#include "concepts/named.hpp"
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// A minimal implementation of the standard concept library for use with
|
||||
/// compilers that lack it.
|
||||
///
|
||||
/// Portions of this code are adapted from the standard and as such do not
|
||||
/// fall under the top copyright notice.
|
||||
///
|
||||
/// clang#xxx: Remove me when clang includes an implementation of these.
|
||||
namespace cruft::concepts {
|
||||
template <typename T>
|
||||
concept floating_point = std::is_floating_point_v<T>;
|
||||
|
||||
template <typename T>
|
||||
concept integral = std::is_integral_v<T>;
|
||||
|
||||
template <typename T>
|
||||
concept signed_integral = integral<T> && std::is_signed_v<T>;
|
||||
|
||||
template <typename T>
|
||||
concept unsigned_integral = integral<T> && std::is_unsigned_v<T>;
|
||||
|
||||
template <typename T>
|
||||
concept destructible = std::is_nothrow_destructible_v<T>;
|
||||
|
||||
template <class T, typename ...ArgsT>
|
||||
concept constructible_from = destructible<T> && std::is_constructible_v<T, ArgsT...>;
|
||||
|
||||
template <class T>
|
||||
concept default_constructible = constructible_from<T>;
|
||||
|
||||
template <class T>
|
||||
concept copy_constructible = std::is_copy_constructible_v<T>;
|
||||
|
||||
template <class T>
|
||||
concept move_constructible = std::is_move_constructible_v<T>;
|
||||
|
||||
|
||||
template <typename A, typename B>
|
||||
concept same_as = std::is_same_v<A, B> and std::is_same_v<B, A>;
|
||||
|
||||
|
||||
template <typename From, typename To>
|
||||
concept convertible_to =
|
||||
std::is_convertible_v<From, To> &&
|
||||
requires (From (&f)())
|
||||
{
|
||||
static_cast<To> (f());
|
||||
};
|
||||
|
||||
|
||||
template <
|
||||
typename LHS,
|
||||
typename RHS
|
||||
>
|
||||
concept assignable_from =
|
||||
std::is_lvalue_reference_v<LHS> &&
|
||||
// clang#xxx: common_reference_t is too annoying to implement as
|
||||
// a temporary fix for this temporary fix. Reintroduce this when
|
||||
// clang knows about common_reference_t.
|
||||
// std::common_reference_with<
|
||||
// std::remove_reference_t<LHS> const&,
|
||||
// std::remove_reference_t<RHS> const&
|
||||
// > &&
|
||||
requires(LHS lhs, RHS&& rhs)
|
||||
{
|
||||
{ lhs = std::forward<RHS>(rhs) } -> same_as<LHS>;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept swappable = requires (T &&a, T &&b) { std::swap (a, b); };
|
||||
|
||||
|
||||
template < class T >
|
||||
concept movable =
|
||||
std::is_object_v<T> &&
|
||||
move_constructible<T> &&
|
||||
assignable_from<T&, T> &&
|
||||
swappable<T>;
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept boolean =
|
||||
movable<std::remove_cvref_t<T>> &&
|
||||
requires (
|
||||
std::remove_reference_t<T> const& b1,
|
||||
std::remove_reference_t<T> const& b2,
|
||||
bool const a
|
||||
)
|
||||
{
|
||||
{ b1 } -> convertible_to<bool>;
|
||||
{ !b1 } -> convertible_to<bool>;
|
||||
|
||||
{ b1 && b2 } -> same_as<bool>;
|
||||
{ b1 && a } -> same_as<bool>;
|
||||
{ a && b2 } -> same_as<bool>;
|
||||
{ b1 || b2 } -> same_as<bool>;
|
||||
{ b1 || a } -> same_as<bool>;
|
||||
{ a || b2 } -> same_as<bool>;
|
||||
|
||||
{ b1 == b2 } -> convertible_to<bool>;
|
||||
{ b1 == a } -> convertible_to<bool>;
|
||||
{ a == b2 } -> convertible_to<bool>;
|
||||
{ b1 != b2 } -> convertible_to<bool>;
|
||||
{ b1 != a } -> convertible_to<bool>;
|
||||
{ a != b2 } -> convertible_to<bool>;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept equality_comparable =
|
||||
requires (
|
||||
std::remove_reference_t<T> const &a,
|
||||
std::remove_reference_t<T> const &b
|
||||
)
|
||||
{
|
||||
{ a == b } -> boolean;
|
||||
{ a != b } -> boolean;
|
||||
{ b == a } -> boolean;
|
||||
{ b != a } -> boolean;
|
||||
};
|
||||
|
||||
|
||||
template <typename FunctionT, typename ...ArgsT>
|
||||
concept invocable =
|
||||
requires (FunctionT &&function, ArgsT &&...args)
|
||||
{
|
||||
std::invoke (
|
||||
std::forward<FunctionT> (function),
|
||||
std::forward<ArgsT> (args)...
|
||||
);
|
||||
};
|
||||
|
||||
template <typename FunctionT, typename ...ArgsT>
|
||||
concept regular_invocable = invocable<FunctionT, ArgsT...>;
|
||||
|
||||
template <typename FunctionT, typename ...ArgsT>
|
||||
concept predicate =
|
||||
regular_invocable<FunctionT, ArgsT...> &&
|
||||
boolean<std::invoke_result_t<FunctionT, ArgsT...>>;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// C++ named requirements
|
||||
namespace cruft::concepts {
|
||||
/// Corresponds to the "Container" named requirement.
|
||||
template <class T>
|
||||
concept container =
|
||||
default_constructible<T> &&
|
||||
copy_constructible<T> &&
|
||||
move_constructible<T> &&
|
||||
destructible<T> &&
|
||||
equality_comparable<T> &&
|
||||
requires (T a, T b)
|
||||
{
|
||||
typename T::value_type;
|
||||
typename T::reference;
|
||||
typename T::const_reference;
|
||||
typename T::iterator;
|
||||
typename T::const_iterator;
|
||||
typename T::difference_type;
|
||||
typename T::size_type;
|
||||
|
||||
{ a = b } -> same_as<T&>;
|
||||
{ a = std::move (b) } -> same_as<T&>;
|
||||
|
||||
{ a.begin () } -> same_as<typename T::iterator>;
|
||||
{ a.end () } -> same_as<typename T::iterator>;
|
||||
{ a.cbegin () } -> same_as<typename T::const_iterator>;
|
||||
{ a.cend () } -> same_as<typename T::const_iterator>;
|
||||
|
||||
{ a.swap (b) } -> same_as<void>;
|
||||
{ std::swap (a, b) } -> same_as<void>;
|
||||
|
||||
{ a.size () } -> same_as<typename T::size_type>;
|
||||
{ a.max_size () } -> same_as<typename T::size_type>;
|
||||
{ a.empty () } -> boolean;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept move_assignable =
|
||||
requires (T a, T b)
|
||||
{
|
||||
{ a = std::move (b) } -> same_as<T&>;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept copy_assignable =
|
||||
move_assignable<T> &&
|
||||
requires (T a, T b)
|
||||
{
|
||||
{ a = b } -> same_as<T&>;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept legacy_iterator =
|
||||
copy_constructible<T> &&
|
||||
copy_assignable<T> &&
|
||||
destructible<T> &&
|
||||
swappable<T> &&
|
||||
requires (T t)
|
||||
{
|
||||
typename std::iterator_traits<T>::value_type;
|
||||
typename std::iterator_traits<T>::difference_type;
|
||||
typename std::iterator_traits<T>::reference;
|
||||
typename std::iterator_traits<T>::pointer;
|
||||
typename std::iterator_traits<T>::iterator_category;
|
||||
|
||||
{ *t };
|
||||
{ ++t } -> same_as<T&>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept legacy_input_iterator =
|
||||
legacy_iterator<T> &&
|
||||
equality_comparable<T> &&
|
||||
requires (T a, T b)
|
||||
{
|
||||
typename std::iterator_traits<T>::reference;
|
||||
typename std::iterator_traits<T>::value_type;
|
||||
{ a != b } -> boolean;
|
||||
|
||||
{ ++a } -> same_as<T&>;
|
||||
{ a++ };
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Trivial wrappers around traits
|
||||
namespace cruft::concepts {
|
||||
template <typename T>
|
||||
concept arithmetic = std::is_arithmetic_v<T>;
|
||||
|
||||
template <typename T>
|
||||
concept scalar = std::is_scalar_v<T>;
|
||||
|
||||
template <typename T>
|
||||
concept enumeration = std::is_enum_v<T>;
|
||||
|
||||
template <typename T>
|
||||
concept pointer = std::is_pointer_v<T>;
|
||||
|
||||
template <typename T>
|
||||
concept reference = std::is_reference_v<T>;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Some handy non-standard concepts
|
||||
#include <concepts>
|
||||
#include <tuple>
|
||||
|
||||
|
||||
namespace cruft::concepts {
|
||||
/// Tests if the type has all typedefs required for use with
|
||||
/// std::iterator_traits.
|
||||
@ -301,10 +45,10 @@ namespace cruft::concepts {
|
||||
template <typename T>
|
||||
concept numeric = requires (T t)
|
||||
{
|
||||
{ t * t } -> convertible_to<T>;
|
||||
{ t / t } -> convertible_to<T>;
|
||||
{ t - t } -> convertible_to<T>;
|
||||
{ t + t } -> convertible_to<T>;
|
||||
{ t * t } -> std::convertible_to<T>;
|
||||
{ t / t } -> std::convertible_to<T>;
|
||||
{ t - t } -> std::convertible_to<T>;
|
||||
{ t + t } -> std::convertible_to<T>;
|
||||
};
|
||||
|
||||
|
||||
@ -312,10 +56,10 @@ namespace cruft::concepts {
|
||||
template <typename T>
|
||||
concept iterable = requires (T t)
|
||||
{
|
||||
{ std::begin (t) } -> legacy_iterator;
|
||||
{ std::end (t) } -> legacy_iterator;
|
||||
{ std::cbegin (t) } -> legacy_iterator;
|
||||
{ std::cend (t) } -> legacy_iterator;
|
||||
{ std::begin (t) } -> named::legacy_iterator;
|
||||
{ std::end (t) } -> named::legacy_iterator;
|
||||
{ std::cbegin (t) } -> named::legacy_iterator;
|
||||
{ std::cend (t) } -> named::legacy_iterator;
|
||||
};
|
||||
|
||||
|
||||
@ -326,7 +70,7 @@ namespace cruft::concepts {
|
||||
// We should be checking this, but it fails for zero length tuples and
|
||||
// it's kind of a low priority right now.
|
||||
// { std::tuple_element<0,T> {} };
|
||||
{ std::tuple_size<T>::value } -> convertible_to<std::size_t>;
|
||||
{ std::tuple_size<T>::value } -> std::convertible_to<std::size_t>;
|
||||
{ std::tuple_cat (a, b) };
|
||||
};
|
||||
}
|
94
concepts/named.hpp
Normal file
94
concepts/named.hpp
Normal file
@ -0,0 +1,94 @@
|
||||
#pragma once
|
||||
|
||||
#include <iterator>
|
||||
#include <concepts>
|
||||
#include <utility>
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// C++ named requirements
|
||||
namespace cruft::concepts::named {
|
||||
/// Corresponds to the "Container" named requirement.
|
||||
template <class T>
|
||||
concept container =
|
||||
std::default_initializable<T> and
|
||||
std::copy_constructible<T> and
|
||||
std::move_constructible<T> and
|
||||
std::destructible<T> and
|
||||
std::equality_comparable<T> and
|
||||
requires (T a, T b)
|
||||
{
|
||||
typename T::value_type;
|
||||
typename T::reference;
|
||||
typename T::const_reference;
|
||||
typename T::iterator;
|
||||
typename T::const_iterator;
|
||||
typename T::difference_type;
|
||||
typename T::size_type;
|
||||
|
||||
{ a = b } -> std::same_as<T&>;
|
||||
{ a = std::move (b) } -> std::same_as<T&>;
|
||||
|
||||
{ a.begin () } -> std::same_as<typename T::iterator>;
|
||||
{ a.end () } -> std::same_as<typename T::iterator>;
|
||||
{ a.cbegin () } -> std::same_as<typename T::const_iterator>;
|
||||
{ a.cend () } -> std::same_as<typename T::const_iterator>;
|
||||
|
||||
{ a.swap (b) } -> std::same_as<void>;
|
||||
{ std::swap (a, b) } -> std::same_as<void>;
|
||||
|
||||
{ a.size () } -> std::same_as<typename T::size_type>;
|
||||
{ a.max_size () } -> std::same_as<typename T::size_type>;
|
||||
{ a.empty () } -> std::same_as<bool>;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept move_assignable =
|
||||
requires (T a, T b)
|
||||
{
|
||||
{ a = std::move (b) } -> std::same_as<T&>;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept copy_assignable =
|
||||
move_assignable<T> &&
|
||||
requires (T a, T b)
|
||||
{
|
||||
{ a = b } -> std::same_as<T&>;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept legacy_iterator =
|
||||
std::copy_constructible<T> &&
|
||||
copy_assignable<T> &&
|
||||
std::destructible<T> &&
|
||||
std::swappable<T> &&
|
||||
requires (T t)
|
||||
{
|
||||
typename std::iterator_traits<T>::value_type;
|
||||
typename std::iterator_traits<T>::difference_type;
|
||||
typename std::iterator_traits<T>::reference;
|
||||
typename std::iterator_traits<T>::pointer;
|
||||
typename std::iterator_traits<T>::iterator_category;
|
||||
|
||||
{ *t };
|
||||
{ ++t } -> std::same_as<T&>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept legacy_input_iterator =
|
||||
legacy_iterator<T> &&
|
||||
std::equality_comparable<T> &&
|
||||
requires (T a, T b)
|
||||
{
|
||||
typename std::iterator_traits<T>::reference;
|
||||
typename std::iterator_traits<T>::value_type;
|
||||
{ a != b } -> std::same_as<bool>;
|
||||
|
||||
{ ++a } -> std::same_as<T&>;
|
||||
{ a++ };
|
||||
};
|
||||
}
|
23
concepts/string.hpp
Normal file
23
concepts/string.hpp
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright 2022, Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <concepts>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace cruft::concepts {
|
||||
/// A type that behaves like a string. ie, a sequence of characters
|
||||
template <typename T>
|
||||
concept stringy =
|
||||
std::same_as<T, std::string> or
|
||||
std::same_as<T, std::string_view> or
|
||||
std::same_as<T, char const*> or
|
||||
std::same_as<T, char *>;
|
||||
}
|
23
concepts/traits.hpp
Normal file
23
concepts/traits.hpp
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Trivial wrappers around traits
|
||||
namespace cruft::concepts::traits {
|
||||
template <typename T>
|
||||
concept arithmetic = std::is_arithmetic_v<T>;
|
||||
|
||||
template <typename T>
|
||||
concept scalar = std::is_scalar_v<T>;
|
||||
|
||||
template <typename T>
|
||||
concept enumeration = std::is_enum_v<T>;
|
||||
|
||||
template <typename T>
|
||||
concept pointer = std::is_pointer_v<T>;
|
||||
|
||||
template <typename T>
|
||||
concept reference = std::is_reference_v<T>;
|
||||
}
|
87
maths.hpp
87
maths.hpp
@ -12,7 +12,10 @@
|
||||
// it triggers a circular dependency; debug -> format -> maths -> debug
|
||||
// instead, just use cassert
|
||||
|
||||
#include "concepts/traits.hpp"
|
||||
#include "concepts/named.hpp"
|
||||
#include "concepts.hpp"
|
||||
|
||||
#include "types/traits.hpp"
|
||||
#include "float.hpp"
|
||||
|
||||
@ -36,7 +39,7 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
namespace cruft {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <concepts::arithmetic T>
|
||||
template <concepts::traits::arithmetic T>
|
||||
constexpr T
|
||||
abs [[gnu::const]] (T t)
|
||||
{
|
||||
@ -151,7 +154,7 @@ namespace cruft {
|
||||
|
||||
template <
|
||||
typename BaseT,
|
||||
concepts::integral ExponentT
|
||||
std::integral ExponentT
|
||||
>
|
||||
constexpr BaseT
|
||||
pow [[gnu::const]] (BaseT base, ExponentT exponent)
|
||||
@ -174,7 +177,7 @@ namespace cruft {
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
template <concepts::integral T>
|
||||
template <std::integral T>
|
||||
constexpr bool
|
||||
is_pow2 [[gnu::const]] (T value)
|
||||
{
|
||||
@ -188,7 +191,7 @@ namespace cruft {
|
||||
///
|
||||
/// `val` must be strictly greater than zero, otherwise the results are
|
||||
/// undefined.
|
||||
template <concepts::integral T>
|
||||
template <std::integral T>
|
||||
constexpr T
|
||||
log2 (T val)
|
||||
{
|
||||
@ -219,7 +222,7 @@ namespace cruft {
|
||||
/// with runtime performance given the simplistic construction.
|
||||
///
|
||||
/// It's useful for sizing temporary arrays.
|
||||
template <concepts::integral T>
|
||||
template <std::integral T>
|
||||
consteval T
|
||||
ilog (T val, T base)
|
||||
{
|
||||
@ -232,7 +235,7 @@ namespace cruft {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// round T up to the nearest multiple of U
|
||||
template <concepts::integral T, concepts::integral U>
|
||||
template <std::integral T, std::integral U>
|
||||
inline
|
||||
std::common_type_t<T, U>
|
||||
round_up (T value, U size)
|
||||
@ -247,7 +250,7 @@ namespace cruft {
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// round T up to the nearest power-of-2
|
||||
template <concepts::integral T>
|
||||
template <std::integral T>
|
||||
constexpr auto
|
||||
round_pow2 (T value)
|
||||
{
|
||||
@ -265,8 +268,8 @@ namespace cruft {
|
||||
///----------------------------------------------------------------------------
|
||||
/// round T up to the nearest multiple of U and return the quotient.
|
||||
template <
|
||||
concepts::integral T,
|
||||
concepts::integral U
|
||||
std::integral T,
|
||||
std::integral U
|
||||
>
|
||||
constexpr auto
|
||||
divup (T const a, U const b)
|
||||
@ -277,7 +280,7 @@ namespace cruft {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Properties
|
||||
template <concepts::integral T>
|
||||
template <std::integral T>
|
||||
constexpr bool
|
||||
is_integer (T)
|
||||
{
|
||||
@ -285,7 +288,7 @@ namespace cruft {
|
||||
}
|
||||
|
||||
|
||||
template <concepts::floating_point T>
|
||||
template <std::floating_point T>
|
||||
constexpr bool
|
||||
is_integer (T t)
|
||||
{
|
||||
@ -295,7 +298,7 @@ namespace cruft {
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
template <concepts::integral NumericT>
|
||||
template <std::integral NumericT>
|
||||
constexpr auto
|
||||
digits10 (NumericT v) noexcept
|
||||
{
|
||||
@ -325,7 +328,7 @@ namespace cruft {
|
||||
}
|
||||
|
||||
|
||||
template <concepts::integral ValueT, concepts::integral BaseT>
|
||||
template <std::integral ValueT, std::integral BaseT>
|
||||
constexpr int
|
||||
digits (ValueT value, BaseT base) noexcept
|
||||
{
|
||||
@ -344,7 +347,7 @@ namespace cruft {
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// return positive or negative unit value corresponding to the input.
|
||||
template <concepts::signed_integral T>
|
||||
template <std::signed_integral T>
|
||||
constexpr T
|
||||
sign (T t)
|
||||
{
|
||||
@ -355,7 +358,7 @@ namespace cruft {
|
||||
/// return positive or negative unit value corresponding to the input.
|
||||
/// guaranteed to give correct results for signed zeroes, use another
|
||||
/// method if extreme speed is important.
|
||||
template <concepts::floating_point T>
|
||||
template <std::floating_point T>
|
||||
constexpr T
|
||||
sign (T t)
|
||||
{
|
||||
@ -386,7 +389,7 @@ namespace cruft {
|
||||
// Modulus/etc
|
||||
|
||||
// namespaced wrapper for `man 3 fmod`
|
||||
template <concepts::floating_point T>
|
||||
template <std::floating_point T>
|
||||
constexpr T
|
||||
mod (T x, T y)
|
||||
{
|
||||
@ -394,7 +397,7 @@ namespace cruft {
|
||||
}
|
||||
|
||||
|
||||
template <concepts::integral T>
|
||||
template <std::integral T>
|
||||
constexpr T
|
||||
mod (T x, T y)
|
||||
{
|
||||
@ -402,7 +405,7 @@ namespace cruft {
|
||||
}
|
||||
|
||||
|
||||
template <concepts::floating_point ValueT>
|
||||
template <std::floating_point ValueT>
|
||||
ValueT
|
||||
frac (ValueT val)
|
||||
{
|
||||
@ -515,8 +518,8 @@ namespace cruft {
|
||||
|
||||
template <typename InputT>
|
||||
requires
|
||||
concepts::legacy_input_iterator<InputT> &&
|
||||
concepts::floating_point<typename std::iterator_traits<InputT>::value_type>
|
||||
concepts::named::legacy_input_iterator<InputT> &&
|
||||
std::floating_point<typename std::iterator_traits<InputT>::value_type>
|
||||
typename std::iterator_traits<InputT>::value_type
|
||||
sum (InputT first, InputT last)
|
||||
{
|
||||
@ -545,8 +548,8 @@ namespace cruft {
|
||||
//-------------------------------------------------------------------------
|
||||
template <typename InputT>
|
||||
requires
|
||||
concepts::legacy_input_iterator<InputT> &&
|
||||
concepts::integral<typename std::iterator_traits<InputT>::value_type>
|
||||
concepts::named::legacy_input_iterator<InputT> &&
|
||||
std::integral<typename std::iterator_traits<InputT>::value_type>
|
||||
typename std::iterator_traits<InputT>::value_type
|
||||
sum (InputT first, InputT last)
|
||||
{
|
||||
@ -575,7 +578,7 @@ namespace cruft {
|
||||
/// parameter packs.
|
||||
///
|
||||
/// eg, `max (sizeof (T)...)` will otherwise fail with a single type.
|
||||
template <concepts::integral ValueT>
|
||||
template <std::integral ValueT>
|
||||
constexpr decltype(auto)
|
||||
max (ValueT &&val)
|
||||
{
|
||||
@ -598,7 +601,7 @@ namespace cruft {
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
template <concepts::container ContainerT>
|
||||
template <concepts::named::container ContainerT>
|
||||
typename ContainerT::value_type const&
|
||||
max (ContainerT const &vals)
|
||||
{
|
||||
@ -606,13 +609,13 @@ namespace cruft {
|
||||
}
|
||||
|
||||
|
||||
template <concepts::container ValueT>
|
||||
template <concepts::named::container ValueT>
|
||||
typename ValueT::value_type &
|
||||
max (ValueT &&) = delete;
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
template <concepts::container ContainerT>
|
||||
template <concepts::named::container ContainerT>
|
||||
typename ContainerT::value_type const&
|
||||
min (ContainerT const &vals)
|
||||
{
|
||||
@ -620,7 +623,7 @@ namespace cruft {
|
||||
}
|
||||
|
||||
|
||||
template <concepts::container ContainerT>
|
||||
template <concepts::named::container ContainerT>
|
||||
typename ContainerT::value_type&
|
||||
min (ContainerT &&) = delete;
|
||||
|
||||
@ -643,9 +646,9 @@ namespace cruft {
|
||||
|
||||
// min/max clamping
|
||||
template <
|
||||
concepts::scalar T,
|
||||
concepts::scalar U,
|
||||
concepts::scalar V
|
||||
concepts::traits::scalar T,
|
||||
concepts::traits::scalar U,
|
||||
concepts::traits::scalar V
|
||||
>
|
||||
constexpr std::common_type_t<T,U,V>
|
||||
clamp (T const val, U const lo, V const hi)
|
||||
@ -697,8 +700,8 @@ namespace cruft {
|
||||
|
||||
// uint -> float
|
||||
template <
|
||||
concepts::unsigned_integral T,
|
||||
concepts::floating_point U
|
||||
std::unsigned_integral T,
|
||||
std::floating_point U
|
||||
>
|
||||
constexpr U
|
||||
renormalise (T t)
|
||||
@ -710,8 +713,8 @@ namespace cruft {
|
||||
//-------------------------------------------------------------------------
|
||||
// float -> uint
|
||||
template <
|
||||
concepts::floating_point T,
|
||||
concepts::unsigned_integral U
|
||||
std::floating_point T,
|
||||
std::unsigned_integral U
|
||||
>
|
||||
constexpr U
|
||||
renormalise (T t)
|
||||
@ -745,8 +748,8 @@ namespace cruft {
|
||||
// ambiguous overloads
|
||||
template <typename T, typename U>
|
||||
requires
|
||||
concepts::floating_point<T> &&
|
||||
concepts::floating_point<U> &&
|
||||
std::floating_point<T> &&
|
||||
std::floating_point<U> &&
|
||||
(!std::is_same_v<T, U>)
|
||||
constexpr U
|
||||
renormalise (T t)
|
||||
@ -759,8 +762,8 @@ namespace cruft {
|
||||
// hi_uint -> lo_uint
|
||||
template <typename T, typename U>
|
||||
requires
|
||||
concepts::unsigned_integral<T> &&
|
||||
concepts::unsigned_integral<U> &&
|
||||
std::unsigned_integral<T> &&
|
||||
std::unsigned_integral<U> &&
|
||||
(sizeof (T) > sizeof (U))
|
||||
constexpr U
|
||||
renormalise (T t)
|
||||
@ -781,8 +784,8 @@ namespace cruft {
|
||||
typename DstT
|
||||
>
|
||||
requires
|
||||
concepts::unsigned_integral<SrcT> &&
|
||||
concepts::unsigned_integral<DstT> &&
|
||||
std::unsigned_integral<SrcT> &&
|
||||
std::unsigned_integral<DstT> &&
|
||||
(sizeof (SrcT) < sizeof (DstT))
|
||||
constexpr DstT
|
||||
renormalise (SrcT src)
|
||||
@ -834,7 +837,7 @@ namespace cruft {
|
||||
// anything-to-sint
|
||||
template <typename T, typename U>
|
||||
requires
|
||||
concepts::signed_integral<U> &&
|
||||
std::signed_integral<U> &&
|
||||
(!std::is_same<T,U>::value)
|
||||
constexpr U
|
||||
renormalise (T t)
|
||||
@ -851,7 +854,7 @@ namespace cruft {
|
||||
// sint-to-anything
|
||||
template <typename T, typename U>
|
||||
requires
|
||||
concepts::signed_integral<T> &&
|
||||
std::signed_integral<T> &&
|
||||
(!std::is_same<T,U>::value)
|
||||
constexpr U
|
||||
renormalise (T sint)
|
||||
|
@ -1,12 +1,12 @@
|
||||
#include <cruft/util/tap.hpp>
|
||||
#include <cruft/util/concepts.hpp>
|
||||
#include <cruft/util/concepts/named.hpp>
|
||||
|
||||
int main ()
|
||||
{
|
||||
cruft::TAP::logger tap;
|
||||
|
||||
tap.expect (cruft::concepts::container<std::vector<int>>, "vector is a container");
|
||||
tap.expect (!cruft::concepts::container<int>, "int is not a container");
|
||||
tap.expect (cruft::concepts::named::container<std::vector<int>>, "vector is a container");
|
||||
tap.expect (!cruft::concepts::named::container<int>, "int is not a container");
|
||||
|
||||
tap.expect (cruft::concepts::tuple<std::tuple<>>, "tuple<> is a tuple");
|
||||
tap.expect (cruft::concepts::tuple<std::tuple<int>>, "tuple<int> is a tuple");
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "../maths.hpp"
|
||||
#include "../tuple/type.hpp"
|
||||
|
||||
#include <concepts>
|
||||
#include <tuple>
|
||||
|
||||
|
||||
@ -54,7 +55,7 @@ namespace cruft {
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
template <typename InitialT>
|
||||
requires (cruft::concepts::same_as<std::remove_cvref_t<InitialT>, ValueT> || ...)
|
||||
requires (std::same_as<std::remove_cvref_t<InitialT>, ValueT> || ...)
|
||||
tagged (InitialT &&initial)
|
||||
{
|
||||
set<InitialT> (std::forward<InitialT> (initial));
|
||||
|
Loading…
Reference in New Issue
Block a user