based

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

commit 1ff25aa15525ef445c7e3c5716d83ae2a032d82f
parent 4d38cd3cb45556a57d4343b9ea5df5938c296477
author Dimitrije Dobrota < mail@dimitrijedobrota.com >
date Tue, 6 May 2025 20:46:49 +0200

Shuffle type_traits around

Diffstat:
M include/based/algorithms/max.hpp | +++++++ ----
M include/based/algorithms/min.hpp | +++++++ ----
M include/based/concepts/callable.hpp | ++ --
M include/based/concepts/comparable/equal.hpp | + -
M include/based/concepts/comparable/greater.hpp | + -
M include/based/concepts/comparable/greater_equal.hpp | + -
M include/based/concepts/comparable/less.hpp | + -
M include/based/concepts/comparable/less_equal.hpp | + -
M include/based/concepts/comparable/not_equal.hpp | + -
M include/based/concepts/is/convertable.hpp | + -
M include/based/concepts/is/regular.hpp | + -
M include/based/concepts/is/same.hpp | ++ --
M include/based/concepts/is/semiregular.hpp | + -
M include/based/concepts/iterator.hpp | + -
M include/based/concepts/procedure/domain.hpp | ++++ ----
M include/based/concepts/procedure/procedure.hpp | ++ --
M include/based/count.hpp | + -
M include/based/functional/function.hpp | + -
A include/based/trait/add/lvalue_reference.hpp | +++++++++++++++++++++++++++
A include/based/trait/add/rvalue_reference.hpp | +++++++++++++++++++++++++++
A include/based/trait/integral_constant.hpp | ++++++++++++++++++++++
A include/based/trait/invoke/result.hpp | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A include/based/trait/is/const.hpp | +++++++++++++++++
A include/based/trait/is/convertable.hpp | ++++++++++++++
A include/based/trait/is/invocable.hpp | ++++++++++++++
A include/based/trait/is/lvalue_reference.hpp | +++++++++++++++++
A include/based/trait/is/rvalue_reference.hpp | +++++++++++++++++
A include/based/trait/is/same.hpp | +++++++++++++++++
A include/based/trait/iterator.hpp | +++++++++++++++++++++++++++++++++++++++++++++
A include/based/trait/remove/const.hpp | +++++++++++++++
A include/based/trait/remove/cv.hpp | +++++++++++++++++
A include/based/trait/remove/cvref.hpp | +++++++++++++++++++
A include/based/trait/remove/pointer.hpp | ++++++++++++++++++
A include/based/trait/remove/reference.hpp | ++++++++++++++++
A include/based/trait/remove/volatile.hpp | +++++++++++++++
A include/based/trait/signature.hpp | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A include/based/trait/type_identity.hpp | ++++++++++++++
D include/based/type_traits/add/lvalue_reference.hpp | ---------------------------
D include/based/type_traits/add/rvalue_reference.hpp | ---------------------------
D include/based/type_traits/integral_constant.hpp | ----------------------
D include/based/type_traits/invoke/result.hpp | --------------
D include/based/type_traits/is/const.hpp | -----------------
D include/based/type_traits/is/convertable.hpp | --------------
D include/based/type_traits/is/invocable.hpp | --------------
D include/based/type_traits/is/same.hpp | -----------------
D include/based/type_traits/iterator.hpp | ---------------------------------------------
D include/based/type_traits/remove/const.hpp | ---------------
D include/based/type_traits/remove/cv.hpp | -----------------
D include/based/type_traits/remove/cvref.hpp | -------------------
D include/based/type_traits/remove/pointer.hpp | ------------------
D include/based/type_traits/remove/reference.hpp | ----------------
D include/based/type_traits/remove/volatile.hpp | ---------------
D include/based/type_traits/signature.hpp | ---------------------------------------------------------------------------------
D include/based/type_traits/type_identity.hpp | --------------
M include/based/utility/declvar.hpp | + -
A include/based/utility/forward.hpp | +++++++++++++++++++++++
A include/based/utility/move.hpp | +++++++++++++++
M test/CMakeLists.txt | +++++++ -------
M test/source/concepts/callable_test.cpp | +++ ---
A test/source/trait/is_lvalue_reference.cpp | ++++++++++++++++++++++++++++++++++
A test/source/trait/is_rvalue_reference.cpp | ++++++++++++++++++++++++++++++++++
A test/source/trait/remove_const.cpp | +++++++++++++++++++++++++++++++++++++
A test/source/trait/remove_cv.cpp | +++++++++++++++++++++++++++++++++++++
A test/source/trait/remove_cvref.cpp | +++++++++++++++++++++++++++++++++++++
A test/source/trait/remove_pointer.cpp | ++++++++++++++++++++++
A test/source/trait/remove_reference.cpp | +++++++++++++++++++++++++++++++++++++
A test/source/trait/remove_volatile.cpp | +++++++++++++++++++++++++++++++++++++
A test/source/trait/signature_test.cpp | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
D test/source/type_traits/remove_const.cpp | -------------------------------------
D test/source/type_traits/remove_cv.cpp | -------------------------------------
D test/source/type_traits/remove_cvref.cpp | -------------------------------------
D test/source/type_traits/remove_pointer.cpp | ----------------------
D test/source/type_traits/remove_reference.cpp | -------------------------------------
D test/source/type_traits/remove_volatile.cpp | -------------------------------------
D test/source/type_traits/signature_test.cpp | ---------------------------------------------------------------------------------

75 files changed, 1505 insertions(+), 1296 deletions(-)


diff --git a/ include/based/algorithms/max.hpp b/ include/based/algorithms/max.hpp

@@ -1,11 +1,9 @@

#pragma once

#include <functional>

#include "based/concepts/is/regular.hpp"
#include "based/concepts/is/same.hpp"
#include "based/concepts/procedure/procedure.hpp"
#include "based/type_traits/remove/cvref.hpp"
#include "based/trait/remove/reference.hpp"

namespace based
{

@@ -32,7 +30,12 @@ template<BareRegular T, BareRegular U>

decltype(auto) max(T&& lhs, U&& rhs)
{
return based::max(
std::forward<T>(lhs), std::forward<U>(rhs), std::less<remove_cvref_t<T>>()
std::forward<T>(lhs),
std::forward<U>(rhs),
[](const remove_reference_t<T>& llhs, const remove_reference_t<U>& lrhs)
{
return llhs < lrhs;
}
);
}

diff --git a/ include/based/algorithms/min.hpp b/ include/based/algorithms/min.hpp

@@ -1,11 +1,9 @@

#pragma once

#include <functional>

#include "based/concepts/is/regular.hpp"
#include "based/concepts/is/same.hpp"
#include "based/concepts/procedure/procedure.hpp"
#include "based/type_traits/remove/cvref.hpp"
#include "based/trait/remove/reference.hpp"

namespace based
{

@@ -31,7 +29,12 @@ template<BareRegular T, BareRegular U>

decltype(auto) min(T&& lhs, U&& rhs)
{
return based::min(
std::forward<T>(lhs), std::forward<U>(rhs), std::less<remove_cvref_t<T>>()
std::forward<T>(lhs),
std::forward<U>(rhs),
[](const remove_reference_t<T>& llhs, const remove_reference_t<U>& lrhs)
{
return llhs < lrhs;
}
);
}

diff --git a/ include/based/concepts/callable.hpp b/ include/based/concepts/callable.hpp

@@ -1,7 +1,7 @@

#pragma once

#include "based/type_traits/remove/pointer.hpp"
#include "based/type_traits/signature.hpp"
#include "based/trait/remove/pointer.hpp"
#include "based/trait/signature.hpp"

namespace based
{

diff --git a/ include/based/concepts/comparable/equal.hpp b/ include/based/concepts/comparable/equal.hpp

@@ -1,7 +1,7 @@

#pragma once

#include "based/concepts/is/same.hpp"
#include "based/type_traits/remove/reference.hpp"
#include "based/trait/remove/reference.hpp"

namespace based
{

diff --git a/ include/based/concepts/comparable/greater.hpp b/ include/based/concepts/comparable/greater.hpp

@@ -1,7 +1,7 @@

#pragma once

#include "based/concepts/is/same.hpp"
#include "based/type_traits/remove/reference.hpp"
#include "based/trait/remove/reference.hpp"

namespace based
{

diff --git a/ include/based/concepts/comparable/greater_equal.hpp b/ include/based/concepts/comparable/greater_equal.hpp

@@ -1,7 +1,7 @@

#pragma once

#include "based/concepts/is/same.hpp"
#include "based/type_traits/remove/reference.hpp"
#include "based/trait/remove/reference.hpp"

namespace based
{

diff --git a/ include/based/concepts/comparable/less.hpp b/ include/based/concepts/comparable/less.hpp

@@ -1,7 +1,7 @@

#pragma once

#include "based/concepts/is/same.hpp"
#include "based/type_traits/remove/reference.hpp"
#include "based/trait/remove/reference.hpp"

namespace based
{

diff --git a/ include/based/concepts/comparable/less_equal.hpp b/ include/based/concepts/comparable/less_equal.hpp

@@ -1,7 +1,7 @@

#pragma once

#include "based/concepts/is/same.hpp"
#include "based/type_traits/remove/reference.hpp"
#include "based/trait/remove/reference.hpp"

namespace based
{

diff --git a/ include/based/concepts/comparable/not_equal.hpp b/ include/based/concepts/comparable/not_equal.hpp

@@ -1,7 +1,7 @@

#pragma once

#include "based/concepts/is/same.hpp"
#include "based/type_traits/remove/reference.hpp"
#include "based/trait/remove/reference.hpp"

namespace based
{

diff --git a/ include/based/concepts/is/convertable.hpp b/ include/based/concepts/is/convertable.hpp

@@ -1,6 +1,6 @@

#pragma once

#include "based/type_traits/is/convertable.hpp"
#include "based/trait/is/convertable.hpp"
#include "based/utility/declvar.hpp"

namespace based

diff --git a/ include/based/concepts/is/regular.hpp b/ include/based/concepts/is/regular.hpp

@@ -2,7 +2,7 @@


#include <concepts>

#include "based/type_traits/remove/cvref.hpp"
#include "based/trait/remove/cvref.hpp"

namespace based
{

diff --git a/ include/based/concepts/is/same.hpp b/ include/based/concepts/is/same.hpp

@@ -1,7 +1,7 @@

#pragma once

#include "based/type_traits/is/same.hpp"
#include "based/type_traits/remove/cvref.hpp"
#include "based/trait/is/same.hpp"
#include "based/trait/remove/cvref.hpp"

namespace based
{

diff --git a/ include/based/concepts/is/semiregular.hpp b/ include/based/concepts/is/semiregular.hpp

@@ -2,7 +2,7 @@


#include <concepts>

#include "based/type_traits/remove/cvref.hpp"
#include "based/trait/remove/cvref.hpp"

namespace based
{

diff --git a/ include/based/concepts/iterator.hpp b/ include/based/concepts/iterator.hpp

@@ -2,7 +2,7 @@


#include "based/concepts/is/regular.hpp"
#include "based/concepts/is/same.hpp"
#include "based/type_traits/iterator.hpp"
#include "based/trait/iterator.hpp"

namespace based
{

diff --git a/ include/based/concepts/procedure/domain.hpp b/ include/based/concepts/procedure/domain.hpp

@@ -5,10 +5,10 @@

#include "based/concepts/is/regular.hpp"
#include "based/concepts/is/same.hpp"
#include "based/concepts/is/semiregular.hpp"
#include "based/type_traits/is/const.hpp"
#include "based/type_traits/remove/cvref.hpp"
#include "based/type_traits/remove/pointer.hpp"
#include "based/type_traits/remove/reference.hpp"
#include "based/trait/is/const.hpp"
#include "based/trait/remove/cvref.hpp"
#include "based/trait/remove/pointer.hpp"
#include "based/trait/remove/reference.hpp"
#include "based/types/types.hpp"

namespace based

diff --git a/ include/based/concepts/procedure/procedure.hpp b/ include/based/concepts/procedure/procedure.hpp

@@ -4,8 +4,8 @@

#include "based/concepts/is/invocable.hpp"
#include "based/concepts/is/regular.hpp"
#include "based/concepts/procedure/domain.hpp"
#include "based/type_traits/integral_constant.hpp"
#include "based/type_traits/invoke/result.hpp"
#include "based/trait/integral_constant.hpp"
#include "based/trait/invoke/result.hpp"

namespace based
{

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

@@ -1,7 +1,7 @@

#pragma once

#include "based/concepts/iterator.hpp"
#include "based/type_traits/iterator.hpp"
#include "based/trait/iterator.hpp"

namespace based
{

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

@@ -3,7 +3,7 @@

#include <functional>

#include "based/concepts/is/same.hpp"
#include "based/type_traits/signature.hpp"
#include "based/trait/signature.hpp"
#include "based/types/types.hpp"
#include "based/utility/buffer.hpp"

diff --git a/ include/based/trait/add/lvalue_reference.hpp b/ include/based/trait/add/lvalue_reference.hpp

@@ -0,0 +1,27 @@

#pragma once

#include "based/trait/type_identity.hpp"

namespace based
{

// clang-format off

namespace detail
{

// Note that “cv void&” is a substitution failure
template<class T> auto try_add(int) -> type_identity<T&>;

// Handle T = cv void case
template<class T> auto try_add(...) -> type_identity<T>;

} // namespace detail

template<class T> struct add_lvalue_reference : decltype(detail::try_add<T>(0)) {};

template<class T> using add_lvalue_reference_t = add_lvalue_reference<T>::type;

// clang-format on

} // namespace based

diff --git a/ include/based/trait/add/rvalue_reference.hpp b/ include/based/trait/add/rvalue_reference.hpp

@@ -0,0 +1,27 @@

#pragma once

#include "based/trait/type_identity.hpp"

namespace based
{

// clang-format off

namespace detail
{

// Note that “cv void&&” is a substitution failure
template<class T> auto try_add(int) -> type_identity<T&&>;

// Handle T = cv void case
template<class T> auto try_add(...) -> type_identity<T>;

} // namespace detail

template<class T> struct add_rvalue_reference : decltype(detail::try_add<T>(0)) {};

template<class T> using add_rvalue_reference_t = add_rvalue_reference<T>::type;

// clang-format on

} // namespace based

diff --git a/ include/based/trait/integral_constant.hpp b/ include/based/trait/integral_constant.hpp

@@ -0,0 +1,22 @@

#pragma once

namespace based
{

template<class T, T v>
struct integral_constant
{
static constexpr T value = v;

using value_type = T;
using type = integral_constant;

// NOLINTNEXTLINE(*explicit*)
constexpr operator value_type() const noexcept { return value; }
constexpr value_type operator()() const noexcept { return value; }
};

using true_type = integral_constant<bool, true>;
using false_type = integral_constant<bool, false>;

} // namespace based

diff --git a/ include/based/trait/invoke/result.hpp b/ include/based/trait/invoke/result.hpp

@@ -0,0 +1,77 @@

#pragma once

#include <type_traits>
#include <utility>

namespace based
{

namespace detail
{
template<class T>
struct is_reference_wrapper : std::false_type
{
};
template<class U>
struct is_reference_wrapper<std::reference_wrapper<U>> : std::true_type
{
};

template<class T>
struct invoke_impl
{
template<class F, class... Args>
static auto call(F&& f, Args&&... args)
-> decltype(std::forward<F>(f)(std::forward<Args>(args)...));
};

template<class B, class MT>
struct invoke_impl<MT B::*>
{
template<
class T,
class Td = typename std::decay<T>::type,
class = typename std::enable_if<std::is_base_of<B, Td>::value>::type>
static auto get(T&& t) -> T&&;

template<
class T,
class Td = typename std::decay<T>::type,
class = typename std::enable_if<is_reference_wrapper<Td>::value>::type>
static auto get(T&& t) -> decltype(t.get());

template<
class T,
class Td = typename std::decay<T>::type,
class = typename std::enable_if<!std::is_base_of<B, Td>::value>::type,
class = typename std::enable_if<!is_reference_wrapper<Td>::value>::type>
static auto get(T&& t) -> decltype(*std::forward<T>(t));

template<
class T,
class... Args,
class MT1,
class = typename std::enable_if<std::is_function<MT1>::value>::type>
static auto call(MT1 B::* pmf, T&& t, Args&&... args)
-> decltype((invoke_impl::get(std::forward<T>(t)).*pmf)(
std::forward<Args>(args)...
));

template<class T>
static auto call(MT B::* pmd, T&& t)
-> decltype(invoke_impl::get(std::forward<T>(t)).*pmd);
};

template<class F, class... Args, class Fd = typename std::decay<F>::type>
auto INVOKE(F&& f, Args&&... args) -> decltype(invoke_impl<Fd>::call(
std::forward<F>(f), std::forward<Args>(args)...
));
} // namespace detail

template<class F, class... Args>
using invoke_result = std::invoke_result<F, Args...>;

template<class F, class... Args>
using invoke_result_t = invoke_result<F, Args...>::type;

} // namespace based

diff --git a/ include/based/trait/is/const.hpp b/ include/based/trait/is/const.hpp

@@ -0,0 +1,17 @@

#pragma once

#include "based/trait/integral_constant.hpp"

namespace based
{

// clang-format off

template<class T> struct is_const : false_type {};
template<class T> struct is_const<const T> : true_type {};

template<class T> constexpr bool is_const_v = is_const<T>::value;

// clang-format on

} // namespace based

diff --git a/ include/based/trait/is/convertable.hpp b/ include/based/trait/is/convertable.hpp

@@ -0,0 +1,14 @@

#pragma once

#include <type_traits>

namespace based
{

template<class From, class To>
using is_convertible = std::is_convertible<From, To>;

template<class From, class To>
constexpr bool is_convertible_v = std::is_convertible_v<From, To>;

} // namespace based

diff --git a/ include/based/trait/is/invocable.hpp b/ include/based/trait/is/invocable.hpp

@@ -0,0 +1,14 @@

#pragma once

#include <type_traits>

namespace based
{

template<class F, class... Args>
using is_invocable = std::is_invocable<F, Args...>;

template<class F, class... Args>
constexpr bool is_invocable_v = is_invocable<F, Args...>::value;

} // namespace based

diff --git a/ include/based/trait/is/lvalue_reference.hpp b/ include/based/trait/is/lvalue_reference.hpp

@@ -0,0 +1,17 @@

#pragma once

#include "based/trait/integral_constant.hpp"

namespace based
{

// clang-format off

template <class T> struct is_lvalue_reference : false_type {};
template <class T> struct is_lvalue_reference<T&> : true_type {};

template <class T> constexpr bool is_lvalue_reference_v = is_lvalue_reference<T>::value;

// clang-format on

} // namespace based

diff --git a/ include/based/trait/is/rvalue_reference.hpp b/ include/based/trait/is/rvalue_reference.hpp

@@ -0,0 +1,17 @@

#pragma once

#include "based/trait/integral_constant.hpp"

namespace based
{

// clang-format off

template <class T> struct is_rvalue_reference : false_type {};
template <class T> struct is_rvalue_reference<T&&> : true_type {};

template <class T> constexpr bool is_rvalue_reference_v = is_rvalue_reference<T>::value;

// clang-format on

} // namespace based

diff --git a/ include/based/trait/is/same.hpp b/ include/based/trait/is/same.hpp

@@ -0,0 +1,17 @@

#pragma once

#include "based/trait/integral_constant.hpp"

namespace based
{

// clang-format off

template<class T, class U> struct is_same : false_type {};
template<class T> struct is_same<T, T> : true_type {};

template<class T, class U> constexpr bool is_same_v = is_same<T, U>::value;

// clang-format on

} // namespace based

diff --git a/ include/based/trait/iterator.hpp b/ include/based/trait/iterator.hpp

@@ -0,0 +1,45 @@

#pragma once

#include <iterator>

#include "based/types/types.hpp"

namespace based
{

namespace detail
{
template<typename I>
struct iterator_traits
{
using value_type = I;
using distance_type = u64;
using pointer_type = I&;
using reference_type = I*;
};

template<typename I>
requires std::input_or_output_iterator<I>
struct iterator_traits<I>
{
using value_type = std::iterator_traits<I>::value_type;
using distance_type = std::iterator_traits<I>::difference_type;
using pointer_type = std::iterator_traits<I>::pointer;
using reference_type = std::iterator_traits<I>::reference;
};

} // namespace detail

template<typename T>
using iter_value_t = detail::iterator_traits<T>::value_type;

template<typename T>
using iter_dist_t = detail::iterator_traits<T>::distance_type;

template<typename T>
using iter_ptr_t = detail::iterator_traits<T>::pointer;

template<typename T>
using iter_ref_t = detail::iterator_traits<T>::reference;

} // namespace based

diff --git a/ include/based/trait/remove/const.hpp b/ include/based/trait/remove/const.hpp

@@ -0,0 +1,15 @@

#pragma once

namespace based
{

// clang-format off

template<class T> struct remove_const { using type = T; };
template<class T> struct remove_const<const T> { using type = T; };

template<class T> using remove_const_t = typename remove_const<T>::type;

// clang-format on

} // namespace based

diff --git a/ include/based/trait/remove/cv.hpp b/ include/based/trait/remove/cv.hpp

@@ -0,0 +1,17 @@

#pragma once

namespace based
{

// clang-format off

template<class T> struct remove_cv { using type = T; };
template<class T> struct remove_cv<const T> { using type = T; };
template<class T> struct remove_cv<volatile T> { using type = T; };
template<class T> struct remove_cv<const volatile T> { using type = T; };

template<class T> using remove_cv_t = typename remove_cv<T>::type;

// clang-format on

} // namespace based

diff --git a/ include/based/trait/remove/cvref.hpp b/ include/based/trait/remove/cvref.hpp

@@ -0,0 +1,19 @@

#pragma once

#include "based/trait/remove/cv.hpp"
#include "based/trait/remove/reference.hpp"

namespace based
{

// clang-format off

template<class T> struct remove_cvref {
using type = remove_cv_t<remove_reference_t<T>>;
};

template<class T> using remove_cvref_t = typename remove_cvref<T>::type;

// clang-format on

} // namespace based

diff --git a/ include/based/trait/remove/pointer.hpp b/ include/based/trait/remove/pointer.hpp

@@ -0,0 +1,18 @@

#pragma once

namespace based
{

// clang-format off

template<class T> struct remove_pointer { using type = T; };
template<class T> struct remove_pointer<T*> { using type = T; };
template<class T> struct remove_pointer<T* const> { using type = T; };
template<class T> struct remove_pointer<T* volatile> { using type = T; };
template<class T> struct remove_pointer<T* const volatile> { using type = T; };

template<class T> using remove_pointer_t = typename remove_pointer<T>::type;

// clang-format on

} // namespace based

diff --git a/ include/based/trait/remove/reference.hpp b/ include/based/trait/remove/reference.hpp

@@ -0,0 +1,16 @@

#pragma once

namespace based
{

// clang-format off

template<class T> struct remove_reference { using type = T; };
template<class T> struct remove_reference<T&> { using type = T; };
template<class T> struct remove_reference<T&&> { using type = T; };

template<class T> using remove_reference_t = typename remove_reference<T>::type;

// clang-format on

} // namespace based

diff --git a/ include/based/trait/remove/volatile.hpp b/ include/based/trait/remove/volatile.hpp

@@ -0,0 +1,15 @@

#pragma once

namespace based
{

// clang-format off

template<class T> struct remove_volatile { using type = T; };
template<class T> struct remove_volatile<volatile T> { using type = T; };

template<class T> using remove_volatile_t = typename remove_volatile<T>::type;

// clang-format on

} // namespace based

diff --git a/ include/based/trait/signature.hpp b/ include/based/trait/signature.hpp

@@ -0,0 +1,257 @@

#pragma once

#include <tuple>

#include "based/trait/integral_constant.hpp"

namespace based
{

template<typename>
struct signature;

template<typename Ret, bool ne, typename... Args>
struct signature<Ret(Args...) noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using noexcept_val = integral_constant<bool, ne>;
};

template<typename Ret, bool ne, typename... Args>
struct signature<Ret (*)(Args...) noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using noexcept_val = integral_constant<bool, ne>;
};

template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using const_val = false_type;
using volatile_val = false_type;

using lvalref_val = false_type;
using rvalref_val = false_type;

using noexcept_val = integral_constant<bool, ne>;
};

template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) & noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using const_val = false_type;
using volatile_val = false_type;

using lvalref_val = true_type;
using rvalref_val = false_type;

using noexcept_val = integral_constant<bool, ne>;
};

template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) && noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using const_val = false_type;
using volatile_val = false_type;

using lvalref_val = false_type;
using rvalref_val = true_type;

using noexcept_val = integral_constant<bool, ne>;
};

template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) const noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using const_val = true_type;
using volatile_val = false_type;

using lvalref_val = false_type;
using rvalref_val = false_type;

using noexcept_val = integral_constant<bool, ne>;
};

template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) const & noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using const_val = true_type;
using volatile_val = false_type;

using lvalref_val = true_type;
using rvalref_val = false_type;

using noexcept_val = integral_constant<bool, ne>;
};

template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) const && noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using const_val = true_type;
using volatile_val = false_type;

using lvalref_val = false_type;
using rvalref_val = true_type;

using noexcept_val = integral_constant<bool, ne>;
};

template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) volatile noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using const_val = false_type;
using volatile_val = true_type;

using lvalref_val = false_type;
using rvalref_val = false_type;

using noexcept_val = integral_constant<bool, ne>;
};

template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) volatile & noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using const_val = false_type;
using volatile_val = true_type;

using lvalref_val = true_type;
using rvalref_val = false_type;

using noexcept_val = integral_constant<bool, ne>;
};

template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) volatile && noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using const_val = false_type;
using volatile_val = true_type;

using lvalref_val = false_type;
using rvalref_val = true_type;

using noexcept_val = integral_constant<bool, ne>;
};

template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) const volatile noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using const_val = true_type;
using volatile_val = true_type;

using lvalref_val = false_type;
using rvalref_val = false_type;

using noexcept_val = integral_constant<bool, ne>;
};

template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) const volatile & noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using const_val = true_type;
using volatile_val = true_type;

using lvalref_val = true_type;
using rvalref_val = false_type;

using noexcept_val = integral_constant<bool, ne>;
};

template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) const volatile && noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using const_val = true_type;
using volatile_val = true_type;

using lvalref_val = false_type;
using rvalref_val = true_type;

using noexcept_val = integral_constant<bool, ne>;
};

template<typename StaticCallOp>
struct signature_static
{
};

template<typename Ret, bool ne, typename... Args>
struct signature_static<Ret (*)(Args...) noexcept(ne)>
{
using sig_type = Ret(Args...);
};

template<typename F, typename Op>
using signature_t = typename std::conditional_t<requires(F& func) {
(void)func.operator();
}, signature_static<Op>, signature<Op>>::sig_type;

/*
template<typename Sig>
class function;

template<typename Ret, typename... Args>
class function<Ret(Args...)>
{
};

template<typename Ret, typename... Args>
function(Ret (*)(Args...)) -> function<Ret(Args...)>;

template<typename F, typename Sig = signature_t<F, decltype(&F::operator())>>
function(F) -> function<Sig>;
*/

} // namespace based

diff --git a/ include/based/trait/type_identity.hpp b/ include/based/trait/type_identity.hpp

@@ -0,0 +1,14 @@

#pragma once

namespace based
{

// clang-format off

template<class T> struct type_identity { using type = T; };

template<class T> using type_dentity_t = type_identity<T>::type;

// clang-format on

} // namespace based

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

@@ -1,27 +0,0 @@

#pragma once

#include "based/type_traits/type_identity.hpp"

namespace based
{

// clang-format off

namespace detail
{

// Note that “cv void&” is a substitution failure
template<class T> auto try_add(int) -> type_identity<T&>;

// Handle T = cv void case
template<class T> auto try_add(...) -> type_identity<T>;

} // namespace detail

template<class T> struct add_lvalue_reference : decltype(detail::try_add<T>(0)) {};

template<class T> using add_lvalue_reference_t = add_lvalue_reference<T>::type;

// clang-format on

} // namespace based

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

@@ -1,27 +0,0 @@

#pragma once

#include "based/type_traits/type_identity.hpp"

namespace based
{

// clang-format off

namespace detail
{

// Note that “cv void&&” is a substitution failure
template<class T> auto try_add(int) -> type_identity<T&&>;

// Handle T = cv void case
template<class T> auto try_add(...) -> type_identity<T>;

} // namespace detail

template<class T> struct add_rvalue_reference : decltype(detail::try_add<T>(0)) {};

template<class T> using add_rvalue_reference_t = add_rvalue_reference<T>::type;

// clang-format on

} // namespace based

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

@@ -1,22 +0,0 @@

#pragma once

namespace based
{

template<class T, T v>
struct integral_constant
{
static constexpr T value = v;

using value_type = T;
using type = integral_constant;

// NOLINTNEXTLINE(*explicit*)
constexpr operator value_type() const noexcept { return value; }
constexpr value_type operator()() const noexcept { return value; }
};

using true_type = integral_constant<bool, true>;
using false_type = integral_constant<bool, false>;

} // namespace based

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

@@ -1,14 +0,0 @@

#pragma once

#include <type_traits>

namespace based
{

template<class F, class... Args>
using invoke_result = std::invoke_result<F, Args...>;

template<class F, class... Args>
using invoke_result_t = invoke_result<F, Args...>::type;

} // namespace based

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

@@ -1,17 +0,0 @@

#pragma once

#include "based/type_traits/integral_constant.hpp"

namespace based
{

// clang-format off

template<class T> struct is_const : false_type {};
template<class T> struct is_const<const T> : true_type {};

template<class T> constexpr bool is_const_v = is_const<T>::value;

// clang-format on

} // namespace based

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

@@ -1,14 +0,0 @@

#pragma once

#include <type_traits>

namespace based
{

template<class From, class To>
using is_convertible = std::is_convertible<From, To>;

template<class From, class To>
static constexpr bool is_convertible_v = std::is_convertible_v<From, To>;

} // namespace based

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

@@ -1,14 +0,0 @@

#pragma once

#include <type_traits>

namespace based
{

template<class F, class... Args>
using is_invocable = std::is_invocable<F, Args...>;

template<class F, class... Args>
static constexpr bool is_invocable_v = is_invocable<F, Args...>::value;

} // namespace based

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

@@ -1,17 +0,0 @@

#pragma once

#include "based/type_traits/integral_constant.hpp"

namespace based
{

// clang-format off

template<class T, class U> struct is_same : false_type {};
template<class T> struct is_same<T, T> : true_type {};

template<class T, class U> constexpr bool is_same_v = is_same<T, U>::value;

// clang-format on

} // namespace based

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

@@ -1,45 +0,0 @@

#pragma once

#include <iterator>

#include "based/types/types.hpp"

namespace based
{

namespace detail
{
template<typename I>
struct iterator_traits
{
using value_type = I;
using distance_type = u64;
using pointer_type = I&;
using reference_type = I*;
};

template<typename I>
requires std::input_or_output_iterator<I>
struct iterator_traits<I>
{
using value_type = std::iterator_traits<I>::value_type;
using distance_type = std::iterator_traits<I>::difference_type;
using pointer_type = std::iterator_traits<I>::pointer;
using reference_type = std::iterator_traits<I>::reference;
};

} // namespace detail

template<typename T>
using iter_value_t = detail::iterator_traits<T>::value_type;

template<typename T>
using iter_dist_t = detail::iterator_traits<T>::distance_type;

template<typename T>
using iter_ptr_t = detail::iterator_traits<T>::pointer;

template<typename T>
using iter_ref_t = detail::iterator_traits<T>::reference;

} // namespace based

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

@@ -1,15 +0,0 @@

#pragma once

namespace based
{

// clang-format off

template<class T> struct remove_const { using type = T; };
template<class T> struct remove_const<const T> { using type = T; };

template<class T> using remove_const_t = typename remove_const<T>::type;

// clang-format on

} // namespace based

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

@@ -1,17 +0,0 @@

#pragma once

namespace based
{

// clang-format off

template<class T> struct remove_cv { using type = T; };
template<class T> struct remove_cv<const T> { using type = T; };
template<class T> struct remove_cv<volatile T> { using type = T; };
template<class T> struct remove_cv<const volatile T> { using type = T; };

template<class T> using remove_cv_t = typename remove_cv<T>::type;

// clang-format on

} // namespace based

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

@@ -1,19 +0,0 @@

#pragma once

#include "based/type_traits/remove/cv.hpp"
#include "based/type_traits/remove/reference.hpp"

namespace based
{

// clang-format off

template<class T> struct remove_cvref {
using type = remove_cv_t<remove_reference_t<T>>;
};

template<class T> using remove_cvref_t = typename remove_cvref<T>::type;

// clang-format on

} // namespace based

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

@@ -1,18 +0,0 @@

#pragma once

namespace based
{

// clang-format off

template<class T> struct remove_pointer { using type = T; };
template<class T> struct remove_pointer<T*> { using type = T; };
template<class T> struct remove_pointer<T* const> { using type = T; };
template<class T> struct remove_pointer<T* volatile> { using type = T; };
template<class T> struct remove_pointer<T* const volatile> { using type = T; };

template<class T> using remove_pointer_t = typename remove_pointer<T>::type;

// clang-format on

} // namespace based

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

@@ -1,16 +0,0 @@

#pragma once

namespace based
{

// clang-format off

template<class T> struct remove_reference { using type = T; };
template<class T> struct remove_reference<T&> { using type = T; };
template<class T> struct remove_reference<T&&> { using type = T; };

template<class T> using remove_reference_t = typename remove_reference<T>::type;

// clang-format on

} // namespace based

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

@@ -1,15 +0,0 @@

#pragma once

namespace based
{

// clang-format off

template<class T> struct remove_volatile { using type = T; };
template<class T> struct remove_volatile<volatile T> { using type = T; };

template<class T> using remove_volatile_t = typename remove_volatile<T>::type;

// clang-format on

} // namespace based

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

@@ -1,257 +0,0 @@

#pragma once

#include <tuple>

#include "based/type_traits/integral_constant.hpp"

namespace based
{

template<typename>
struct signature;

template<typename Ret, bool ne, typename... Args>
struct signature<Ret(Args...) noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using noexcept_val = integral_constant<bool, ne>;
};

template<typename Ret, bool ne, typename... Args>
struct signature<Ret (*)(Args...) noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using noexcept_val = integral_constant<bool, ne>;
};

template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using const_val = false_type;
using volatile_val = false_type;

using lvalref_val = false_type;
using rvalref_val = false_type;

using noexcept_val = integral_constant<bool, ne>;
};

template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) & noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using const_val = false_type;
using volatile_val = false_type;

using lvalref_val = true_type;
using rvalref_val = false_type;

using noexcept_val = integral_constant<bool, ne>;
};

template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) && noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using const_val = false_type;
using volatile_val = false_type;

using lvalref_val = false_type;
using rvalref_val = true_type;

using noexcept_val = integral_constant<bool, ne>;
};

template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) const noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using const_val = true_type;
using volatile_val = false_type;

using lvalref_val = false_type;
using rvalref_val = false_type;

using noexcept_val = integral_constant<bool, ne>;
};

template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) const & noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using const_val = true_type;
using volatile_val = false_type;

using lvalref_val = true_type;
using rvalref_val = false_type;

using noexcept_val = integral_constant<bool, ne>;
};

template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) const && noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using const_val = true_type;
using volatile_val = false_type;

using lvalref_val = false_type;
using rvalref_val = true_type;

using noexcept_val = integral_constant<bool, ne>;
};

template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) volatile noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using const_val = false_type;
using volatile_val = true_type;

using lvalref_val = false_type;
using rvalref_val = false_type;

using noexcept_val = integral_constant<bool, ne>;
};

template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) volatile & noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using const_val = false_type;
using volatile_val = true_type;

using lvalref_val = true_type;
using rvalref_val = false_type;

using noexcept_val = integral_constant<bool, ne>;
};

template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) volatile && noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using const_val = false_type;
using volatile_val = true_type;

using lvalref_val = false_type;
using rvalref_val = true_type;

using noexcept_val = integral_constant<bool, ne>;
};

template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) const volatile noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using const_val = true_type;
using volatile_val = true_type;

using lvalref_val = false_type;
using rvalref_val = false_type;

using noexcept_val = integral_constant<bool, ne>;
};

template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) const volatile & noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using const_val = true_type;
using volatile_val = true_type;

using lvalref_val = true_type;
using rvalref_val = false_type;

using noexcept_val = integral_constant<bool, ne>;
};

template<typename Ret, typename Obj, bool ne, typename... Args>
struct signature<Ret (Obj::*)(Args...) const volatile && noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using const_val = true_type;
using volatile_val = true_type;

using lvalref_val = false_type;
using rvalref_val = true_type;

using noexcept_val = integral_constant<bool, ne>;
};

template<typename StaticCallOp>
struct signature_static
{
};

template<typename Ret, bool ne, typename... Args>
struct signature_static<Ret (*)(Args...) noexcept(ne)>
{
using sig_type = Ret(Args...);
};

template<typename F, typename Op>
using signature_t = typename std::conditional_t<requires(F& func) {
(void)func.operator();
}, signature_static<Op>, signature<Op>>::sig_type;

/*
template<typename Sig>
class function;

template<typename Ret, typename... Args>
class function<Ret(Args...)>
{
};

template<typename Ret, typename... Args>
function(Ret (*)(Args...)) -> function<Ret(Args...)>;

template<typename F, typename Sig = signature_t<F, decltype(&F::operator())>>
function(F) -> function<Sig>;
*/

} // namespace based

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

@@ -1,14 +0,0 @@

#pragma once

namespace based
{

// clang-format off

template<class T> struct type_identity { using type = T; };

template<class T> using type_dentity_t = type_identity<T>::type;

// clang-format on

} // namespace based

diff --git a/ include/based/utility/declvar.hpp b/ include/based/utility/declvar.hpp

@@ -1,6 +1,6 @@

#pragma once

#include "based/type_traits/add/rvalue_reference.hpp"
#include "based/trait/add/rvalue_reference.hpp"

namespace based
{

diff --git a/ include/based/utility/forward.hpp b/ include/based/utility/forward.hpp

@@ -0,0 +1,23 @@

#pragma once

#include "based/trait/is/lvalue_reference.hpp"
#include "based/trait/remove/reference.hpp"

namespace based
{

template<class T>
constexpr auto forward(remove_reference_t<T>& tmp) noexcept
{
return static_cast<T&&>(tmp);
}

template<class T>
// NOLINTNEXTLINE(*move*)
constexpr auto forward(remove_reference_t<T>&& tmp) noexcept
{
static_assert(!is_lvalue_reference_v<T>);
return static_cast<T&&>(tmp);
}

} // namespace based

diff --git a/ include/based/utility/move.hpp b/ include/based/utility/move.hpp

@@ -0,0 +1,15 @@

#pragma once

#include "based/trait/remove/reference.hpp"

namespace based
{

template<class T>
// NOLINTNEXTLINE(*forward*)
constexpr auto move(T&& tmp) noexcept
{
return static_cast<remove_reference_t<T>&&>(tmp);
}

} // namespace based

diff --git a/ test/CMakeLists.txt b/ test/CMakeLists.txt

@@ -28,13 +28,13 @@ endfunction()


## ----- Type Traits -----

add_test(type_traits remove_const)
add_test(type_traits remove_cv)
add_test(type_traits remove_cvref)
add_test(type_traits remove_pointer)
add_test(type_traits remove_reference)
add_test(type_traits remove_volatile)
add_test(type_traits signature_test)
add_test(trait remove_const)
add_test(trait remove_cv)
add_test(trait remove_cvref)
add_test(trait remove_pointer)
add_test(trait remove_reference)
add_test(trait remove_volatile)
add_test(trait signature_test)

## ----- Concepts -----

diff --git a/ test/source/concepts/callable_test.cpp b/ test/source/concepts/callable_test.cpp

@@ -19,7 +19,7 @@ int free_func(int a, double b)


using based::SameAs;

TEST_CASE("free function", "[type_traits/callable]")
TEST_CASE("free function", "[trait/callable]")
{
using type_t = decltype(free_func);

@@ -28,7 +28,7 @@ TEST_CASE("free function", "[type_traits/callable]")

STATIC_REQUIRE(SameAs<based::callable_ret_t<type_t>, int>);
}

TEST_CASE("lambda", "[type_traits/callable]")
TEST_CASE("lambda", "[trait/callable]")
{
const auto func = [](int a, double b)
{

@@ -47,7 +47,7 @@ struct func

auto operator()(auto a, auto b) { return static_cast<int>(a + b); }
};

TEST_CASE("member function", "[type_traits/callable]")
TEST_CASE("member function", "[trait/callable]")
{
// [&](auto&&... args) -> decltype(auto) { return
// f(std::forward<decltype(args)>(args)...); }

diff --git a/ test/source/trait/is_lvalue_reference.cpp b/ test/source/trait/is_lvalue_reference.cpp

@@ -0,0 +1,34 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include <catch2/catch_test_macros.hpp>

#include "based/trait/is/lvalue_reference.hpp"

TEST_CASE("is_lvalue_reference", "[trait/is_lvalue_reference]")
{
// NOLINTBEGIN(*array*)
// clang-format off
STATIC_REQUIRE(!based::is_lvalue_reference_v<int>);
STATIC_REQUIRE(based::is_lvalue_reference_v<int&>);
STATIC_REQUIRE(!based::is_lvalue_reference_v<int&&>);
STATIC_REQUIRE(!based::is_lvalue_reference_v<int[2]>);
STATIC_REQUIRE(based::is_lvalue_reference_v<int(&)[2]>);
STATIC_REQUIRE(!based::is_lvalue_reference_v<int(&&)[2]>);
STATIC_REQUIRE(!based::is_lvalue_reference_v<const int>);
STATIC_REQUIRE(based::is_lvalue_reference_v<const int&>);
STATIC_REQUIRE(!based::is_lvalue_reference_v<const int[2]>);
STATIC_REQUIRE(based::is_lvalue_reference_v<const int(&)[2]>);
STATIC_REQUIRE(!based::is_lvalue_reference_v<int(int)>);
STATIC_REQUIRE(!based::is_lvalue_reference_v<volatile int>);
STATIC_REQUIRE(based::is_lvalue_reference_v<volatile int&>);
STATIC_REQUIRE(!based::is_lvalue_reference_v<volatile int&&>);
STATIC_REQUIRE(!based::is_lvalue_reference_v<volatile int[2]>);
STATIC_REQUIRE(based::is_lvalue_reference_v<volatile int(&)[2]>);
STATIC_REQUIRE(!based::is_lvalue_reference_v<volatile int(&&)[2]>);
STATIC_REQUIRE(!based::is_lvalue_reference_v<const volatile int>);
STATIC_REQUIRE(based::is_lvalue_reference_v<const volatile int&>);
STATIC_REQUIRE(!based::is_lvalue_reference_v<const volatile int[2]>);
STATIC_REQUIRE(based::is_lvalue_reference_v<const volatile int(&)[2]>);
// clang-format on
// NOLINTEND(*array*)
}

diff --git a/ test/source/trait/is_rvalue_reference.cpp b/ test/source/trait/is_rvalue_reference.cpp

@@ -0,0 +1,34 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include <catch2/catch_test_macros.hpp>

#include "based/trait/is/rvalue_reference.hpp"

TEST_CASE("is_rvalue_reference", "[trait/is_rvalue_reference]")
{
// NOLINTBEGIN(*array*)
// clang-format off
STATIC_REQUIRE(!based::is_rvalue_reference_v<int>);
STATIC_REQUIRE(!based::is_rvalue_reference_v<int&>);
STATIC_REQUIRE(based::is_rvalue_reference_v<int&&>);
STATIC_REQUIRE(!based::is_rvalue_reference_v<int[2]>);
STATIC_REQUIRE(!based::is_rvalue_reference_v<int(&)[2]>);
STATIC_REQUIRE(based::is_rvalue_reference_v<int(&&)[2]>);
STATIC_REQUIRE(!based::is_rvalue_reference_v<const int>);
STATIC_REQUIRE(!based::is_rvalue_reference_v<const int&>);
STATIC_REQUIRE(!based::is_rvalue_reference_v<const int[2]>);
STATIC_REQUIRE(!based::is_rvalue_reference_v<const int(&)[2]>);
STATIC_REQUIRE(!based::is_rvalue_reference_v<int(int)>);
STATIC_REQUIRE(!based::is_rvalue_reference_v<volatile int>);
STATIC_REQUIRE(!based::is_rvalue_reference_v<volatile int&>);
STATIC_REQUIRE(based::is_rvalue_reference_v<volatile int&&>);
STATIC_REQUIRE(!based::is_rvalue_reference_v<volatile int[2]>);
STATIC_REQUIRE(!based::is_rvalue_reference_v<volatile int(&)[2]>);
STATIC_REQUIRE(based::is_rvalue_reference_v<volatile int(&&)[2]>);
STATIC_REQUIRE(!based::is_rvalue_reference_v<const volatile int>);
STATIC_REQUIRE(!based::is_rvalue_reference_v<const volatile int&>);
STATIC_REQUIRE(!based::is_rvalue_reference_v<const volatile int[2]>);
STATIC_REQUIRE(!based::is_rvalue_reference_v<const volatile int(&)[2]>);
// clang-format on
// NOLINTEND(*array*)
}

diff --git a/ test/source/trait/remove_const.cpp b/ test/source/trait/remove_const.cpp

@@ -0,0 +1,37 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include <catch2/catch_test_macros.hpp>

#include "based/concepts/is/same.hpp"
#include "based/trait/remove/const.hpp"

using based::SameAs;

TEST_CASE("remove_const", "[trait/remove/remove_const]")
{
// NOLINTBEGIN(*array*)
// clang-format off
STATIC_REQUIRE(SameAs<based::remove_const_t<int>, int>);
STATIC_REQUIRE(SameAs<based::remove_const_t<int&>, int&>);
STATIC_REQUIRE(SameAs<based::remove_const_t<int&&>, int&&>);
STATIC_REQUIRE(SameAs<based::remove_const_t<int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<int(&)[2]>, int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<int(&&)[2]>, int(&&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const int>, int>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const int&>, const int&>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const int(&)[2]>, const int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<int(int)>, int(int)>);
STATIC_REQUIRE(SameAs<based::remove_const_t<volatile int>, volatile int>);
STATIC_REQUIRE(SameAs<based::remove_const_t<volatile int&>, volatile int&>);
STATIC_REQUIRE(SameAs<based::remove_const_t<volatile int&&>, volatile int&&>);
STATIC_REQUIRE(SameAs<based::remove_const_t<volatile int[2]>, volatile int[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<volatile int(&)[2]>, volatile int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<volatile int(&&)[2]>, volatile int(&&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const volatile int>, volatile int>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const volatile int&>, volatile const int&>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const volatile int[2]>, volatile int[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const volatile int(&)[2]>, volatile const int(&)[2]>);
// clang-format on
// NOLINTEND(*array*)
}

diff --git a/ test/source/trait/remove_cv.cpp b/ test/source/trait/remove_cv.cpp

@@ -0,0 +1,37 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include <catch2/catch_test_macros.hpp>

#include "based/concepts/is/same.hpp"
#include "based/trait/remove/cv.hpp"

using based::SameAs;

TEST_CASE("remove_cv", "[trait/remove_cv]")
{
// NOLINTBEGIN(*array*)
// clang-format off
STATIC_REQUIRE(SameAs<based::remove_cv_t<int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<int&>, int&>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<int&&>, int&&>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<int(&)[2]>, int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<int(&&)[2]>, int(&&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const int&>, const int&>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const int(&)[2]>, const int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<int(int)>, int(int)>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<volatile int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<volatile int&>, volatile int&>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<volatile int&&>, volatile int&&>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<volatile int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<volatile int(&)[2]>, volatile int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<volatile int(&&)[2]>, volatile int(&&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const volatile int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const volatile int&>, volatile const int&>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const volatile int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const volatile int(&)[2]>, volatile const int(&)[2]>);
// clang-format on
// NOLINTEND(*array*)
}

diff --git a/ test/source/trait/remove_cvref.cpp b/ test/source/trait/remove_cvref.cpp

@@ -0,0 +1,37 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include <catch2/catch_test_macros.hpp>

#include "based/concepts/is/same.hpp"
#include "based/trait/remove/cvref.hpp"

using based::SameAs;

TEST_CASE("remove_cvref", "[trait/remove_cvref]")
{
// NOLINTBEGIN(*array*)
// clang-format off
STATIC_REQUIRE(SameAs<based::remove_cvref_t<int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<int&>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<int&&>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<int(&)[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<int(&&)[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const int&>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const int(&)[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<int(int)>, int(int)>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<volatile int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<volatile int&>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<volatile int&&>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<volatile int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<volatile int(&)[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<volatile int(&&)[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const volatile int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const volatile int&>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const volatile int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const volatile int(&)[2]>, int[2]>);
// clang-format on
// NOLINTEND(*array*)
}

diff --git a/ test/source/trait/remove_pointer.cpp b/ test/source/trait/remove_pointer.cpp

@@ -0,0 +1,22 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include <catch2/catch_test_macros.hpp>

#include "based/concepts/is/same.hpp"
#include "based/trait/remove/pointer.hpp"

using based::SameAs;

TEST_CASE("remove_pointer", "[trait/remove_pointer]")
{
// NOLINTBEGIN(*array*)
// clang-format off
STATIC_REQUIRE(SameAs<based::remove_pointer_t<int>, int>);
STATIC_REQUIRE(SameAs<based::remove_pointer_t<int*>, int>);
STATIC_REQUIRE(SameAs<based::remove_pointer_t<int**>, int*>);
STATIC_REQUIRE(SameAs<based::remove_pointer_t<int* const>, int>);
STATIC_REQUIRE(SameAs<based::remove_pointer_t<int* volatile>, int>);
STATIC_REQUIRE(SameAs<based::remove_pointer_t<int* const volatile>, int>);
// clang-format on
// NOLINTEND(*array*)
}

diff --git a/ test/source/trait/remove_reference.cpp b/ test/source/trait/remove_reference.cpp

@@ -0,0 +1,37 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include <catch2/catch_test_macros.hpp>

#include "based/concepts/is/same.hpp"
#include "based/trait/remove/reference.hpp"

using based::SameAs;

TEST_CASE("remove_reference", "[trait/remove_reference]")
{
// NOLINTBEGIN(*array*)
// clang-format off
STATIC_REQUIRE(SameAs<based::remove_reference_t<int>, int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<int&>, int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<int&&>, int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<int(&)[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<int(&&)[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const int>, const int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const int&>, const int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const int[2]>, const int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const int(&)[2]>, const int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<int(int)>, int(int)>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<volatile int>,volatile int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<volatile int&>, volatile int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<volatile int&&>, volatile int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<volatile int[2]>, volatile int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<volatile int(&)[2]>, volatile int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<volatile int(&&)[2]>, volatile int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const volatile int>, const volatile int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const volatile int&>, volatile const int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const volatile int[2]>, const volatile int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const volatile int(&)[2]>, volatile const int[2]>);
// clang-format on
// NOLINTEND(*array*)
}

diff --git a/ test/source/trait/remove_volatile.cpp b/ test/source/trait/remove_volatile.cpp

@@ -0,0 +1,37 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include <catch2/catch_test_macros.hpp>

#include "based/concepts/is/same.hpp"
#include "based/trait/remove/volatile.hpp"

using based::SameAs;

TEST_CASE("remove_volatile", "[trait/remove/remove_volatile]")
{
// NOLINTBEGIN(*array*)
// clang-format off
STATIC_REQUIRE(SameAs<based::remove_volatile_t<int>, int>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<int&>, int&>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<int&&>, int&&>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<int(&)[2]>, int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<int(&&)[2]>, int(&&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const int>, const int>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const int&>, const int&>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const int[2]>, const int[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const int(&)[2]>, const int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<int(int)>, int(int)>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<volatile int>, int>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<volatile int&>, volatile int&>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<volatile int&&>, volatile int&&>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<volatile int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<volatile int(&)[2]>, volatile int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<volatile int(&&)[2]>, volatile int(&&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const volatile int>, const int>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const volatile int&>, volatile const int&>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const volatile int[2]>, const int[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const volatile int(&)[2]>, volatile const int(&)[2]>);
// clang-format on
// NOLINTEND(*array*)
}

diff --git a/ test/source/trait/signature_test.cpp b/ test/source/trait/signature_test.cpp

@@ -0,0 +1,480 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include "based/trait/signature.hpp"

#include <catch2/catch_test_macros.hpp>

#include "based/concepts/is/same.hpp"

// NOLINTBEGIN(*cognitive-complexity*)

namespace
{

// NOLINTNEXTLINE (*needed*)
int free_func(const double& a, int&& b) noexcept(false)
{
return static_cast<int>(a + b);
}

// NOLINTNEXTLINE (*needed*)
int free_func_noexcept(const double& a, int&& b) noexcept(true)
{
return static_cast<int>(a + b);
}

} // namespace

using based::SameAs;

TEST_CASE("free function", "[trait/signature]")
{
using sig = based::signature<decltype(free_func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}

TEST_CASE("free function noexcept", "[trait/signature]")
{
using sig = based::signature<decltype(free_func_noexcept)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}

TEST_CASE("empty", "[trait/signature]")
{
struct test
{
int func(const double& a, int&& b) noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}

TEST_CASE("const", "[trait/signature]")
{
struct test
{
int func(const double& a, int&& b) const noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}

TEST_CASE("volatile", "[trait/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}

TEST_CASE("const volatile", "[trait/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}

TEST_CASE("noexcept", "[trait/signature]")
{
struct test
{
int func(const double& a, int&& b) noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}

TEST_CASE("const noexcept", "[trait/signature]")
{
struct test
{
int func(const double& a, int&& b) const noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}

TEST_CASE("volatile noexcept", "[trait/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}

TEST_CASE("const volatile noexcept", "[trait/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}

TEST_CASE("lvalref", "[trait/signature]")
{
struct test
{
int func(const double& a, int&& b) & noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}

TEST_CASE("const lvalref", "[trait/signature]")
{
struct test
{
int func(const double& a, int&& b) const& noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}

TEST_CASE("volatile lvalref", "[trait/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile& noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}

TEST_CASE("const volatile lvalref", "[trait/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile& noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}

TEST_CASE("noexcept lvalref", "[trait/signature]")
{
struct test
{
int func(const double& a, int&& b) & noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}

TEST_CASE("const noexcept lvalref", "[trait/signature]")
{
struct test
{
int func(const double& a, int&& b) const& noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}

TEST_CASE("volatile noexcept lvalref", "[trait/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile& noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}

TEST_CASE("const volatile noexcept lvalref", "[trait/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile& noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}

TEST_CASE("rvalref", "[trait/signature]")
{
struct test
{
int func(const double& a, int&& b) && noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}

TEST_CASE("const rvalref", "[trait/signature]")
{
struct test
{
int func(const double& a, int&& b) const&& noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}

TEST_CASE("volatile rvalref", "[trait/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile&& noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}

TEST_CASE("const volatile rvalref", "[trait/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile&& noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}

TEST_CASE("noexcept rvalref", "[trait/signature]")
{
struct test
{
int func(const double& a, int&& b) && noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}

TEST_CASE("const noexcept rvalref", "[trait/signature]")
{
struct test
{
int func(const double& a, int&& b) const&& noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}

TEST_CASE("volatile noexcept rvalref", "[trait/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile&& noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}

TEST_CASE("const volatile noexcept rvalref", "[trait/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile&& noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}

// NOLINTEND(*cognitive-complexity*)

diff --git a/ test/source/type_traits/remove_const.cpp b/ test/source/type_traits/remove_const.cpp

@@ -1,37 +0,0 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include <catch2/catch_test_macros.hpp>

#include "based/concepts/is/same.hpp"
#include "based/type_traits/remove/const.hpp"

using based::SameAs;

TEST_CASE("remove_const", "[type_traits/remove/remove_const]")
{
// NOLINTBEGIN(*array*)
// clang-format off
STATIC_REQUIRE(SameAs<based::remove_const_t<int>, int>);
STATIC_REQUIRE(SameAs<based::remove_const_t<int&>, int&>);
STATIC_REQUIRE(SameAs<based::remove_const_t<int&&>, int&&>);
STATIC_REQUIRE(SameAs<based::remove_const_t<int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<int(&)[2]>, int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<int(&&)[2]>, int(&&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const int>, int>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const int&>, const int&>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const int(&)[2]>, const int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<int(int)>, int(int)>);
STATIC_REQUIRE(SameAs<based::remove_const_t<volatile int>, volatile int>);
STATIC_REQUIRE(SameAs<based::remove_const_t<volatile int&>, volatile int&>);
STATIC_REQUIRE(SameAs<based::remove_const_t<volatile int&&>, volatile int&&>);
STATIC_REQUIRE(SameAs<based::remove_const_t<volatile int[2]>, volatile int[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<volatile int(&)[2]>, volatile int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<volatile int(&&)[2]>, volatile int(&&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const volatile int>, volatile int>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const volatile int&>, volatile const int&>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const volatile int[2]>, volatile int[2]>);
STATIC_REQUIRE(SameAs<based::remove_const_t<const volatile int(&)[2]>, volatile const int(&)[2]>);
// clang-format on
// NOLINTEND(*array*)
}

diff --git a/ test/source/type_traits/remove_cv.cpp b/ test/source/type_traits/remove_cv.cpp

@@ -1,37 +0,0 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include <catch2/catch_test_macros.hpp>

#include "based/concepts/is/same.hpp"
#include "based/type_traits/remove/cv.hpp"

using based::SameAs;

TEST_CASE("remove_cv", "[type_traits/remove_cv]")
{
// NOLINTBEGIN(*array*)
// clang-format off
STATIC_REQUIRE(SameAs<based::remove_cv_t<int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<int&>, int&>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<int&&>, int&&>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<int(&)[2]>, int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<int(&&)[2]>, int(&&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const int&>, const int&>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const int(&)[2]>, const int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<int(int)>, int(int)>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<volatile int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<volatile int&>, volatile int&>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<volatile int&&>, volatile int&&>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<volatile int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<volatile int(&)[2]>, volatile int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<volatile int(&&)[2]>, volatile int(&&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const volatile int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const volatile int&>, volatile const int&>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const volatile int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cv_t<const volatile int(&)[2]>, volatile const int(&)[2]>);
// clang-format on
// NOLINTEND(*array*)
}

diff --git a/ test/source/type_traits/remove_cvref.cpp b/ test/source/type_traits/remove_cvref.cpp

@@ -1,37 +0,0 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include <catch2/catch_test_macros.hpp>

#include "based/concepts/is/same.hpp"
#include "based/type_traits/remove/cvref.hpp"

using based::SameAs;

TEST_CASE("remove_cvref", "[type_traits/remove_cvref]")
{
// NOLINTBEGIN(*array*)
// clang-format off
STATIC_REQUIRE(SameAs<based::remove_cvref_t<int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<int&>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<int&&>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<int(&)[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<int(&&)[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const int&>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const int(&)[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<int(int)>, int(int)>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<volatile int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<volatile int&>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<volatile int&&>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<volatile int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<volatile int(&)[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<volatile int(&&)[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const volatile int>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const volatile int&>, int>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const volatile int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_cvref_t<const volatile int(&)[2]>, int[2]>);
// clang-format on
// NOLINTEND(*array*)
}

diff --git a/ test/source/type_traits/remove_pointer.cpp b/ test/source/type_traits/remove_pointer.cpp

@@ -1,22 +0,0 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include <catch2/catch_test_macros.hpp>

#include "based/concepts/is/same.hpp"
#include "based/type_traits/remove/pointer.hpp"

using based::SameAs;

TEST_CASE("remove_pointer", "[type_traits/remove_pointer]")
{
// NOLINTBEGIN(*array*)
// clang-format off
STATIC_REQUIRE(SameAs<based::remove_pointer_t<int>, int>);
STATIC_REQUIRE(SameAs<based::remove_pointer_t<int*>, int>);
STATIC_REQUIRE(SameAs<based::remove_pointer_t<int**>, int*>);
STATIC_REQUIRE(SameAs<based::remove_pointer_t<int* const>, int>);
STATIC_REQUIRE(SameAs<based::remove_pointer_t<int* volatile>, int>);
STATIC_REQUIRE(SameAs<based::remove_pointer_t<int* const volatile>, int>);
// clang-format on
// NOLINTEND(*array*)
}

diff --git a/ test/source/type_traits/remove_reference.cpp b/ test/source/type_traits/remove_reference.cpp

@@ -1,37 +0,0 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include <catch2/catch_test_macros.hpp>

#include "based/concepts/is/same.hpp"
#include "based/type_traits/remove/reference.hpp"

using based::SameAs;

TEST_CASE("remove_reference", "[type_traits/remove_reference]")
{
// NOLINTBEGIN(*array*)
// clang-format off
STATIC_REQUIRE(SameAs<based::remove_reference_t<int>, int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<int&>, int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<int&&>, int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<int(&)[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<int(&&)[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const int>, const int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const int&>, const int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const int[2]>, const int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const int(&)[2]>, const int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<int(int)>, int(int)>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<volatile int>,volatile int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<volatile int&>, volatile int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<volatile int&&>, volatile int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<volatile int[2]>, volatile int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<volatile int(&)[2]>, volatile int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<volatile int(&&)[2]>, volatile int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const volatile int>, const volatile int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const volatile int&>, volatile const int>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const volatile int[2]>, const volatile int[2]>);
STATIC_REQUIRE(SameAs<based::remove_reference_t<const volatile int(&)[2]>, volatile const int[2]>);
// clang-format on
// NOLINTEND(*array*)
}

diff --git a/ test/source/type_traits/remove_volatile.cpp b/ test/source/type_traits/remove_volatile.cpp

@@ -1,37 +0,0 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include <catch2/catch_test_macros.hpp>

#include "based/concepts/is/same.hpp"
#include "based/type_traits/remove/volatile.hpp"

using based::SameAs;

TEST_CASE("remove_volatile", "[type_traits/remove/remove_volatile]")
{
// NOLINTBEGIN(*array*)
// clang-format off
STATIC_REQUIRE(SameAs<based::remove_volatile_t<int>, int>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<int&>, int&>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<int&&>, int&&>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<int(&)[2]>, int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<int(&&)[2]>, int(&&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const int>, const int>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const int&>, const int&>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const int[2]>, const int[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const int(&)[2]>, const int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<int(int)>, int(int)>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<volatile int>, int>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<volatile int&>, volatile int&>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<volatile int&&>, volatile int&&>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<volatile int[2]>, int[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<volatile int(&)[2]>, volatile int(&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<volatile int(&&)[2]>, volatile int(&&)[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const volatile int>, const int>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const volatile int&>, volatile const int&>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const volatile int[2]>, const int[2]>);
STATIC_REQUIRE(SameAs<based::remove_volatile_t<const volatile int(&)[2]>, volatile const int(&)[2]>);
// clang-format on
// NOLINTEND(*array*)
}

diff --git a/ test/source/type_traits/signature_test.cpp b/ test/source/type_traits/signature_test.cpp

@@ -1,480 +0,0 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include "based/type_traits/signature.hpp"

#include <catch2/catch_test_macros.hpp>

#include "based/concepts/is/same.hpp"

// NOLINTBEGIN(*cognitive-complexity*)

namespace
{

// NOLINTNEXTLINE (*needed*)
int free_func(const double& a, int&& b) noexcept(false)
{
return static_cast<int>(a + b);
}

// NOLINTNEXTLINE (*needed*)
int free_func_noexcept(const double& a, int&& b) noexcept(true)
{
return static_cast<int>(a + b);
}

} // namespace

using based::SameAs;

TEST_CASE("free function", "[type_traits/signature]")
{
using sig = based::signature<decltype(free_func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}

TEST_CASE("free function noexcept", "[type_traits/signature]")
{
using sig = based::signature<decltype(free_func_noexcept)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}

TEST_CASE("empty", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}

TEST_CASE("const", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}

TEST_CASE("volatile", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}

TEST_CASE("const volatile", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}

TEST_CASE("noexcept", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}

TEST_CASE("const noexcept", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}

TEST_CASE("volatile noexcept", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}

TEST_CASE("const volatile noexcept", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}

TEST_CASE("lvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) & noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}

TEST_CASE("const lvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const& noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}

TEST_CASE("volatile lvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile& noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}

TEST_CASE("const volatile lvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile& noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}

TEST_CASE("noexcept lvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) & noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}

TEST_CASE("const noexcept lvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const& noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}

TEST_CASE("volatile noexcept lvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile& noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}

TEST_CASE("const volatile noexcept lvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile& noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}

TEST_CASE("rvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) && noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}

TEST_CASE("const rvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const&& noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}

TEST_CASE("volatile rvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile&& noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}

TEST_CASE("const volatile rvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile&& noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::noexcept_val>);
}

TEST_CASE("noexcept rvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) && noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}

TEST_CASE("const noexcept rvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const&& noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}

TEST_CASE("volatile noexcept rvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile&& noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::false_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}

TEST_CASE("const volatile noexcept rvalref", "[type_traits/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile&& noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(SameAs<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(SameAs<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(SameAs<int, sig::ret_type>);
STATIC_REQUIRE(SameAs<based::true_type, sig::const_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::volatile_val>);
STATIC_REQUIRE(SameAs<based::false_type, sig::lvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::rvalref_val>);
STATIC_REQUIRE(SameAs<based::true_type, sig::noexcept_val>);
}

// NOLINTEND(*cognitive-complexity*)