concepts: split and remove C++20 re-implementations
This commit is contained in:
parent
e96ee81c03
commit
6ed70a4839
@ -294,6 +294,7 @@ list (
|
|||||||
colour.hpp
|
colour.hpp
|
||||||
concepts.hpp
|
concepts.hpp
|
||||||
concepts/clock.hpp
|
concepts/clock.hpp
|
||||||
|
concepts/string.hpp
|
||||||
container.hpp
|
container.hpp
|
||||||
coord.hpp
|
coord.hpp
|
||||||
coord/fwd.hpp
|
coord/fwd.hpp
|
||||||
|
14
cast.hpp
14
cast.hpp
@ -9,7 +9,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
#include "concepts.hpp"
|
#include "concepts/traits.hpp"
|
||||||
#include "debug/assert.hpp"
|
#include "debug/assert.hpp"
|
||||||
#include "platform.hpp"
|
#include "platform.hpp"
|
||||||
|
|
||||||
@ -74,8 +74,8 @@ namespace cruft::cast {
|
|||||||
/// Identity casts are allowed so as to simplify the use of this routine
|
/// Identity casts are allowed so as to simplify the use of this routine
|
||||||
/// in template code.
|
/// in template code.
|
||||||
template <
|
template <
|
||||||
concepts::arithmetic NarrowT,
|
concepts::traits::arithmetic NarrowT,
|
||||||
concepts::arithmetic WideT
|
concepts::traits::arithmetic WideT
|
||||||
>
|
>
|
||||||
requires
|
requires
|
||||||
(std::is_signed_v<NarrowT> == std::is_signed_v<WideT>) &&
|
(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.
|
/// Runtime checks will be compiled out if NDEBUG is defined.
|
||||||
template <
|
template <
|
||||||
concepts::pointer DstT,
|
concepts::traits::pointer DstT,
|
||||||
concepts::pointer SrcT
|
concepts::traits::pointer SrcT
|
||||||
>
|
>
|
||||||
DstT
|
DstT
|
||||||
alignment (SrcT src)
|
alignment (SrcT src)
|
||||||
@ -172,7 +172,7 @@ namespace cruft::cast {
|
|||||||
/// the converted value. Note: this is only a debug-time check and is
|
/// the converted value. Note: this is only a debug-time check and is
|
||||||
/// compiled out in optimised builds.
|
/// compiled out in optimised builds.
|
||||||
template <
|
template <
|
||||||
concepts::pointer T,
|
concepts::traits::pointer T,
|
||||||
typename V
|
typename V
|
||||||
>
|
>
|
||||||
T
|
T
|
||||||
@ -188,7 +188,7 @@ namespace cruft::cast {
|
|||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
template <
|
template <
|
||||||
concepts::reference T,
|
concepts::traits::reference T,
|
||||||
typename V
|
typename V
|
||||||
>
|
>
|
||||||
T
|
T
|
||||||
|
@ -38,7 +38,7 @@ namespace cruft::cmdopt2 {
|
|||||||
bind (ValueT &ref)
|
bind (ValueT &ref)
|
||||||
{
|
{
|
||||||
CHECK (!acceptor1);
|
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; };
|
acceptor1 = [&ref] (std::string_view str) { ref = str; };
|
||||||
} else {
|
} else {
|
||||||
acceptor1 = [&ref] (std::string_view str) { ref = parse::from_string<ValueT> (str); };
|
acceptor1 = [&ref] (std::string_view str) { ref = parse::from_string<ValueT> (str); };
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#include "./parser.hpp"
|
#include "./parser.hpp"
|
||||||
|
|
||||||
|
#include "./arg.hpp"
|
||||||
|
|
||||||
using cruft::cmdopt2::parser;
|
using cruft::cmdopt2::parser;
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "./arg.hpp"
|
#include "./fwd.hpp"
|
||||||
|
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
280
concepts.hpp
280
concepts.hpp
@ -8,268 +8,12 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <type_traits>
|
#include "concepts/named.hpp"
|
||||||
#include <iterator>
|
|
||||||
#include <utility>
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
|
#include <concepts>
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// 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 <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
|
|
||||||
namespace cruft::concepts {
|
namespace cruft::concepts {
|
||||||
/// Tests if the type has all typedefs required for use with
|
/// Tests if the type has all typedefs required for use with
|
||||||
/// std::iterator_traits.
|
/// std::iterator_traits.
|
||||||
@ -301,10 +45,10 @@ namespace cruft::concepts {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
concept numeric = requires (T t)
|
concept numeric = requires (T t)
|
||||||
{
|
{
|
||||||
{ t * t } -> convertible_to<T>;
|
{ t * t } -> std::convertible_to<T>;
|
||||||
{ t / t } -> convertible_to<T>;
|
{ t / t } -> std::convertible_to<T>;
|
||||||
{ t - t } -> convertible_to<T>;
|
{ t - t } -> std::convertible_to<T>;
|
||||||
{ t + t } -> convertible_to<T>;
|
{ t + t } -> std::convertible_to<T>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -312,10 +56,10 @@ namespace cruft::concepts {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
concept iterable = requires (T t)
|
concept iterable = requires (T t)
|
||||||
{
|
{
|
||||||
{ std::begin (t) } -> legacy_iterator;
|
{ std::begin (t) } -> named::legacy_iterator;
|
||||||
{ std::end (t) } -> legacy_iterator;
|
{ std::end (t) } -> named::legacy_iterator;
|
||||||
{ std::cbegin (t) } -> legacy_iterator;
|
{ std::cbegin (t) } -> named::legacy_iterator;
|
||||||
{ std::cend (t) } -> 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
|
// We should be checking this, but it fails for zero length tuples and
|
||||||
// it's kind of a low priority right now.
|
// it's kind of a low priority right now.
|
||||||
// { std::tuple_element<0,T> {} };
|
// { 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) };
|
{ 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
|
// it triggers a circular dependency; debug -> format -> maths -> debug
|
||||||
// instead, just use cassert
|
// instead, just use cassert
|
||||||
|
|
||||||
|
#include "concepts/traits.hpp"
|
||||||
|
#include "concepts/named.hpp"
|
||||||
#include "concepts.hpp"
|
#include "concepts.hpp"
|
||||||
|
|
||||||
#include "types/traits.hpp"
|
#include "types/traits.hpp"
|
||||||
#include "float.hpp"
|
#include "float.hpp"
|
||||||
|
|
||||||
@ -36,7 +39,7 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
namespace cruft {
|
namespace cruft {
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
template <concepts::arithmetic T>
|
template <concepts::traits::arithmetic T>
|
||||||
constexpr T
|
constexpr T
|
||||||
abs [[gnu::const]] (T t)
|
abs [[gnu::const]] (T t)
|
||||||
{
|
{
|
||||||
@ -151,7 +154,7 @@ namespace cruft {
|
|||||||
|
|
||||||
template <
|
template <
|
||||||
typename BaseT,
|
typename BaseT,
|
||||||
concepts::integral ExponentT
|
std::integral ExponentT
|
||||||
>
|
>
|
||||||
constexpr BaseT
|
constexpr BaseT
|
||||||
pow [[gnu::const]] (BaseT base, ExponentT exponent)
|
pow [[gnu::const]] (BaseT base, ExponentT exponent)
|
||||||
@ -174,7 +177,7 @@ namespace cruft {
|
|||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
template <concepts::integral T>
|
template <std::integral T>
|
||||||
constexpr bool
|
constexpr bool
|
||||||
is_pow2 [[gnu::const]] (T value)
|
is_pow2 [[gnu::const]] (T value)
|
||||||
{
|
{
|
||||||
@ -188,7 +191,7 @@ namespace cruft {
|
|||||||
///
|
///
|
||||||
/// `val` must be strictly greater than zero, otherwise the results are
|
/// `val` must be strictly greater than zero, otherwise the results are
|
||||||
/// undefined.
|
/// undefined.
|
||||||
template <concepts::integral T>
|
template <std::integral T>
|
||||||
constexpr T
|
constexpr T
|
||||||
log2 (T val)
|
log2 (T val)
|
||||||
{
|
{
|
||||||
@ -219,7 +222,7 @@ namespace cruft {
|
|||||||
/// with runtime performance given the simplistic construction.
|
/// with runtime performance given the simplistic construction.
|
||||||
///
|
///
|
||||||
/// It's useful for sizing temporary arrays.
|
/// It's useful for sizing temporary arrays.
|
||||||
template <concepts::integral T>
|
template <std::integral T>
|
||||||
consteval T
|
consteval T
|
||||||
ilog (T val, T base)
|
ilog (T val, T base)
|
||||||
{
|
{
|
||||||
@ -232,7 +235,7 @@ namespace cruft {
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
/// round T up to the nearest multiple of U
|
/// round T up to the nearest multiple of U
|
||||||
template <concepts::integral T, concepts::integral U>
|
template <std::integral T, std::integral U>
|
||||||
inline
|
inline
|
||||||
std::common_type_t<T, U>
|
std::common_type_t<T, U>
|
||||||
round_up (T value, U size)
|
round_up (T value, U size)
|
||||||
@ -247,7 +250,7 @@ namespace cruft {
|
|||||||
|
|
||||||
///----------------------------------------------------------------------------
|
///----------------------------------------------------------------------------
|
||||||
/// round T up to the nearest power-of-2
|
/// round T up to the nearest power-of-2
|
||||||
template <concepts::integral T>
|
template <std::integral T>
|
||||||
constexpr auto
|
constexpr auto
|
||||||
round_pow2 (T value)
|
round_pow2 (T value)
|
||||||
{
|
{
|
||||||
@ -265,8 +268,8 @@ namespace cruft {
|
|||||||
///----------------------------------------------------------------------------
|
///----------------------------------------------------------------------------
|
||||||
/// round T up to the nearest multiple of U and return the quotient.
|
/// round T up to the nearest multiple of U and return the quotient.
|
||||||
template <
|
template <
|
||||||
concepts::integral T,
|
std::integral T,
|
||||||
concepts::integral U
|
std::integral U
|
||||||
>
|
>
|
||||||
constexpr auto
|
constexpr auto
|
||||||
divup (T const a, U const b)
|
divup (T const a, U const b)
|
||||||
@ -277,7 +280,7 @@ namespace cruft {
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Properties
|
// Properties
|
||||||
template <concepts::integral T>
|
template <std::integral T>
|
||||||
constexpr bool
|
constexpr bool
|
||||||
is_integer (T)
|
is_integer (T)
|
||||||
{
|
{
|
||||||
@ -285,7 +288,7 @@ namespace cruft {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <concepts::floating_point T>
|
template <std::floating_point T>
|
||||||
constexpr bool
|
constexpr bool
|
||||||
is_integer (T t)
|
is_integer (T t)
|
||||||
{
|
{
|
||||||
@ -295,7 +298,7 @@ namespace cruft {
|
|||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
template <concepts::integral NumericT>
|
template <std::integral NumericT>
|
||||||
constexpr auto
|
constexpr auto
|
||||||
digits10 (NumericT v) noexcept
|
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
|
constexpr int
|
||||||
digits (ValueT value, BaseT base) noexcept
|
digits (ValueT value, BaseT base) noexcept
|
||||||
{
|
{
|
||||||
@ -344,7 +347,7 @@ namespace cruft {
|
|||||||
|
|
||||||
///----------------------------------------------------------------------------
|
///----------------------------------------------------------------------------
|
||||||
/// return positive or negative unit value corresponding to the input.
|
/// return positive or negative unit value corresponding to the input.
|
||||||
template <concepts::signed_integral T>
|
template <std::signed_integral T>
|
||||||
constexpr T
|
constexpr T
|
||||||
sign (T t)
|
sign (T t)
|
||||||
{
|
{
|
||||||
@ -355,7 +358,7 @@ namespace cruft {
|
|||||||
/// return positive or negative unit value corresponding to the input.
|
/// return positive or negative unit value corresponding to the input.
|
||||||
/// guaranteed to give correct results for signed zeroes, use another
|
/// guaranteed to give correct results for signed zeroes, use another
|
||||||
/// method if extreme speed is important.
|
/// method if extreme speed is important.
|
||||||
template <concepts::floating_point T>
|
template <std::floating_point T>
|
||||||
constexpr T
|
constexpr T
|
||||||
sign (T t)
|
sign (T t)
|
||||||
{
|
{
|
||||||
@ -386,7 +389,7 @@ namespace cruft {
|
|||||||
// Modulus/etc
|
// Modulus/etc
|
||||||
|
|
||||||
// namespaced wrapper for `man 3 fmod`
|
// namespaced wrapper for `man 3 fmod`
|
||||||
template <concepts::floating_point T>
|
template <std::floating_point T>
|
||||||
constexpr T
|
constexpr T
|
||||||
mod (T x, T y)
|
mod (T x, T y)
|
||||||
{
|
{
|
||||||
@ -394,7 +397,7 @@ namespace cruft {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <concepts::integral T>
|
template <std::integral T>
|
||||||
constexpr T
|
constexpr T
|
||||||
mod (T x, T y)
|
mod (T x, T y)
|
||||||
{
|
{
|
||||||
@ -402,7 +405,7 @@ namespace cruft {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <concepts::floating_point ValueT>
|
template <std::floating_point ValueT>
|
||||||
ValueT
|
ValueT
|
||||||
frac (ValueT val)
|
frac (ValueT val)
|
||||||
{
|
{
|
||||||
@ -515,8 +518,8 @@ namespace cruft {
|
|||||||
|
|
||||||
template <typename InputT>
|
template <typename InputT>
|
||||||
requires
|
requires
|
||||||
concepts::legacy_input_iterator<InputT> &&
|
concepts::named::legacy_input_iterator<InputT> &&
|
||||||
concepts::floating_point<typename std::iterator_traits<InputT>::value_type>
|
std::floating_point<typename std::iterator_traits<InputT>::value_type>
|
||||||
typename std::iterator_traits<InputT>::value_type
|
typename std::iterator_traits<InputT>::value_type
|
||||||
sum (InputT first, InputT last)
|
sum (InputT first, InputT last)
|
||||||
{
|
{
|
||||||
@ -545,8 +548,8 @@ namespace cruft {
|
|||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
template <typename InputT>
|
template <typename InputT>
|
||||||
requires
|
requires
|
||||||
concepts::legacy_input_iterator<InputT> &&
|
concepts::named::legacy_input_iterator<InputT> &&
|
||||||
concepts::integral<typename std::iterator_traits<InputT>::value_type>
|
std::integral<typename std::iterator_traits<InputT>::value_type>
|
||||||
typename std::iterator_traits<InputT>::value_type
|
typename std::iterator_traits<InputT>::value_type
|
||||||
sum (InputT first, InputT last)
|
sum (InputT first, InputT last)
|
||||||
{
|
{
|
||||||
@ -575,7 +578,7 @@ namespace cruft {
|
|||||||
/// parameter packs.
|
/// parameter packs.
|
||||||
///
|
///
|
||||||
/// eg, `max (sizeof (T)...)` will otherwise fail with a single type.
|
/// eg, `max (sizeof (T)...)` will otherwise fail with a single type.
|
||||||
template <concepts::integral ValueT>
|
template <std::integral ValueT>
|
||||||
constexpr decltype(auto)
|
constexpr decltype(auto)
|
||||||
max (ValueT &&val)
|
max (ValueT &&val)
|
||||||
{
|
{
|
||||||
@ -598,7 +601,7 @@ namespace cruft {
|
|||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
template <concepts::container ContainerT>
|
template <concepts::named::container ContainerT>
|
||||||
typename ContainerT::value_type const&
|
typename ContainerT::value_type const&
|
||||||
max (ContainerT const &vals)
|
max (ContainerT const &vals)
|
||||||
{
|
{
|
||||||
@ -606,13 +609,13 @@ namespace cruft {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <concepts::container ValueT>
|
template <concepts::named::container ValueT>
|
||||||
typename ValueT::value_type &
|
typename ValueT::value_type &
|
||||||
max (ValueT &&) = delete;
|
max (ValueT &&) = delete;
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
template <concepts::container ContainerT>
|
template <concepts::named::container ContainerT>
|
||||||
typename ContainerT::value_type const&
|
typename ContainerT::value_type const&
|
||||||
min (ContainerT const &vals)
|
min (ContainerT const &vals)
|
||||||
{
|
{
|
||||||
@ -620,7 +623,7 @@ namespace cruft {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <concepts::container ContainerT>
|
template <concepts::named::container ContainerT>
|
||||||
typename ContainerT::value_type&
|
typename ContainerT::value_type&
|
||||||
min (ContainerT &&) = delete;
|
min (ContainerT &&) = delete;
|
||||||
|
|
||||||
@ -643,9 +646,9 @@ namespace cruft {
|
|||||||
|
|
||||||
// min/max clamping
|
// min/max clamping
|
||||||
template <
|
template <
|
||||||
concepts::scalar T,
|
concepts::traits::scalar T,
|
||||||
concepts::scalar U,
|
concepts::traits::scalar U,
|
||||||
concepts::scalar V
|
concepts::traits::scalar V
|
||||||
>
|
>
|
||||||
constexpr std::common_type_t<T,U,V>
|
constexpr std::common_type_t<T,U,V>
|
||||||
clamp (T const val, U const lo, V const hi)
|
clamp (T const val, U const lo, V const hi)
|
||||||
@ -697,8 +700,8 @@ namespace cruft {
|
|||||||
|
|
||||||
// uint -> float
|
// uint -> float
|
||||||
template <
|
template <
|
||||||
concepts::unsigned_integral T,
|
std::unsigned_integral T,
|
||||||
concepts::floating_point U
|
std::floating_point U
|
||||||
>
|
>
|
||||||
constexpr U
|
constexpr U
|
||||||
renormalise (T t)
|
renormalise (T t)
|
||||||
@ -710,8 +713,8 @@ namespace cruft {
|
|||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
// float -> uint
|
// float -> uint
|
||||||
template <
|
template <
|
||||||
concepts::floating_point T,
|
std::floating_point T,
|
||||||
concepts::unsigned_integral U
|
std::unsigned_integral U
|
||||||
>
|
>
|
||||||
constexpr U
|
constexpr U
|
||||||
renormalise (T t)
|
renormalise (T t)
|
||||||
@ -745,8 +748,8 @@ namespace cruft {
|
|||||||
// ambiguous overloads
|
// ambiguous overloads
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
requires
|
requires
|
||||||
concepts::floating_point<T> &&
|
std::floating_point<T> &&
|
||||||
concepts::floating_point<U> &&
|
std::floating_point<U> &&
|
||||||
(!std::is_same_v<T, U>)
|
(!std::is_same_v<T, U>)
|
||||||
constexpr U
|
constexpr U
|
||||||
renormalise (T t)
|
renormalise (T t)
|
||||||
@ -759,8 +762,8 @@ namespace cruft {
|
|||||||
// hi_uint -> lo_uint
|
// hi_uint -> lo_uint
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
requires
|
requires
|
||||||
concepts::unsigned_integral<T> &&
|
std::unsigned_integral<T> &&
|
||||||
concepts::unsigned_integral<U> &&
|
std::unsigned_integral<U> &&
|
||||||
(sizeof (T) > sizeof (U))
|
(sizeof (T) > sizeof (U))
|
||||||
constexpr U
|
constexpr U
|
||||||
renormalise (T t)
|
renormalise (T t)
|
||||||
@ -781,8 +784,8 @@ namespace cruft {
|
|||||||
typename DstT
|
typename DstT
|
||||||
>
|
>
|
||||||
requires
|
requires
|
||||||
concepts::unsigned_integral<SrcT> &&
|
std::unsigned_integral<SrcT> &&
|
||||||
concepts::unsigned_integral<DstT> &&
|
std::unsigned_integral<DstT> &&
|
||||||
(sizeof (SrcT) < sizeof (DstT))
|
(sizeof (SrcT) < sizeof (DstT))
|
||||||
constexpr DstT
|
constexpr DstT
|
||||||
renormalise (SrcT src)
|
renormalise (SrcT src)
|
||||||
@ -834,7 +837,7 @@ namespace cruft {
|
|||||||
// anything-to-sint
|
// anything-to-sint
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
requires
|
requires
|
||||||
concepts::signed_integral<U> &&
|
std::signed_integral<U> &&
|
||||||
(!std::is_same<T,U>::value)
|
(!std::is_same<T,U>::value)
|
||||||
constexpr U
|
constexpr U
|
||||||
renormalise (T t)
|
renormalise (T t)
|
||||||
@ -851,7 +854,7 @@ namespace cruft {
|
|||||||
// sint-to-anything
|
// sint-to-anything
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
requires
|
requires
|
||||||
concepts::signed_integral<T> &&
|
std::signed_integral<T> &&
|
||||||
(!std::is_same<T,U>::value)
|
(!std::is_same<T,U>::value)
|
||||||
constexpr U
|
constexpr U
|
||||||
renormalise (T sint)
|
renormalise (T sint)
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
#include <cruft/util/tap.hpp>
|
#include <cruft/util/tap.hpp>
|
||||||
#include <cruft/util/concepts.hpp>
|
#include <cruft/util/concepts/named.hpp>
|
||||||
|
|
||||||
int main ()
|
int main ()
|
||||||
{
|
{
|
||||||
cruft::TAP::logger tap;
|
cruft::TAP::logger tap;
|
||||||
|
|
||||||
tap.expect (cruft::concepts::container<std::vector<int>>, "vector is a container");
|
tap.expect (cruft::concepts::named::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<int>, "int is not a container");
|
||||||
|
|
||||||
tap.expect (cruft::concepts::tuple<std::tuple<>>, "tuple<> is a tuple");
|
tap.expect (cruft::concepts::tuple<std::tuple<>>, "tuple<> is a tuple");
|
||||||
tap.expect (cruft::concepts::tuple<std::tuple<int>>, "tuple<int> is a tuple");
|
tap.expect (cruft::concepts::tuple<std::tuple<int>>, "tuple<int> is a tuple");
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "../maths.hpp"
|
#include "../maths.hpp"
|
||||||
#include "../tuple/type.hpp"
|
#include "../tuple/type.hpp"
|
||||||
|
|
||||||
|
#include <concepts>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
|
|
||||||
@ -54,7 +55,7 @@ namespace cruft {
|
|||||||
|
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
template <typename InitialT>
|
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)
|
tagged (InitialT &&initial)
|
||||||
{
|
{
|
||||||
set<InitialT> (std::forward<InitialT> (initial));
|
set<InitialT> (std::forward<InitialT> (initial));
|
||||||
|
Loading…
Reference in New Issue
Block a user