based

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

commit 1a6c111687493524bdc0a76890662e8db9dba621
parent 951e89cdfcbc8e30c2a3535bf33de7ec1439e3bd
author Dimitrije Dobrota < mail@dimitrijedobrota.com >
date Thu, 19 Jun 2025 14:12:53 +0200

Improve header naming consistency

Diffstat:
A include/based/algorithm/clamp.hpp | ++++++++++++++++++++++++++++++++++++++++++++++
A include/based/algorithm/max.hpp | +++++++++++++++++++++++++++++++++++
A include/based/algorithm/min.hpp | ++++++++++++++++++++++++++++++++++
D include/based/algorithms/clamp.hpp | ----------------------------------------------
D include/based/algorithms/max.hpp | -----------------------------------
D include/based/algorithms/min.hpp | ----------------------------------
D include/based/assert.hpp | ------------------------
D include/based/char/character.hpp | --------------------------------------------------
D include/based/char/is/alnum.hpp | ---------------
D include/based/char/is/alpha.hpp | ---------------
D include/based/char/is/alpha_lower.hpp | -------------
D include/based/char/is/alpha_upper.hpp | -------------
D include/based/char/is/digit.hpp | --------------
D include/based/char/is/xdigit.hpp | --------------
D include/based/char/mapper.hpp | -------------------------------------------------------------------
A include/based/character/format.hpp | +++++++++++++++++++++++++
A include/based/character/is/alnum.hpp | +++++++++++++++
A include/based/character/is/alpha.hpp | +++++++++++++++
A include/based/character/is/alpha_lower.hpp | +++++++++++++
A include/based/character/is/alpha_upper.hpp | +++++++++++++
A include/based/character/is/digit.hpp | ++++++++++++++
A include/based/character/is/xdigit.hpp | ++++++++++++++
A include/based/character/mapper.hpp | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A include/based/character/type.hpp | ++++++++++++++++++++++++++++++++++++++++++++++++++
A include/based/concept/callable.hpp | ++++++++++++++++++++++++++++++++++++++++
A include/based/concept/comparable/equal.hpp | +++++++++++++++++++++
A include/based/concept/comparable/equality.hpp | +++++++++++++++++++
A include/based/concept/comparable/greater.hpp | +++++++++++++++++++++
A include/based/concept/comparable/greater_equal.hpp | +++++++++++++++++++++
A include/based/concept/comparable/less.hpp | +++++++++++++++++++++
A include/based/concept/comparable/less_equal.hpp | +++++++++++++++++++++
A include/based/concept/comparable/not_equal.hpp | +++++++++++++++++++++
A include/based/concept/is/castable.hpp | +++++++++++
A include/based/concept/is/convertable.hpp | +++++++++++++++
A include/based/concept/is/enum.hpp | +++++++++++++++++++++++++++
A include/based/concept/is/invocable.hpp | +++++++++++
A include/based/concept/is/regular.hpp | ++++++++++++++++
A include/based/concept/is/same.hpp | +++++++++++++++
A include/based/concept/is/semiregular.hpp | ++++++++++++++++
A include/based/concept/iterator.hpp | +++++++++++++++++++++++++++++++++++++++++++++++++++
A include/based/concept/ordered/totally.hpp | +++++++++++++++++++++++++
A include/based/concept/procedure/domain.hpp | ++++++++++++++++++++++++++++++++++++++++
A include/based/concept/procedure/function.hpp | ++++++++++++++++++++++++++++
A include/based/concept/procedure/function_iter.hpp | +++++++++++++++++++++++++++
A include/based/concept/procedure/operation.hpp | +++++++++++++++++++++++
A include/based/concept/procedure/operation_iter.hpp | +++++++++++++++++++++
A include/based/concept/procedure/predicate.hpp | ++++++++++++++++++++++++++
A include/based/concept/procedure/predicate_iter.hpp | +++++++++++++++++++++++++++++++++
A include/based/concept/procedure/procedure.hpp | ++++++++++++++++++++++++++++++++++++++++++++++++
A include/based/concept/procedure/procedure_iter.hpp | +++++++++++++++++++++++++++
D include/based/concepts/callable.hpp | ----------------------------------------
D include/based/concepts/comparable/equal.hpp | ---------------------
D include/based/concepts/comparable/equality.hpp | -------------------
D include/based/concepts/comparable/greater.hpp | ---------------------
D include/based/concepts/comparable/greater_equal.hpp | ---------------------
D include/based/concepts/comparable/less.hpp | ---------------------
D include/based/concepts/comparable/less_equal.hpp | ---------------------
D include/based/concepts/comparable/not_equal.hpp | ---------------------
D include/based/concepts/is/castable.hpp | -----------
D include/based/concepts/is/convertable.hpp | ---------------
D include/based/concepts/is/enum.hpp | ---------------------------
D include/based/concepts/is/invocable.hpp | -----------
D include/based/concepts/is/regular.hpp | ----------------
D include/based/concepts/is/same.hpp | ---------------
D include/based/concepts/is/semiregular.hpp | ----------------
D include/based/concepts/iterator.hpp | ---------------------------------------------------
D include/based/concepts/ordered/totally.hpp | -------------------------
D include/based/concepts/procedure/domain.hpp | ----------------------------------------
D include/based/concepts/procedure/function.hpp | ----------------------------
D include/based/concepts/procedure/function_iter.hpp | ---------------------------
D include/based/concepts/procedure/operation.hpp | -----------------------
D include/based/concepts/procedure/operation_iter.hpp | ---------------------
D include/based/concepts/procedure/predicate.hpp | --------------------------
D include/based/concepts/procedure/predicate_iter.hpp | ---------------------------------
D include/based/concepts/procedure/procedure.hpp | ------------------------------------------------
D include/based/concepts/procedure/procedure_iter.hpp | ---------------------------
M include/based/container/array.hpp | + -
A include/based/container/list.hpp | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
M include/based/enum/enum.hpp | +++ ---
D include/based/format.hpp | ---------------------------------------------------------------------------------
M include/based/functional/function.hpp | ++ --
M include/based/functional/predicate/complement.hpp | + -
M include/based/functional/predicate/complement_of_converse.hpp | + -
M include/based/functional/predicate/converse.hpp | + -
M include/based/instrumentation/instrumented.hpp | + -
M include/based/instrumentation/registry.hpp | + -
M include/based/instrumentation/table.hpp | + -
A include/based/integral/format.hpp | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A include/based/integral/literals.hpp | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A include/based/integral/strong.hpp | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A include/based/integral/types.hpp | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
D include/based/list.hpp | ---------------------------------------------------------------------------------
A include/based/memory/nullptr.hpp | ++++++++
M include/based/string/format.hpp | + -
M include/based/trait/is/array.hpp | + -
M include/based/trait/is/null_pointer.hpp | + -
M include/based/trait/iterator.hpp | + -
M include/based/trait/remove/extent.hpp | + -
D include/based/types/builder.hpp | ---------------------------------------------------------------------------------
D include/based/types/literals.hpp | ----------------------------------------------------------------------------
D include/based/types/nullptr.hpp | --------
D include/based/types/strong.hpp | ---------------------------------------------------------------------------------
D include/based/types/types.hpp | ---------------------------------------------------------------------------------
A include/based/utility/assert.hpp | ++++++++++++++++++++++++
M include/based/utility/buffer.hpp | + -
M test/CMakeLists.txt | ++++++++++++++ ---------------
A test/source/algorithm/max_test.cpp | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A test/source/algorithm/min_test.cpp | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
D test/source/algorithms/max_test.cpp | ---------------------------------------------------------------------------------
D test/source/algorithms/min_test.cpp | ---------------------------------------------------------------------------------
D test/source/char/mapper_test.cpp | -------------------
A test/source/character/mapper_test.cpp | +++++++++++++++++++
A test/source/concept/callable_test.cpp | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
D test/source/concepts/callable_test.cpp | ------------------------------------------------------------
A test/source/container/list_test.cpp | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
M test/source/enum/bitmask_test.cpp | ++ --
M test/source/enum/standard_test.cpp | ++ --
A test/source/integral/limits_test.cpp | +++++++++++++++++++++++++++++++++
A test/source/integral/literals_test.cpp | +++++++++++++++++++++++++++++++++++++++++
A test/source/integral/strong_type_test.cpp | +++++++++++++++++++++++++++++++++++++++++
A test/source/integral/type_test.cpp | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
D test/source/list_test.cpp | ---------------------------------------------------------------------------------
M test/source/string/literal_test.cpp | ++++++++ --------
M test/source/trait/invoke_result_test.cpp | + -
M test/source/trait/remove_const_test.cpp | + -
M test/source/trait/remove_cv_test.cpp | + -
M test/source/trait/remove_cvref_test.cpp | + -
M test/source/trait/remove_pointer_test.cpp | + -
M test/source/trait/remove_reference_test.cpp | + -
M test/source/trait/remove_volatile_test.cpp | + -
M test/source/trait/signature_test_test.cpp | + -
D test/source/types/limits.cpp | ---------------------------------
D test/source/types/literals.cpp | -----------------------------------------
D test/source/types/strong_type_test.cpp | -----------------------------------------
D test/source/types/type_test.cpp | ---------------------------------------------------------------------------------
M test/source/utility/buffer_test.cpp | + -

136 files changed, 3904 insertions(+), 4200 deletions(-)


diff --git a/ include/based/algorithm/clamp.hpp b/ include/based/algorithm/clamp.hpp

@@ -0,0 +1,46 @@

#pragma once

#include "based/algorithm/max.hpp"
#include "based/algorithm/min.hpp"
#include "based/concept/is/regular.hpp"
#include "based/concept/is/same.hpp"
#include "based/concept/procedure/procedure.hpp"
#include "based/trait/remove/reference.hpp"
#include "based/utility/forward.hpp"

namespace based
{

// clamp a value between low and high
template<
BareRegular T,
BareRegular U,
BareRegular V,
RegularProcedure<bool, T, T> Rel>
requires(BareSameAs<T, U> && BareSameAs<T, V>)
constexpr decltype(auto) clamp(T&& value, U&& low, V&& high, Rel rel)
{
return based::max(
based::forward<U>(low),
based::min(based::forward<V>(high), based::forward<T>(value), rel),
rel
);
}

// clamp a value between low and high
template<BareRegular T, BareRegular U, BareRegular V>
requires(BareSameAs<T, U> && BareSameAs<T, V>)
constexpr decltype(auto) clamp(T&& value, U&& low, V&& high)
{
return based::clamp(
based::forward<T>(value),
based::forward<U>(low),
based::forward<V>(high),
[](const remove_reference_t<T>& llhs, const remove_reference_t<U>& lrhs)
{
return llhs < lrhs;
}
);
}

} // namespace based

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

@@ -0,0 +1,35 @@

#pragma once

#include "based/concept/is/regular.hpp"
#include "based/concept/is/same.hpp"
#include "based/concept/procedure/procedure.hpp"
#include "based/trait/remove/reference.hpp"
#include "based/utility/forward.hpp"

namespace based
{

// returns max element, second if equal
template<BareRegular T, BareRegular U, RegularProcedure<bool, T, T> Rel>
requires BareSameAs<T, U>
constexpr decltype(auto) max(T&& lhs, U&& rhs, Rel rel)
{
return rel(rhs, lhs) ? based::forward<T>(lhs) : based::forward<U>(rhs);
}

// returns max element, second if equal
template<BareRegular T, BareRegular U>
requires BareSameAs<T, U>
constexpr decltype(auto) max(T&& lhs, U&& rhs)
{
return based::max(
based::forward<T>(lhs),
based::forward<U>(rhs),
[](const remove_reference_t<T>& llhs, const remove_reference_t<U>& lrhs)
{
return llhs < lrhs;
}
);
}

} // namespace based

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

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

#pragma once

#include "based/concept/is/regular.hpp"
#include "based/concept/is/same.hpp"
#include "based/concept/procedure/procedure.hpp"
#include "based/trait/remove/reference.hpp"
#include "based/utility/forward.hpp"

namespace based
{

template<BareRegular T, BareRegular U, RegularProcedure<bool, T, T> Rel>
requires BareSameAs<T, U>
constexpr decltype(auto) min(T&& lhs, U&& rhs, Rel rel)
{
return rel(rhs, lhs) ? based::forward<U>(rhs) : based::forward<T>(lhs);
}

// returns min element, first if equal
template<BareRegular T, BareRegular U>
requires BareSameAs<T, U>
constexpr decltype(auto) min(T&& lhs, U&& rhs)
{
return based::min(
based::forward<T>(lhs),
based::forward<U>(rhs),
[](const remove_reference_t<T>& llhs, const remove_reference_t<U>& lrhs)
{
return llhs < lrhs;
}
);
}

} // namespace based

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

@@ -1,46 +0,0 @@

#pragma once

#include "based/algorithms/max.hpp"
#include "based/algorithms/min.hpp"
#include "based/concepts/is/regular.hpp"
#include "based/concepts/is/same.hpp"
#include "based/concepts/procedure/procedure.hpp"
#include "based/trait/remove/reference.hpp"
#include "based/utility/forward.hpp"

namespace based
{

// clamp a value between low and high
template<
BareRegular T,
BareRegular U,
BareRegular V,
RegularProcedure<bool, T, T> Rel>
requires(BareSameAs<T, U> && BareSameAs<T, V>)
constexpr decltype(auto) clamp(T&& value, U&& low, V&& high, Rel rel)
{
return based::max(
based::forward<U>(low),
based::min(based::forward<V>(high), based::forward<T>(value), rel),
rel
);
}

// clamp a value between low and high
template<BareRegular T, BareRegular U, BareRegular V>
requires(BareSameAs<T, U> && BareSameAs<T, V>)
constexpr decltype(auto) clamp(T&& value, U&& low, V&& high)
{
return based::clamp(
based::forward<T>(value),
based::forward<U>(low),
based::forward<V>(high),
[](const remove_reference_t<T>& llhs, const remove_reference_t<U>& lrhs)
{
return llhs < lrhs;
}
);
}

} // namespace based

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

@@ -1,35 +0,0 @@

#pragma once

#include "based/concepts/is/regular.hpp"
#include "based/concepts/is/same.hpp"
#include "based/concepts/procedure/procedure.hpp"
#include "based/trait/remove/reference.hpp"
#include "based/utility/forward.hpp"

namespace based
{

// returns max element, second if equal
template<BareRegular T, BareRegular U, RegularProcedure<bool, T, T> Rel>
requires BareSameAs<T, U>
constexpr decltype(auto) max(T&& lhs, U&& rhs, Rel rel)
{
return rel(rhs, lhs) ? based::forward<T>(lhs) : based::forward<U>(rhs);
}

// returns max element, second if equal
template<BareRegular T, BareRegular U>
requires BareSameAs<T, U>
constexpr decltype(auto) max(T&& lhs, U&& rhs)
{
return based::max(
based::forward<T>(lhs),
based::forward<U>(rhs),
[](const remove_reference_t<T>& llhs, const remove_reference_t<U>& lrhs)
{
return llhs < lrhs;
}
);
}

} // namespace based

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

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

#pragma once

#include "based/concepts/is/regular.hpp"
#include "based/concepts/is/same.hpp"
#include "based/concepts/procedure/procedure.hpp"
#include "based/trait/remove/reference.hpp"
#include "based/utility/forward.hpp"

namespace based
{

template<BareRegular T, BareRegular U, RegularProcedure<bool, T, T> Rel>
requires BareSameAs<T, U>
constexpr decltype(auto) min(T&& lhs, U&& rhs, Rel rel)
{
return rel(rhs, lhs) ? based::forward<U>(rhs) : based::forward<T>(lhs);
}

// returns min element, first if equal
template<BareRegular T, BareRegular U>
requires BareSameAs<T, U>
constexpr decltype(auto) min(T&& lhs, U&& rhs)
{
return based::min(
based::forward<T>(lhs),
based::forward<U>(rhs),
[](const remove_reference_t<T>& llhs, const remove_reference_t<U>& lrhs)
{
return llhs < lrhs;
}
);
}

} // namespace based

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

@@ -1,24 +0,0 @@

#pragma once

#include <cassert>

#define BASED_ASSERT assert

/*
#ifdef NDEBUG
# define BASED_ASSERT(EX)
#else
# define BASED_ASSERT(EX) \
(void)((EX) || (based::detail::assert(#EX, __FILE__, __LINE__), 0))
#endif

namespace based::detail
{

[[noreturn]] constexpr void assert(const char* msg, const char* file, int line)
{
throw "assertion failsed";
}

} // namespace based::detail
*/

diff --git a/ include/based/char/character.hpp b/ include/based/char/character.hpp

@@ -1,50 +0,0 @@

#pragma once

#include "based/types/types.hpp"

namespace based
{

struct character : public strong_type<char, character>
{
using strong_type::strong_type;
using strong_type::operator=;

constexpr character(char chr) // NOLINT(*explicit*)
: strong_type(chr)
{
}

explicit constexpr character(u8 ord)
: strong_type(static_cast<char>(ord.value))
{
}

[[nodiscard]] char chr() const { return value; }
[[nodiscard]] u8 ord() const { return u8::underlying_cast(value); }

friend constexpr bool operator==(character lhs, char rhs)
{
return lhs.value == rhs;
}

friend constexpr bool operator==(char lhs, character rhs)
{
return lhs == rhs.value;
}

friend constexpr auto operator<=>(character lhs, char rhs)
{
return lhs.value <=> rhs;
}

friend constexpr auto operator<=>(char lhs, character rhs)
{
return lhs <=> rhs.value;
}
};

auto compare(character, character) -> bool;
auto order(character, character) -> bool;

} // namespace based

diff --git a/ include/based/char/is/alnum.hpp b/ include/based/char/is/alnum.hpp

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

#pragma once

#include "based/char/character.hpp"
#include "based/char/is/alpha.hpp"
#include "based/char/is/digit.hpp"

namespace based
{

constexpr bool is_alnum(character chr)
{
return is_alpha(chr) || is_digit(chr);
}

} // namespace based

diff --git a/ include/based/char/is/alpha.hpp b/ include/based/char/is/alpha.hpp

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

#pragma once

#include "based/char/character.hpp"
#include "based/char/is/alpha_lower.hpp"
#include "based/char/is/alpha_upper.hpp"

namespace based
{

constexpr bool is_alpha(character chr)
{
return is_alpha_lower(chr) || is_alpha_upper(chr);
}

} // namespace based

diff --git a/ include/based/char/is/alpha_lower.hpp b/ include/based/char/is/alpha_lower.hpp

@@ -1,13 +0,0 @@

#pragma once

#include "based/char/character.hpp"

namespace based
{

constexpr bool is_alpha_lower(character chr)
{
return chr >= 'a' && chr <= 'z';
}

} // namespace based

diff --git a/ include/based/char/is/alpha_upper.hpp b/ include/based/char/is/alpha_upper.hpp

@@ -1,13 +0,0 @@

#pragma once

#include "based/char/character.hpp"

namespace based
{

constexpr bool is_alpha_upper(character chr)
{
return chr >= 'A' && chr <= 'Z';
}

} // namespace based

diff --git a/ include/based/char/is/digit.hpp b/ include/based/char/is/digit.hpp

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

#pragma once

#include "based/char/character.hpp"

namespace based
{

constexpr bool is_digit(character chr)
{
return chr >= '0' && chr <= '9';
}

} // namespace based

diff --git a/ include/based/char/is/xdigit.hpp b/ include/based/char/is/xdigit.hpp

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

#pragma once

#include "based/char/character.hpp"

namespace based
{

constexpr bool is_xdigit(character chr)
{
return (chr >= 'a' && chr <= 'f') || (chr >= 'A' && chr <= 'F')
|| (chr >= '0' && chr <= '9');
}

} // namespace based

diff --git a/ include/based/char/mapper.hpp b/ include/based/char/mapper.hpp

@@ -1,67 +0,0 @@

#pragma once

#include "based/char/character.hpp"
#include "based/concepts/procedure/predicate.hpp"
#include "based/container/array.hpp"
#include "based/types/literals.hpp"

namespace based
{

template<Predicate<character> Predicate>
class mapper
{
static constexpr auto size = limits<u8>::max;
using mapped_type = u8;

static constexpr Predicate m_predicate = {};

using direct_t = array<mapped_type, u8, size>;
static constexpr direct_t direct = []
{
direct_t res = {};

mapped_type count = 0_u8;
for (auto idx = 0_u8; idx < size; idx++) {
if (m_predicate(character::cast(idx))) {
res[idx] = count++;
}
}

return res;
}();

static constexpr const u8 count = []
{
mapped_type count = 0_u8;
for (auto idx = 0_u8; idx < size; idx++) {
if (m_predicate(character::cast(idx))) {
count++;
}
}
return count;
}();

using reverse_t = array<character, u8, count>;
static constexpr reverse_t reverse = []
{
reverse_t res = {};

mapped_type count = 0_u8;
for (auto idx = 0_u8; idx < size; idx++) {
const auto chr = character::cast(idx);
if (m_predicate(chr)) {
res[count++] = chr;
}
}

return res;
}();

public:
static constexpr bool predicate(character chr) { return m_predicate(chr); }
static constexpr character map(mapped_type value) { return reverse[value]; }
static constexpr mapped_type map(character chr) { return direct[chr.ord()]; }
};

} // namespace based

diff --git a/ include/based/character/format.hpp b/ include/based/character/format.hpp

@@ -0,0 +1,25 @@

#pragma once

#include <format>
#include <ostream>

#include "based/character/type.hpp"

template<>
struct std::formatter<based::character>
{
static constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin();
}

static auto format(based::character value, std::format_context& ctx)
{
return std::format_to(ctx.out(), "{}", value.chr());
}
};

inline std::ostream& operator<<(std::ostream& ost, based::character value)
{
return ost << value.chr();
}

diff --git a/ include/based/character/is/alnum.hpp b/ include/based/character/is/alnum.hpp

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

#pragma once

#include "based/character/type.hpp"
#include "based/character/is/alpha.hpp"
#include "based/character/is/digit.hpp"

namespace based
{

constexpr bool is_alnum(character chr)
{
return is_alpha(chr) || is_digit(chr);
}

} // namespace based

diff --git a/ include/based/character/is/alpha.hpp b/ include/based/character/is/alpha.hpp

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

#pragma once

#include "based/character/type.hpp"
#include "based/character/is/alpha_lower.hpp"
#include "based/character/is/alpha_upper.hpp"

namespace based
{

constexpr bool is_alpha(character chr)
{
return is_alpha_lower(chr) || is_alpha_upper(chr);
}

} // namespace based

diff --git a/ include/based/character/is/alpha_lower.hpp b/ include/based/character/is/alpha_lower.hpp

@@ -0,0 +1,13 @@

#pragma once

#include "based/character/type.hpp"

namespace based
{

constexpr bool is_alpha_lower(character chr)
{
return chr >= 'a' && chr <= 'z';
}

} // namespace based

diff --git a/ include/based/character/is/alpha_upper.hpp b/ include/based/character/is/alpha_upper.hpp

@@ -0,0 +1,13 @@

#pragma once

#include "based/character/type.hpp"

namespace based
{

constexpr bool is_alpha_upper(character chr)
{
return chr >= 'A' && chr <= 'Z';
}

} // namespace based

diff --git a/ include/based/character/is/digit.hpp b/ include/based/character/is/digit.hpp

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

#pragma once

#include "based/character/type.hpp"

namespace based
{

constexpr bool is_digit(character chr)
{
return chr >= '0' && chr <= '9';
}

} // namespace based

diff --git a/ include/based/character/is/xdigit.hpp b/ include/based/character/is/xdigit.hpp

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

#pragma once

#include "based/character/type.hpp"

namespace based
{

constexpr bool is_xdigit(character chr)
{
return (chr >= 'a' && chr <= 'f') || (chr >= 'A' && chr <= 'F')
|| (chr >= '0' && chr <= '9');
}

} // namespace based

diff --git a/ include/based/character/mapper.hpp b/ include/based/character/mapper.hpp

@@ -0,0 +1,67 @@

#pragma once

#include "based/character/type.hpp"
#include "based/concept/procedure/predicate.hpp"
#include "based/container/array.hpp"
#include "based/integral/literals.hpp"

namespace based
{

template<Predicate<character> Predicate>
class mapper
{
static constexpr auto size = limits<u8>::max;
using mapped_type = u8;

static constexpr Predicate m_predicate = {};

using direct_t = array<mapped_type, u8, size>;
static constexpr direct_t direct = []
{
direct_t res = {};

mapped_type count = 0_u8;
for (auto idx = 0_u8; idx < size; idx++) {
if (m_predicate(character::cast(idx))) {
res[idx] = count++;
}
}

return res;
}();

static constexpr const u8 count = []
{
mapped_type count = 0_u8;
for (auto idx = 0_u8; idx < size; idx++) {
if (m_predicate(character::cast(idx))) {
count++;
}
}
return count;
}();

using reverse_t = array<character, u8, count>;
static constexpr reverse_t reverse = []
{
reverse_t res = {};

mapped_type count = 0_u8;
for (auto idx = 0_u8; idx < size; idx++) {
const auto chr = character::cast(idx);
if (m_predicate(chr)) {
res[count++] = chr;
}
}

return res;
}();

public:
static constexpr bool predicate(character chr) { return m_predicate(chr); }
static constexpr character map(mapped_type value) { return reverse[value]; }
static constexpr mapped_type map(character chr) { return direct[chr.ord()]; }
};

} // namespace based

diff --git a/ include/based/character/type.hpp b/ include/based/character/type.hpp

@@ -0,0 +1,50 @@

#pragma once

#include "based/integral/types.hpp"

namespace based
{

struct character : public strong_type<char, character>
{
using strong_type::strong_type;
using strong_type::operator=;

constexpr character(char chr) // NOLINT(*explicit*)
: strong_type(chr)
{
}

explicit constexpr character(u8 ord)
: strong_type(static_cast<char>(ord.value))
{
}

[[nodiscard]] char chr() const { return value; }
[[nodiscard]] u8 ord() const { return u8::underlying_cast(value); }

friend constexpr bool operator==(character lhs, char rhs)
{
return lhs.value == rhs;
}

friend constexpr bool operator==(char lhs, character rhs)
{
return lhs == rhs.value;
}

friend constexpr auto operator<=>(character lhs, char rhs)
{
return lhs.value <=> rhs;
}

friend constexpr auto operator<=>(char lhs, character rhs)
{
return lhs <=> rhs.value;
}
};

auto compare(character, character) -> bool;
auto order(character, character) -> bool;

} // namespace based

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

@@ -0,0 +1,40 @@

#pragma once

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

namespace based
{

template<typename T>
struct callable;

template<typename T>
requires(std::is_function_v<T>)
struct callable<T> : public signature<std::decay_t<T>>
{
};

template<typename T>
requires(requires { &std::decay_t<T>::operator(); })
struct callable<T> : public signature<decltype(&T::operator())>
{
};

template<typename T>
requires(std::is_member_function_pointer_v<std::decay_t<T>>)
struct callable<T> : public signature<remove_pointer_t<T>>
{
};

template<typename T>
// concept Callable = is_instantiable_v<callable, T>;
concept Callable = true;

template<Callable T>
using callable_sig_t = typename callable<T>::signature::sig_type;

template<Callable T>
using callable_ret_t = typename callable<T>::signature::ret_type;

} // namespace based

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

@@ -0,0 +1,21 @@

#pragma once

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

namespace based
{

// clang-format off

template<typename T>
concept EqualComparable = requires(
const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs
) {
{ lhs == rhs } -> SameAs<bool>;
{ rhs == lhs } -> SameAs<bool>;
};

// clang-format on

} // namespace based

diff --git a/ include/based/concept/comparable/equality.hpp b/ include/based/concept/comparable/equality.hpp

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

#pragma once

#include "based/concept/comparable/equal.hpp"
#include "based/concept/comparable/not_equal.hpp"

namespace based
{

// clang-format off

template<typename T>
concept EqualityComparable = requires {
requires(EqualComparable<T>);
requires(NotEqualComparable<T>);
};

// clang-format on

} // namespace based

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

@@ -0,0 +1,21 @@

#pragma once

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

namespace based
{

// clang-format off

template<typename T>
concept GreaterComparable = requires
(const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs)
{
{lhs > rhs} -> SameAs<bool>;
{rhs > lhs} -> SameAs<bool>;
};

// clang-format on

} // namespace based

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

@@ -0,0 +1,21 @@

#pragma once

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

namespace based
{

// clang-format off

template<typename T>
concept LessEqualComparable = requires
(const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs)
{
{lhs <= rhs} -> SameAs<bool>;
{rhs <= lhs} -> SameAs<bool>;
};

// clang-format on

} // namespace based

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

@@ -0,0 +1,21 @@

#pragma once

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

namespace based
{

// clang-format off

template<typename T>
concept LessComparable = requires
(const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs)
{
{lhs < rhs} -> SameAs<bool>;
{rhs < lhs} -> SameAs<bool>;
};

// clang-format on

} // namespace based

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

@@ -0,0 +1,21 @@

#pragma once

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

namespace based
{

// clang-format off

template<typename T>
concept GreaterEqualComparable = requires
(const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs)
{
{lhs >= rhs} -> SameAs<bool>;
{rhs >= lhs} -> SameAs<bool>;
};

// clang-format on

} // namespace based

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

@@ -0,0 +1,21 @@

#pragma once

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

namespace based
{

// clang-format off

template<typename T>
concept NotEqualComparable = requires
(const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs)
{
{lhs != rhs} -> SameAs<bool>;
{rhs != lhs} -> SameAs<bool>;
};

// clang-format on

} // namespace based

diff --git a/ include/based/concept/is/castable.hpp b/ include/based/concept/is/castable.hpp

@@ -0,0 +1,11 @@

#pragma once

#include "based/utility/declvar.hpp"

namespace based
{

template<class From, class To>
concept CastableTo = requires { static_cast<To>(declval<From>()); };

} // namespace based

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

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

#pragma once

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

namespace based
{

template<class From, class To>
concept ConvertibleTo = requires {
requires(is_convertible_v<From, To>);
static_cast<To>(declval<From>());
};

} // namespace based

diff --git a/ include/based/concept/is/enum.hpp b/ include/based/concept/is/enum.hpp

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

#pragma once

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

namespace based
{

namespace detail
{

void test_conversion(...); // selected when E is complete and scoped
void test_conversion(int) = delete; // selected when E is complete and unscoped

} // namespace detail

template<class T>
concept IsEnum = is_enum_v<T>;

template<class T>
concept IsScopedEnum = requires {
requires(IsEnum<T>);
{
detail::test_conversion(T {})
};
};

} // namespace based

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

@@ -0,0 +1,11 @@

#pragma once

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

namespace based
{

template<typename P, typename... Args>
concept Invocable = is_invocable_v<P, Args...>;

} // namespace based

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

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

#pragma once

#include <concepts>

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

namespace based
{

template<typename T>
concept Regular = std::regular<T>;

template<typename T>
concept BareRegular = Regular<remove_cvref_t<T>>;

} // namespace based

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

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

#pragma once

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

namespace based
{

template<class T, class U>
concept SameAs = is_same_v<T, U> && is_same_v<U, T>;

template<class T, class U>
concept BareSameAs = SameAs<remove_cvref_t<T>, remove_cvref_t<U>>;

} // namespace based

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

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

#pragma once

#include <concepts>

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

namespace based
{

template<typename T>
concept Semiregular = std::semiregular<T>;

template<typename T>
concept BareSemiregular = Semiregular<remove_cvref_t<T>>;

} // namespace based

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

@@ -0,0 +1,51 @@

#pragma once

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

namespace based
{

// clang-format off

template<typename T>
concept Readable = requires(T val) {
requires(Regular<T>);
typename iter_value_t<T>;
{
*val
} -> BareSameAs<iter_value_t<T>>;
};

template<typename T>
concept Iterator = requires(T val) {
requires(Regular<T>);
typename iter_dist_t<T>;
{
++val
} -> BareSameAs<T>;
// successor is not necessarily regular
};

template<typename T>
concept ForwardIterator = requires {
requires(Iterator<T>);
// successor is regular
};

template<typename T>
concept ReadableIterator = requires {
requires(Iterator<T>);
requires(Readable<T>);
};

template<typename T>
concept ReadableForwardIterator = requires {
requires(ForwardIterator<T>);
requires(Readable<T>);
};

// clang-format on

} // namespace based

diff --git a/ include/based/concept/ordered/totally.hpp b/ include/based/concept/ordered/totally.hpp

@@ -0,0 +1,25 @@

#pragma once

#include "based/concept/comparable/equality.hpp"
#include "based/concept/comparable/greater.hpp"
#include "based/concept/comparable/greater_equal.hpp"
#include "based/concept/comparable/less.hpp"
#include "based/concept/comparable/less_equal.hpp"

namespace based
{

// clang-format off

template<typename T>
concept totally_ordered = requires {
requires(EqualityComparable<T>);
requires(LessComparable<T>);
requires(GreaterComparable<T>);
requires(LessEqualComparable<T>);
requires(GreaterEqualComparable<T>);
};

// clang-format on

} // namespace based

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

@@ -0,0 +1,40 @@

#pragma once

#include <tuple>

#include "based/concept/is/regular.hpp"
#include "based/concept/is/same.hpp"
#include "based/concept/is/semiregular.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/integral/types.hpp"

namespace based
{

template<typename T>
concept Input = SameAs<T, remove_cvref_t<remove_pointer_t<T>>>
|| is_const_v<remove_reference_t<T>> || is_const_v<remove_pointer_t<T>>;

template<size_t idx, typename... Args>
requires(idx < sizeof...(Args))
using elem_t = std::tuple_element_t<idx, std::tuple<Args...>>;

template<typename... Args>
concept SemiregularDomain = (Semiregular<remove_cvref_t<Args>> && ...);

template<typename... Args>
concept RegularDomain = (Regular<remove_cvref_t<Args>> && ...);

template<typename... Args>
concept InputDomain = (Input<Args> && ...);

template<typename... Args>
concept HomogeneousDomain = (SameAs<elem_t<0, Args...>, Args> && ...);

template<typename P, typename... Args>
using ret_t = std::invoke_result_t<P, Args...>;

} // namespace based

diff --git a/ include/based/concept/procedure/function.hpp b/ include/based/concept/procedure/function.hpp

@@ -0,0 +1,28 @@

#pragma once

#include "based/concept/procedure/domain.hpp"
#include "based/concept/procedure/procedure.hpp"

namespace based
{

template<typename P, typename Ret, typename... Args>
concept FunctionalProcedure = requires {
requires(RegularProcedure<P, Ret, Args...>);
requires(InputDomain<Args...>);
};

template<typename P, typename Ret, typename Arg>
concept UnaryFunction = requires {
requires(FunctionalProcedure<P, Ret, Arg>);
requires(UnaryProcedure<P, Ret, Arg>);
};

template<typename P, typename Ret, typename... Args>
concept HomogeneousFunction = requires {
requires(FunctionalProcedure<P, Ret, Args...>);
requires(sizeof...(Args) > 0);
requires(HomogeneousDomain<Args...>);
};

} // namespace based

diff --git a/ include/based/concept/procedure/function_iter.hpp b/ include/based/concept/procedure/function_iter.hpp

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

#pragma once

#include "based/concept/iterator.hpp"
#include "based/concept/procedure/function.hpp"

namespace based
{

template<typename P, typename Ret, typename I>
concept IterFunctionalProcedure = requires {
requires(Iterator<I>);
requires(FunctionalProcedure<P, Ret, iter_value_t<I>>);
};

template<typename P, typename Ret, typename I>
concept IterUnaryFunction = requires {
requires(Iterator<I>);
requires(UnaryFunction<P, Ret, iter_value_t<I>>);
};

template<typename P, typename Ret, typename I>
concept IterHomogeneousFunction = requires {
requires(Iterator<I>);
requires(HomogeneousFunction<P, Ret, iter_value_t<I>>);
};

} // namespace based

diff --git a/ include/based/concept/procedure/operation.hpp b/ include/based/concept/procedure/operation.hpp

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

#pragma once

#include "based/concept/procedure/function.hpp"

namespace based
{

template<typename P, typename... Args>
concept Operation = HomogeneousFunction<P, elem_t<0, Args...>, Args...>;

template<typename P, typename Ret, typename Arg>
concept Transformation = requires {
requires(Operation<P, Ret, Arg>);
requires(UnaryFunction<P, Ret, Arg>);
};

template<typename P, typename Arg>
concept BinaryOperation = Operation<P, Arg, Arg>;

template<typename P, typename Arg>
concept AssociativeBinaryOperation = Operation<P, Arg, Arg>;

} // namespace based

diff --git a/ include/based/concept/procedure/operation_iter.hpp b/ include/based/concept/procedure/operation_iter.hpp

@@ -0,0 +1,21 @@

#pragma once

#include "based/concept/iterator.hpp"
#include "based/concept/procedure/operation.hpp"

namespace based
{

template<typename P, typename Ret, typename... I>
concept IterOperation = requires {
requires(Iterator<I> && ...);
requires(Operation<P, iter_value_t<I>...>);
};

template<typename P, typename Ret, typename I>
concept IterBinaryOperation = requires {
requires(Iterator<I>);
requires(BinaryOperation<P, iter_value_t<I>>);
};

} // namespace based

diff --git a/ include/based/concept/procedure/predicate.hpp b/ include/based/concept/procedure/predicate.hpp

@@ -0,0 +1,26 @@

#pragma once

#include "based/concept/procedure/function.hpp"

namespace based
{

template<typename P, typename... Args>
concept Predicate = FunctionalProcedure<P, bool, Args...>;

template<typename P, typename... Args>
concept HomogeneousPredicate = requires {
requires(Predicate<P, Args...>);
requires(HomogeneousFunction<P, bool, Args...>);
};

template<typename P, typename Arg>
concept UnaryPredicate = requires {
requires(Predicate<P, Arg>);
requires(UnaryFunction<P, bool, Arg>);
};

template<typename P, typename Arg>
concept Relation = HomogeneousPredicate<P, Arg, Arg>;

} // namespace based

diff --git a/ include/based/concept/procedure/predicate_iter.hpp b/ include/based/concept/procedure/predicate_iter.hpp

@@ -0,0 +1,33 @@

#pragma once

#include "based/concept/iterator.hpp"
#include "based/concept/procedure/predicate.hpp"

namespace based
{

template<typename P, typename... I>
concept IterPredicate = requires {
requires(Iterator<I> && ...);
requires(Predicate<P, iter_value_t<I>...>);
};

template<typename P, typename... I>
concept IterHomogeneousPredicate = requires {
requires(Iterator<I> && ...);
requires(HomogeneousPredicate<P, iter_value_t<I>...>);
};

template<typename P, typename I>
concept IterUnaryPredicate = requires {
requires(Iterator<I>);
requires(UnaryPredicate<P, iter_value_t<I>>);
};

template<typename P, typename I>
concept IterRelation = requires {
requires(Iterator<I>);
requires(Relation<P, iter_value_t<I>>);
};

} // namespace based

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

@@ -0,0 +1,48 @@

#pragma once

#include "based/concept/is/convertable.hpp"
#include "based/concept/is/invocable.hpp"
#include "based/concept/is/regular.hpp"
#include "based/concept/procedure/domain.hpp"
#include "based/trait/integral_constant.hpp"
#include "based/trait/invoke_result.hpp"

namespace based
{

namespace detail
{

// clang-format off

template<typename P, typename Sig> struct procedure : public false_type {};

template<typename P, typename Ret, typename... Args>
requires (Invocable<P, Args...> && ConvertibleTo<invoke_result_t<P, Args...>, Ret>)
struct procedure<P, Ret(Args...)> : public true_type {};

template<typename P, typename... Args>
requires (Invocable<P, Args...>)
struct procedure<P, void(Args...)> : public true_type {};

template<typename P, typename Ret, typename... Args>
static constexpr bool procedure_v = procedure<P, Ret(Args...)>::value;

// clang-format on

} // namespace detail

template<typename P, typename Ret, typename... Args>
concept Procedure = detail::procedure_v<P, Ret, Args...>;

template<typename P, typename Ret, typename Arg>
concept UnaryProcedure = Procedure<P, Ret, Arg>;

template<typename P, typename Ret, typename... Args>
concept RegularProcedure = requires {
requires(Procedure<P, Ret, Args...>);
requires(RegularDomain<Args...>);
requires(Regular<ret_t<P, Args...>>);
};

} // namespace based

diff --git a/ include/based/concept/procedure/procedure_iter.hpp b/ include/based/concept/procedure/procedure_iter.hpp

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

#pragma once

#include "based/concept/iterator.hpp"
#include "based/concept/procedure/procedure.hpp"

namespace based
{

template<typename P, typename Ret, typename I>
concept IterProcedure = requires {
requires(Iterator<I>);
requires(Procedure<P, Ret, iter_value_t<I>>);
};

template<typename P, typename Ret, typename I>
concept IterUnaryProcedure = requires {
requires(Iterator<I>);
requires(UnaryProcedure<P, Ret, iter_value_t<I>>);
};

template<typename P, typename Ret, typename I>
concept IterRegularProcedure = requires {
requires(Iterator<I>);
requires(RegularProcedure<P, Ret, iter_value_t<I>>);
};

} // namespace based

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

@@ -1,40 +0,0 @@

#pragma once

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

namespace based
{

template<typename T>
struct callable;

template<typename T>
requires(std::is_function_v<T>)
struct callable<T> : public signature<std::decay_t<T>>
{
};

template<typename T>
requires(requires { &std::decay_t<T>::operator(); })
struct callable<T> : public signature<decltype(&T::operator())>
{
};

template<typename T>
requires(std::is_member_function_pointer_v<std::decay_t<T>>)
struct callable<T> : public signature<remove_pointer_t<T>>
{
};

template<typename T>
// concept Callable = is_instantiable_v<callable, T>;
concept Callable = true;

template<Callable T>
using callable_sig_t = typename callable<T>::signature::sig_type;

template<Callable T>
using callable_ret_t = typename callable<T>::signature::ret_type;

} // namespace based

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

@@ -1,21 +0,0 @@

#pragma once

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

namespace based
{

// clang-format off

template<typename T>
concept EqualComparable = requires(
const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs
) {
{ lhs == rhs } -> SameAs<bool>;
{ rhs == lhs } -> SameAs<bool>;
};

// clang-format on

} // namespace based

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

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

#pragma once

#include "based/concepts/comparable/equal.hpp"
#include "based/concepts/comparable/not_equal.hpp"

namespace based
{

// clang-format off

template<typename T>
concept EqualityComparable = requires {
requires(EqualComparable<T>);
requires(NotEqualComparable<T>);
};

// clang-format on

} // namespace based

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

@@ -1,21 +0,0 @@

#pragma once

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

namespace based
{

// clang-format off

template<typename T>
concept GreaterComparable = requires
(const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs)
{
{lhs > rhs} -> SameAs<bool>;
{rhs > lhs} -> SameAs<bool>;
};

// clang-format on

} // namespace based

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

@@ -1,21 +0,0 @@

#pragma once

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

namespace based
{

// clang-format off

template<typename T>
concept LessEqualComparable = requires
(const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs)
{
{lhs <= rhs} -> SameAs<bool>;
{rhs <= lhs} -> SameAs<bool>;
};

// clang-format on

} // namespace based

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

@@ -1,21 +0,0 @@

#pragma once

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

namespace based
{

// clang-format off

template<typename T>
concept LessComparable = requires
(const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs)
{
{lhs < rhs} -> SameAs<bool>;
{rhs < lhs} -> SameAs<bool>;
};

// clang-format on

} // namespace based

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

@@ -1,21 +0,0 @@

#pragma once

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

namespace based
{

// clang-format off

template<typename T>
concept GreaterEqualComparable = requires
(const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs)
{
{lhs >= rhs} -> SameAs<bool>;
{rhs >= lhs} -> SameAs<bool>;
};

// clang-format on

} // namespace based

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

@@ -1,21 +0,0 @@

#pragma once

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

namespace based
{

// clang-format off

template<typename T>
concept NotEqualComparable = requires
(const remove_reference_t<T>& lhs, const remove_reference_t<T>& rhs)
{
{lhs != rhs} -> SameAs<bool>;
{rhs != lhs} -> SameAs<bool>;
};

// clang-format on

} // namespace based

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

@@ -1,11 +0,0 @@

#pragma once

#include "based/utility/declvar.hpp"

namespace based
{

template<class From, class To>
concept CastableTo = requires { static_cast<To>(declval<From>()); };

} // namespace based

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

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

#pragma once

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

namespace based
{

template<class From, class To>
concept ConvertibleTo = requires {
requires(is_convertible_v<From, To>);
static_cast<To>(declval<From>());
};

} // namespace based

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

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

#pragma once

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

namespace based
{

namespace detail
{

void test_conversion(...); // selected when E is complete and scoped
void test_conversion(int) = delete; // selected when E is complete and unscoped

} // namespace detail

template<class T>
concept IsEnum = is_enum_v<T>;

template<class T>
concept IsScopedEnum = requires {
requires(IsEnum<T>);
{
detail::test_conversion(T {})
};
};

} // namespace based

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

@@ -1,11 +0,0 @@

#pragma once

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

namespace based
{

template<typename P, typename... Args>
concept Invocable = is_invocable_v<P, Args...>;

} // namespace based

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

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

#pragma once

#include <concepts>

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

namespace based
{

template<typename T>
concept Regular = std::regular<T>;

template<typename T>
concept BareRegular = Regular<remove_cvref_t<T>>;

} // namespace based

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

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

#pragma once

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

namespace based
{

template<class T, class U>
concept SameAs = is_same_v<T, U> && is_same_v<U, T>;

template<class T, class U>
concept BareSameAs = SameAs<remove_cvref_t<T>, remove_cvref_t<U>>;

} // namespace based

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

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

#pragma once

#include <concepts>

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

namespace based
{

template<typename T>
concept Semiregular = std::semiregular<T>;

template<typename T>
concept BareSemiregular = Semiregular<remove_cvref_t<T>>;

} // namespace based

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

@@ -1,51 +0,0 @@

#pragma once

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

namespace based
{

// clang-format off

template<typename T>
concept Readable = requires(T val) {
requires(Regular<T>);
typename iter_value_t<T>;
{
*val
} -> BareSameAs<iter_value_t<T>>;
};

template<typename T>
concept Iterator = requires(T val) {
requires(Regular<T>);
typename iter_dist_t<T>;
{
++val
} -> BareSameAs<T>;
// successor is not necessarily regular
};

template<typename T>
concept ForwardIterator = requires {
requires(Iterator<T>);
// successor is regular
};

template<typename T>
concept ReadableIterator = requires {
requires(Iterator<T>);
requires(Readable<T>);
};

template<typename T>
concept ReadableForwardIterator = requires {
requires(ForwardIterator<T>);
requires(Readable<T>);
};

// clang-format on

} // namespace based

diff --git a/ include/based/concepts/ordered/totally.hpp b/ include/based/concepts/ordered/totally.hpp

@@ -1,25 +0,0 @@

#pragma once

#include "based/concepts/comparable/equality.hpp"
#include "based/concepts/comparable/greater.hpp"
#include "based/concepts/comparable/greater_equal.hpp"
#include "based/concepts/comparable/less.hpp"
#include "based/concepts/comparable/less_equal.hpp"

namespace based
{

// clang-format off

template<typename T>
concept totally_ordered = requires {
requires(EqualityComparable<T>);
requires(LessComparable<T>);
requires(GreaterComparable<T>);
requires(LessEqualComparable<T>);
requires(GreaterEqualComparable<T>);
};

// clang-format on

} // namespace based

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

@@ -1,40 +0,0 @@

#pragma once

#include <tuple>

#include "based/concepts/is/regular.hpp"
#include "based/concepts/is/same.hpp"
#include "based/concepts/is/semiregular.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
{

template<typename T>
concept Input = SameAs<T, remove_cvref_t<remove_pointer_t<T>>>
|| is_const_v<remove_reference_t<T>> || is_const_v<remove_pointer_t<T>>;

template<size_t idx, typename... Args>
requires(idx < sizeof...(Args))
using elem_t = std::tuple_element_t<idx, std::tuple<Args...>>;

template<typename... Args>
concept SemiregularDomain = (Semiregular<remove_cvref_t<Args>> && ...);

template<typename... Args>
concept RegularDomain = (Regular<remove_cvref_t<Args>> && ...);

template<typename... Args>
concept InputDomain = (Input<Args> && ...);

template<typename... Args>
concept HomogeneousDomain = (SameAs<elem_t<0, Args...>, Args> && ...);

template<typename P, typename... Args>
using ret_t = std::invoke_result_t<P, Args...>;

} // namespace based

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

@@ -1,28 +0,0 @@

#pragma once

#include "based/concepts/procedure/domain.hpp"
#include "based/concepts/procedure/procedure.hpp"

namespace based
{

template<typename P, typename Ret, typename... Args>
concept FunctionalProcedure = requires {
requires(RegularProcedure<P, Ret, Args...>);
requires(InputDomain<Args...>);
};

template<typename P, typename Ret, typename Arg>
concept UnaryFunction = requires {
requires(FunctionalProcedure<P, Ret, Arg>);
requires(UnaryProcedure<P, Ret, Arg>);
};

template<typename P, typename Ret, typename... Args>
concept HomogeneousFunction = requires {
requires(FunctionalProcedure<P, Ret, Args...>);
requires(sizeof...(Args) > 0);
requires(HomogeneousDomain<Args...>);
};

} // namespace based

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

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

#pragma once

#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/function.hpp"

namespace based
{

template<typename P, typename Ret, typename I>
concept IterFunctionalProcedure = requires {
requires(Iterator<I>);
requires(FunctionalProcedure<P, Ret, iter_value_t<I>>);
};

template<typename P, typename Ret, typename I>
concept IterUnaryFunction = requires {
requires(Iterator<I>);
requires(UnaryFunction<P, Ret, iter_value_t<I>>);
};

template<typename P, typename Ret, typename I>
concept IterHomogeneousFunction = requires {
requires(Iterator<I>);
requires(HomogeneousFunction<P, Ret, iter_value_t<I>>);
};

} // namespace based

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

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

#pragma once

#include "based/concepts/procedure/function.hpp"

namespace based
{

template<typename P, typename... Args>
concept Operation = HomogeneousFunction<P, elem_t<0, Args...>, Args...>;

template<typename P, typename Ret, typename Arg>
concept Transformation = requires {
requires(Operation<P, Ret, Arg>);
requires(UnaryFunction<P, Ret, Arg>);
};

template<typename P, typename Arg>
concept BinaryOperation = Operation<P, Arg, Arg>;

template<typename P, typename Arg>
concept AssociativeBinaryOperation = Operation<P, Arg, Arg>;

} // namespace based

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

@@ -1,21 +0,0 @@

#pragma once

#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/operation.hpp"

namespace based
{

template<typename P, typename Ret, typename... I>
concept IterOperation = requires {
requires(Iterator<I> && ...);
requires(Operation<P, iter_value_t<I>...>);
};

template<typename P, typename Ret, typename I>
concept IterBinaryOperation = requires {
requires(Iterator<I>);
requires(BinaryOperation<P, iter_value_t<I>>);
};

} // namespace based

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

@@ -1,26 +0,0 @@

#pragma once

#include "based/concepts/procedure/function.hpp"

namespace based
{

template<typename P, typename... Args>
concept Predicate = FunctionalProcedure<P, bool, Args...>;

template<typename P, typename... Args>
concept HomogeneousPredicate = requires {
requires(Predicate<P, Args...>);
requires(HomogeneousFunction<P, bool, Args...>);
};

template<typename P, typename Arg>
concept UnaryPredicate = requires {
requires(Predicate<P, Arg>);
requires(UnaryFunction<P, bool, Arg>);
};

template<typename P, typename Arg>
concept Relation = HomogeneousPredicate<P, Arg, Arg>;

} // namespace based

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

@@ -1,33 +0,0 @@

#pragma once

#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/predicate.hpp"

namespace based
{

template<typename P, typename... I>
concept IterPredicate = requires {
requires(Iterator<I> && ...);
requires(Predicate<P, iter_value_t<I>...>);
};

template<typename P, typename... I>
concept IterHomogeneousPredicate = requires {
requires(Iterator<I> && ...);
requires(HomogeneousPredicate<P, iter_value_t<I>...>);
};

template<typename P, typename I>
concept IterUnaryPredicate = requires {
requires(Iterator<I>);
requires(UnaryPredicate<P, iter_value_t<I>>);
};

template<typename P, typename I>
concept IterRelation = requires {
requires(Iterator<I>);
requires(Relation<P, iter_value_t<I>>);
};

} // namespace based

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

@@ -1,48 +0,0 @@

#pragma once

#include "based/concepts/is/convertable.hpp"
#include "based/concepts/is/invocable.hpp"
#include "based/concepts/is/regular.hpp"
#include "based/concepts/procedure/domain.hpp"
#include "based/trait/integral_constant.hpp"
#include "based/trait/invoke_result.hpp"

namespace based
{

namespace detail
{

// clang-format off

template<typename P, typename Sig> struct procedure : public false_type {};

template<typename P, typename Ret, typename... Args>
requires (Invocable<P, Args...> && ConvertibleTo<invoke_result_t<P, Args...>, Ret>)
struct procedure<P, Ret(Args...)> : public true_type {};

template<typename P, typename... Args>
requires (Invocable<P, Args...>)
struct procedure<P, void(Args...)> : public true_type {};

template<typename P, typename Ret, typename... Args>
static constexpr bool procedure_v = procedure<P, Ret(Args...)>::value;

// clang-format on

} // namespace detail

template<typename P, typename Ret, typename... Args>
concept Procedure = detail::procedure_v<P, Ret, Args...>;

template<typename P, typename Ret, typename Arg>
concept UnaryProcedure = Procedure<P, Ret, Arg>;

template<typename P, typename Ret, typename... Args>
concept RegularProcedure = requires {
requires(Procedure<P, Ret, Args...>);
requires(RegularDomain<Args...>);
requires(Regular<ret_t<P, Args...>>);
};

} // namespace based

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

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

#pragma once

#include "based/concepts/iterator.hpp"
#include "based/concepts/procedure/procedure.hpp"

namespace based
{

template<typename P, typename Ret, typename I>
concept IterProcedure = requires {
requires(Iterator<I>);
requires(Procedure<P, Ret, iter_value_t<I>>);
};

template<typename P, typename Ret, typename I>
concept IterUnaryProcedure = requires {
requires(Iterator<I>);
requires(UnaryProcedure<P, Ret, iter_value_t<I>>);
};

template<typename P, typename Ret, typename I>
concept IterRegularProcedure = requires {
requires(Iterator<I>);
requires(RegularProcedure<P, Ret, iter_value_t<I>>);
};

} // namespace based

diff --git a/ include/based/container/array.hpp b/ include/based/container/array.hpp

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


#include <array>

#include "based/types/types.hpp"
#include "based/integral/types.hpp"

namespace based
{

diff --git a/ include/based/container/list.hpp b/ include/based/container/list.hpp

@@ -0,0 +1,262 @@

#pragma once

#include <cassert>
#include <vector>

#include "based/concept/is/same.hpp"
#include "based/integral/types.hpp"

namespace based
{

template<typename T, typename N>
// T semiregular
// N integral
class list_pool
{
public:
using value_type = T;
using list_type = N;

private:
struct node_t
{
value_type value {};
list_type next;
};

std::vector<node_t> m_pool;
list_type m_free_list;

[[nodiscard]] const node_t& node(list_type x) const
{
assert(x != list_type(0));
return m_pool[(x - list_type(1)).value];
}

[[nodiscard]] node_t& node(list_type x)
{
assert(x != list_type(0));
return m_pool[(x - list_type(1)).value];
}

[[nodiscard]] list_type new_node()
{
m_pool.push_back(node_t());
return list_type {static_cast<list_type::basic_type>(m_pool.size())};
}

public:
list_pool()
: m_free_list(node_empty())
{
}

struct iterator
{
using iterator_category = std::forward_iterator_tag;
using difference_type = list_pool::list_type;
using value_type = list_pool::value_type;
using reference = value_type&;
using pointer = value_type*;

iterator() = default;

explicit iterator(list_pool& pool)
: iterator(pool, pool.node_empty())
{
}

iterator(list_pool& pool, list_pool::list_type node)
: m_pool(&pool)
, m_node(node)
{
}

reference operator*() const { return m_pool->value(m_node); }
pointer operator->() const { return &**this; }

iterator& operator++()
{
m_node = m_pool->next(m_node);
return *this;
}

iterator operator++(int)
{
iterator tmp(*this);
++*this;
return tmp;
}

friend bool operator==(const iterator& x, const iterator& y)
{
assert(x.m_pool == y.m_pool);
return x.m_node == y.m_node;
}

friend bool operator!=(const iterator& x, const iterator& y)
{
return !(x == y);
}

private:
list_pool* m_pool;
list_pool::list_type m_node;
};

struct const_iterator
{
using iterator_category = std::forward_iterator_tag;
using difference_type = list_pool::list_type;
using value_type = list_pool::value_type;
using reference = const value_type&;
using pointer = const value_type*;

const_iterator() = default;

explicit const_iterator(const list_pool& pool)
: const_iterator(pool, pool.node_empty())
{
}

const_iterator(const list_pool& pool, list_pool::list_type node)
: m_pool(&pool)
, m_node(node)
{
}

reference operator*() const { return m_pool->value(m_node); }
pointer operator->() const { return &**this; }

const_iterator& operator++()
{
m_node = m_pool->next(m_node);
return *this;
}

const_iterator operator++(int)
{
const_iterator tmp(*this);
++*this;
return tmp;
}

friend bool operator==(const const_iterator& x, const const_iterator& y)
{
assert(x.m_pool == y.m_pool);
return x.m_node == y.m_node;
}

friend bool operator!=(const const_iterator& x, const const_iterator& y)
{
return !(x == y);
}

private:
const list_pool* m_pool;
list_pool::list_type m_node;
};

[[nodiscard]] bool is_empty(list_type x) const { return x == node_empty(); }
[[nodiscard]] list_type node_empty() const { return list_type(0); }

[[nodiscard]] const value_type& value(list_type x) const
{
return node(x).value;
}
[[nodiscard]] value_type& value(list_type x) { return node(x).value; }

[[nodiscard]] const list_type& next(list_type x) const
{
return node(x).next;
}
[[nodiscard]] list_type& next(list_type x) { return node(x).next; }

list_type free(list_type x)
{
const list_type ret = next(x);
next(x) = m_free_list;
m_free_list = x;
return ret;
}

list_type free(
list_type front, // NOLINT(*swappable*)
list_type back
)
{
if (is_empty(front)) {
return node_empty();
}

const list_type ret = next(back);
next(back) = m_free_list;
m_free_list = front;
return ret;
}

[[nodiscard]] list_type allocate(const value_type& val, list_type tail)
{
list_type new_list = m_free_list;

if (is_empty(new_list)) {
new_list = new_node();
} else {
m_free_list = next(m_free_list);
}

value(new_list) = val;
next(new_list) = tail;
return new_list;
}

using queue_t = std::pair<list_type, list_type>;

[[nodiscard]] bool is_empty(const queue_t& queue) const
{
return is_empty(queue.first);
}
[[nodiscard]] queue_t queue_empty() { return {node_empty(), node_empty()}; }

[[nodiscard]] queue_t push_front(const queue_t& queue, const value_type& val)
{
auto new_node = allocate(val, queue.first);
if (is_empty(queue)) {
return {new_node, new_node};
}
return {new_node, queue.second};
}

[[nodiscard]] queue_t push_back(const queue_t& queue, const value_type& val)
{
auto new_node = allocate(val, node_empty());
if (is_empty(queue)) {
return {new_node, new_node};
}
next(queue.second) = new_node;
return {queue.first, new_node};
}

[[nodiscard]] queue_t pop_front(const queue_t& queue)
{
if (is_empty(queue)) {
return queue;
}
queue_t ret = {next(queue.first), queue.second};
free(queue.first);
return ret;
}

void free(const queue_t& queue) { free(queue.first, queue.second); }
};

template<typename T, typename N>
void free_list(list_pool<T, N>& pool, typename list_pool<T, N>::list_type x)
{
while (!pool.is_empty(x)) {
x = pool.free(x);
}
}

} // namespace based

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

@@ -1,8 +1,8 @@

#pragma once

#include "based/algorithms/clamp.hpp"
#include "based/concepts/is/enum.hpp"
#include "based/concepts/is/same.hpp"
#include "based/algorithm/clamp.hpp"
#include "based/concept/is/enum.hpp"
#include "based/concept/is/same.hpp"

namespace based::enumeration
{

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

@@ -1,178 +0,0 @@

#pragma once

#include <format>
#include <ostream>

#include "based/char/character.hpp"
#include "based/types/types.hpp"

template<>
struct std::formatter<based::character>
{
static constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin();
}

static auto format(based::character value, std::format_context& ctx)
{
return std::format_to(ctx.out(), "{}", value.chr());
}
};

template<>
struct std::formatter<based::i8>
{
static constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin();
}

static auto format(based::i8 value, std::format_context& ctx)
{
return std::format_to(ctx.out(), "{}", value.value);
}
};

template<>
struct std::formatter<based::i16>
{
static constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin();
}

static auto format(based::i16 value, std::format_context& ctx)
{
return std::format_to(ctx.out(), "{}", value.value);
}
};

template<>
struct std::formatter<based::i32>
{
static constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin();
}

static auto format(based::i32 value, std::format_context& ctx)
{
return std::format_to(ctx.out(), "{}", value.value);
}
};

template<>
struct std::formatter<based::i64>
{
static constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin();
}

static auto format(based::i64 value, std::format_context& ctx)
{
return std::format_to(ctx.out(), "{}", value.value);
}
};

template<>
struct std::formatter<based::u8>
{
static constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin();
}

static auto format(based::u8 value, std::format_context& ctx)
{
return std::format_to(ctx.out(), "{}", value.value);
}
};

template<>
struct std::formatter<based::u16>
{
static constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin();
}

static auto format(based::u16 value, std::format_context& ctx)
{
return std::format_to(ctx.out(), "{}", value.value);
}
};

template<>
struct std::formatter<based::u32>
{
static constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin();
}

static auto format(based::u32 value, std::format_context& ctx)
{
return std::format_to(ctx.out(), "{}", value.value);
}
};

template<>
struct std::formatter<based::u64>
{
static constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin();
}

static auto format(based::u64 value, std::format_context& ctx)
{
return std::format_to(ctx.out(), "{}", value.value);
}
};

inline std::ostream& operator<<(std::ostream& ost, based::character value)
{
return ost << value.chr();
}

inline std::ostream& operator<<(std::ostream& ost, based::i8 value)
{
return ost << value.value;
}

inline std::ostream& operator<<(std::ostream& ost, based::i16 value)
{
return ost << value.value;
}

inline std::ostream& operator<<(std::ostream& ost, based::i32 value)
{
return ost << value.value;
}

inline std::ostream& operator<<(std::ostream& ost, based::i64 value)
{
return ost << value.value;
}

inline std::ostream& operator<<(std::ostream& ost, based::u8 value)
{
return ost << value.value;
}

inline std::ostream& operator<<(std::ostream& ost, based::u16 value)
{
return ost << value.value;
}

inline std::ostream& operator<<(std::ostream& ost, based::u32 value)
{
return ost << value.value;
}

inline std::ostream& operator<<(std::ostream& ost, based::u64 value)
{
return ost << value.value;
}

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

@@ -2,9 +2,9 @@


#include <functional>

#include "based/concepts/is/same.hpp"
#include "based/concept/is/same.hpp"
#include "based/trait/signature.hpp"
#include "based/types/types.hpp"
#include "based/integral/types.hpp"
#include "based/utility/buffer.hpp"
#include "based/utility/forward.hpp"

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

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

#pragma once

#include "based/concepts/procedure/predicate.hpp"
#include "based/concept/procedure/predicate.hpp"

namespace based
{

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

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

#pragma once

#include "based/concepts/procedure/predicate.hpp"
#include "based/concept/procedure/predicate.hpp"

namespace based
{

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

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

#pragma once

#include "based/concepts/procedure/predicate.hpp"
#include "based/concept/procedure/predicate.hpp"

namespace based
{

diff --git a/ include/based/instrumentation/instrumented.hpp b/ include/based/instrumentation/instrumented.hpp

@@ -9,7 +9,7 @@


#include "based/enum/enum.hpp"
#include "based/instrumentation/table.hpp"
#include "based/types/types.hpp"
#include "based/integral/types.hpp"
#include "based/utility/move.hpp"

namespace based

diff --git a/ include/based/instrumentation/registry.hpp b/ include/based/instrumentation/registry.hpp

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

#pragma once

#include "based/types/types.hpp"
#include "based/integral/types.hpp"

namespace based
{

diff --git a/ include/based/instrumentation/table.hpp b/ include/based/instrumentation/table.hpp

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

#include <format>
#include <iostream>

#include "based/types/types.hpp"
#include "based/integral/types.hpp"

namespace based
{

diff --git a/ include/based/integral/format.hpp b/ include/based/integral/format.hpp

@@ -0,0 +1,158 @@

#pragma once

#include <format>
#include <ostream>

#include "based/integral/types.hpp"

template<>
struct std::formatter<based::i8>
{
static constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin();
}

static auto format(based::i8 value, std::format_context& ctx)
{
return std::format_to(ctx.out(), "{}", value.value);
}
};

template<>
struct std::formatter<based::i16>
{
static constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin();
}

static auto format(based::i16 value, std::format_context& ctx)
{
return std::format_to(ctx.out(), "{}", value.value);
}
};

template<>
struct std::formatter<based::i32>
{
static constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin();
}

static auto format(based::i32 value, std::format_context& ctx)
{
return std::format_to(ctx.out(), "{}", value.value);
}
};

template<>
struct std::formatter<based::i64>
{
static constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin();
}

static auto format(based::i64 value, std::format_context& ctx)
{
return std::format_to(ctx.out(), "{}", value.value);
}
};

template<>
struct std::formatter<based::u8>
{
static constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin();
}

static auto format(based::u8 value, std::format_context& ctx)
{
return std::format_to(ctx.out(), "{}", value.value);
}
};

template<>
struct std::formatter<based::u16>
{
static constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin();
}

static auto format(based::u16 value, std::format_context& ctx)
{
return std::format_to(ctx.out(), "{}", value.value);
}
};

template<>
struct std::formatter<based::u32>
{
static constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin();
}

static auto format(based::u32 value, std::format_context& ctx)
{
return std::format_to(ctx.out(), "{}", value.value);
}
};

template<>
struct std::formatter<based::u64>
{
static constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin();
}

static auto format(based::u64 value, std::format_context& ctx)
{
return std::format_to(ctx.out(), "{}", value.value);
}
};

inline std::ostream& operator<<(std::ostream& ost, based::i8 value)
{
return ost << value.value;
}

inline std::ostream& operator<<(std::ostream& ost, based::i16 value)
{
return ost << value.value;
}

inline std::ostream& operator<<(std::ostream& ost, based::i32 value)
{
return ost << value.value;
}

inline std::ostream& operator<<(std::ostream& ost, based::i64 value)
{
return ost << value.value;
}

inline std::ostream& operator<<(std::ostream& ost, based::u8 value)
{
return ost << value.value;
}

inline std::ostream& operator<<(std::ostream& ost, based::u16 value)
{
return ost << value.value;
}

inline std::ostream& operator<<(std::ostream& ost, based::u32 value)
{
return ost << value.value;
}

inline std::ostream& operator<<(std::ostream& ost, based::u64 value)
{
return ost << value.value;
}

diff --git a/ include/based/integral/literals.hpp b/ include/based/integral/literals.hpp

@@ -0,0 +1,76 @@

#pragma once

#include "based/integral/types.hpp"

// NOLINTBEGIN(google-runtime-int)

namespace based
{

namespace literals
{

consteval auto operator""_i(unsigned long long val)
{
return i::underlying_cast(val);
}

consteval i8 operator""_i8(unsigned long long val)
{
return i::underlying_cast(val);
}

consteval i16 operator""_i16(unsigned long long val)
{
return i::underlying_cast(val);
}

consteval i32 operator""_i32(unsigned long long val)
{
return i::underlying_cast(val);
}

consteval i64 operator""_i64(unsigned long long val)
{
return i::underlying_cast(val);
}

} // namespace literals

// Unsigned

namespace literals
{

consteval auto operator""_u(unsigned long long val)
{
return u::underlying_cast(val);
}

consteval u8 operator""_u8(unsigned long long val)
{
return u::underlying_cast(val);
}

consteval u16 operator""_u16(unsigned long long val)
{
return u::underlying_cast(val);
}

consteval u32 operator""_u32(unsigned long long val)
{
return u::underlying_cast(val);
}

consteval u64 operator""_u64(unsigned long long val)
{
return u::underlying_cast(val);
}

} // namespace literals

using namespace literals; // NOLINT(*namespace*)

} // namespace based

// NOLINTEND(google-runtime-int)

diff --git a/ include/based/integral/strong.hpp b/ include/based/integral/strong.hpp

@@ -0,0 +1,354 @@

#pragma once

#include <compare>

#include "based/concept/is/same.hpp"
#include "based/trait/is/class.hpp"

namespace based
{

// NOLINTNEXTLINE(*macro*)
#define BASED_DETAIL_MACRO(decl, val) \
decltype(decl) \
{ \
static_cast<decltype(decl)::basic_type>(val) \
}

template<class V, class Tag>
// NOLINTBEGIN(*crtp*)
struct strong_type
{
using value_type = strong_type;
using basic_type = V;
using tag_type = Tag;

basic_type value;

constexpr ~strong_type() = default;

explicit constexpr strong_type()
: value(0)
{
}

explicit constexpr strong_type(basic_type val)
: value(val)
{
}

explicit constexpr operator basic_type() const { return value; }

constexpr strong_type(const strong_type&) = default;
constexpr strong_type(strong_type&&) = default;

constexpr strong_type& operator=(const strong_type&) = default;
constexpr strong_type& operator=(strong_type&&) = default;

template<class T>
static constexpr Tag underlying_cast(T value)
{
return Tag {static_cast<basic_type>(value)};
}

template<class T>
static constexpr Tag cast(T value)
{
return static_cast<Tag>(value);
}
};
// NOLINTEND(*crtp*)

template<class LHS, class RHS>
concept comparable = requires(LHS lhs, RHS rhs) { compare(lhs, rhs); };

template<class LHS, class RHS>
requires comparable<LHS, RHS>
constexpr bool operator==(LHS lhs, RHS rhs)
{
return lhs.value == rhs.value;
}

template<class LHS, class RHS>
concept ordered = requires(LHS lhs, RHS rhs) { order(lhs, rhs); };

template<class LHS, class RHS>
requires ordered<LHS, RHS>
constexpr auto operator<=>(LHS lhs, RHS rhs)
{
return lhs.value <=> rhs.value;
}

template<class LHS, class RHS>
concept addable = requires(LHS lhs, RHS rhs) { add(lhs, rhs); };

template<class LHS, class RHS>
requires addable<LHS, RHS>
constexpr auto operator+(LHS lhs, RHS rhs)
{
return BASED_DETAIL_MACRO(add(lhs, rhs), lhs.value + rhs.value);
}

template<class LHS, class RHS>
requires(requires(LHS lhs, RHS rhs) {
requires addable<LHS, RHS>;
requires SameAs<LHS, decltype(add(lhs, rhs))>;
})
constexpr auto& operator+=(LHS& lhs, RHS rhs)
{
return lhs = lhs + rhs;
}

template<class LHS, class RHS>
concept subtractable = requires(LHS lhs, RHS rhs) { sub(lhs, rhs); };

template<class LHS, class RHS>
requires subtractable<LHS, RHS>
constexpr auto operator-(LHS lhs, RHS rhs)
{
return BASED_DETAIL_MACRO(sub(lhs, rhs), lhs.value - rhs.value);
}

template<class LHS, class RHS>
requires(requires(LHS lhs, RHS rhs) {
requires subtractable<LHS, RHS>;
requires SameAs<LHS, decltype(sub(lhs, rhs))>;
})
constexpr auto& operator-=(LHS& lhs, RHS rhs)
{
return lhs = lhs - rhs;
}

template<class LHS, class RHS>
concept multiplyable = requires(LHS lhs, RHS rhs) { mul(lhs, rhs); };

template<class LHS, class RHS>
requires multiplyable<LHS, RHS>
constexpr auto operator*(LHS lhs, RHS rhs)
{
return BASED_DETAIL_MACRO(mul(lhs, rhs), lhs.value * rhs.value);
}

template<class LHS, class RHS>
requires(requires(LHS lhs, RHS rhs) {
requires multiplyable<LHS, RHS>;
requires SameAs<LHS, decltype(mul(lhs, rhs))>;
})
constexpr auto& operator*=(LHS& lhs, RHS rhs)
{
return lhs = lhs * rhs;
}

template<class LHS, class RHS>
concept divisible = requires(LHS lhs, RHS rhs) { div(lhs, rhs); };

template<class LHS, class RHS>
requires divisible<LHS, RHS>
constexpr auto operator/(LHS lhs, RHS rhs)
{
return BASED_DETAIL_MACRO(div(lhs, rhs), lhs.value / rhs.value);
}

template<class LHS, class RHS>
requires(requires(LHS lhs, RHS rhs) {
requires divisible<LHS, RHS>;
requires SameAs<LHS, decltype(div(lhs, rhs))>;
})
constexpr auto& operator/=(LHS& lhs, RHS rhs)
{
return lhs = lhs / rhs;
}

template<class LHS, class RHS>
concept modable = requires(LHS lhs, RHS rhs) { mod(lhs, rhs); };

template<class LHS, class RHS>
requires modable<LHS, RHS>
constexpr auto operator%(LHS lhs, RHS rhs)
{
return BASED_DETAIL_MACRO(mod(lhs, rhs), lhs.value % rhs.value);
}

template<class LHS, class RHS>
requires(requires(LHS lhs, RHS rhs) {
requires modable<LHS, RHS>;
requires SameAs<LHS, decltype(mod(lhs, rhs))>;
})
constexpr auto& operator%=(LHS& lhs, RHS rhs)
{
return lhs = lhs % rhs;
}

template<class LHS, class RHS>
concept lshiftable = requires(LHS lhs, RHS rhs) { lshift(lhs, rhs); };

template<class LHS, class RHS>
requires lshiftable<LHS, RHS>
constexpr auto operator<<(LHS lhs, RHS rhs)
{
return BASED_DETAIL_MACRO(lshift(lhs, rhs), lhs.value << rhs.value);
}

template<class LHS, class RHS>
requires(requires(LHS lhs, RHS rhs) {
requires lshiftable<LHS, RHS>;
requires SameAs<LHS, decltype(lshift(lhs, rhs))>;
})
constexpr auto& operator<<=(LHS& lhs, RHS rhs)
{
return lhs = lhs << rhs;
}

template<class LHS, class RHS>
concept rshiftable = requires(LHS lhs, RHS rhs) { rshift(lhs, rhs); };

template<class LHS, class RHS>
requires rshiftable<LHS, RHS>
constexpr auto operator>>(LHS lhs, RHS rhs)
{
return BASED_DETAIL_MACRO(rshift(lhs, rhs), lhs.value >> rhs.value);
}

template<class LHS, class RHS>
requires(requires(LHS lhs, RHS rhs) {
requires rshiftable<LHS, RHS>;
requires SameAs<LHS, decltype(rshift(lhs, rhs))>;
})
constexpr auto& operator>>=(LHS& lhs, RHS rhs)
{
return lhs = lhs >> rhs;
}

template<class LHS, class RHS>
concept andable = requires(LHS lhs, RHS rhs) { land(lhs, rhs); };

template<class LHS, class RHS>
requires andable<LHS, RHS>
constexpr auto operator&(LHS lhs, RHS rhs)
{
return BASED_DETAIL_MACRO(land(lhs, rhs), lhs.value & rhs.value);
}

template<class LHS, class RHS>
requires(requires(LHS lhs, RHS rhs) {
requires andable<LHS, RHS>;
requires SameAs<LHS, decltype(land(lhs, rhs))>;
})
constexpr auto& operator&=(LHS& lhs, RHS rhs)
{
return lhs = lhs & rhs;
}

template<class LHS, class RHS>
concept orable = requires(LHS lhs, RHS rhs) { lor(lhs, rhs); };

template<class LHS, class RHS>
requires orable<LHS, RHS>
constexpr auto operator|(LHS lhs, RHS rhs)
{
return BASED_DETAIL_MACRO(lor(lhs, rhs), lhs.value | rhs.value);
}

template<class LHS, class RHS>
requires(requires(LHS lhs, RHS rhs) {
requires orable<LHS, RHS>;
requires SameAs<LHS, decltype(lor(lhs, rhs))>;
})
constexpr auto& operator|=(LHS& lhs, RHS rhs)
{
return lhs = lhs | rhs;
}

template<class LHS, class RHS>
concept xorable = requires(LHS lhs, RHS rhs) { lxor(lhs, rhs); };

template<class LHS, class RHS>
requires xorable<LHS, RHS>
constexpr auto operator^(LHS lhs, RHS rhs)
{
return BASED_DETAIL_MACRO(lxor(lhs, rhs), lhs.value ^ rhs.value);
}

template<class LHS, class RHS>
requires(requires(LHS lhs, RHS rhs) {
requires xorable<LHS, RHS>;
requires SameAs<LHS, decltype(lxor(lhs, rhs))>;
})
constexpr auto& operator^=(LHS& lhs, RHS rhs)
{
return lhs = lhs ^ rhs;
}

template<class LHS>
concept lnotable = requires(LHS lhs) { lnot(lhs); };

template<class LHS>
requires lnotable<LHS>
constexpr auto operator~(LHS lhs)
{
lhs.value = ~lhs.value;
return lhs;
}

template<class LHS>
concept unariable = requires(LHS lhs) { unary(lhs); };

template<class LHS>
requires unariable<LHS>
constexpr auto operator+(LHS lhs)
{
return decltype(lhs)(+lhs.value);
}

template<class LHS>
requires unariable<LHS>
constexpr auto operator-(LHS lhs)
{
return decltype(lhs)(-lhs.value);
}

template<class LHS>
concept preincable = requires(LHS lhs) { preinc(lhs); };

template<class LHS>
requires preincable<LHS>
constexpr auto& operator++(LHS& lhs)
{
++lhs.value;
return lhs;
}

template<class LHS>
concept postincable = requires(LHS lhs) { postinc(lhs); };

template<class LHS>
requires postincable<LHS>
constexpr auto operator++(LHS& lhs, int)
{
return BASED_DETAIL_MACRO(postinc(lhs), lhs.value++);
}

template<class LHS>
concept predecable = requires(LHS lhs) { predec(lhs); };

template<class LHS>
requires predecable<LHS>
constexpr auto operator--(LHS& lhs)
{
--lhs.value;
return lhs;
}

template<class LHS>
concept postdecable = requires(LHS lhs) { postdec(lhs); };

template<class LHS>
requires postdecable<LHS>
constexpr auto operator--(LHS& lhs, int)
{
return BASED_DETAIL_MACRO(postdec(lhs), lhs.value--);
}

#undef BASED_DETAIL_MACRO

} // namespace based

diff --git a/ include/based/integral/types.hpp b/ include/based/integral/types.hpp

@@ -0,0 +1,314 @@

#pragma once

#include "based/utility/assert.hpp"
#include "based/macro/foreach_1.hpp"
#include "based/integral/strong.hpp"

namespace based
{

// NOLINTBEGIN(google-runtime-int)

using size_t = unsigned long long int;

#define BASED_DETAIL_OP_UNARY(Prefix, Name, Index) \
auto Name(Prefix##8)->Prefix##8; \
auto Name(Prefix##16)->Prefix##16; \
auto Name(Prefix##32)->Prefix##32; \
auto Name(Prefix##64)->Prefix##64; \
auto Name(Prefix)->Prefix;

#define BASED_DETAIL_OP_BINARY(Prefix, Name, Index) \
auto Name(Prefix##8, Prefix##8)->Prefix##8; \
auto Name(Prefix##8, Prefix##16)->Prefix##16; \
auto Name(Prefix##8, Prefix##32)->Prefix##32; \
auto Name(Prefix##8, Prefix##64)->Prefix##64; \
\
auto Name(Prefix##16, Prefix##8)->Prefix##16; \
auto Name(Prefix##16, Prefix##16)->Prefix##16; \
auto Name(Prefix##16, Prefix##32)->Prefix##32; \
auto Name(Prefix##16, Prefix##64)->Prefix##64; \
\
auto Name(Prefix##32, Prefix##8)->Prefix##32; \
auto Name(Prefix##32, Prefix##16)->Prefix##32; \
auto Name(Prefix##32, Prefix##32)->Prefix##32; \
auto Name(Prefix##32, Prefix##64)->Prefix##64; \
\
auto Name(Prefix##64, Prefix##8)->Prefix##64; \
auto Name(Prefix##64, Prefix##16)->Prefix##64; \
auto Name(Prefix##64, Prefix##32)->Prefix##64; \
auto Name(Prefix##64, Prefix##64)->Prefix##64; \
\
auto Name(Prefix, Prefix)->Prefix;

template<class T>
struct limits;

struct i64 : strong_type<signed long long int, i64>
{
using strong_type::strong_type;
using strong_type::operator=;
};

struct i32 : strong_type<signed int, i32>
{
using strong_type::strong_type;
using strong_type::operator=;

explicit constexpr operator i64() { return i64::underlying_cast(value); }

[[nodiscard]] constexpr i64 to_i64() const { return i64::cast(*this); }
};

struct i16 : strong_type<signed short int, i16>
{
using strong_type::strong_type;
using strong_type::operator=;

explicit constexpr operator i64() { return i64::underlying_cast(value); }
explicit constexpr operator i32() { return i32::underlying_cast(value); }

[[nodiscard]] constexpr i64 to_i64() const { return i64::cast(*this); }
[[nodiscard]] constexpr i32 to_i32() const { return i32::cast(*this); }
};

struct i8 : strong_type<signed char, i8>
{
using strong_type::strong_type;
using strong_type::operator=;

explicit constexpr operator i64() { return i64::underlying_cast(value); }
explicit constexpr operator i32() { return i32::underlying_cast(value); }
explicit constexpr operator i16() { return i16::underlying_cast(value); }

[[nodiscard]] constexpr i64 to_i64() const { return i64::cast(*this); }
[[nodiscard]] constexpr i32 to_i32() const { return i32::cast(*this); }
[[nodiscard]] constexpr i16 to_i16() const { return i16::cast(*this); }
};

template<>
struct limits<i8>
{
static constexpr bool is_integer = true;
static constexpr bool is_signed = true;

static constexpr auto min = i8::underlying_cast(0x80);
static constexpr auto max = i8::underlying_cast(0x7F);
};

template<>
struct limits<i16>
{
static constexpr bool is_integer = true;
static constexpr bool is_signed = true;

static constexpr auto min = i16::underlying_cast(0x8000);
static constexpr auto max = i16::underlying_cast(0x7FFF);
};

template<>
struct limits<i32>
{
static constexpr bool is_integer = true;
static constexpr bool is_signed = true;

static constexpr auto min = i32::underlying_cast(0x80000000);
static constexpr auto max = i32::underlying_cast(0x7FFFFFFF);
};

template<>
struct limits<i64>
{
static constexpr bool is_integer = true;
static constexpr bool is_signed = true;

static constexpr auto min = i64::underlying_cast(0x8000000000000000);
static constexpr auto max = i64::underlying_cast(0x7FFFFFFFFFFFFFFF);
};

struct i : strong_type<signed long long int, i>
{
using strong_type::strong_type;
using strong_type::operator=;

consteval operator i8() const // NOLINT(*explicit*)
{
BASED_ASSERT(value >= limits<i8>::min.value);
BASED_ASSERT(value <= limits<i8>::max.value);
return i8::underlying_cast(value);
}

consteval operator i16() const // NOLINT(*explicit*)
{
BASED_ASSERT(value >= limits<i16>::min.value);
BASED_ASSERT(value <= limits<i16>::max.value);
return i16::underlying_cast(value);
}

consteval operator i32() const // NOLINT(*explicit*)
{
BASED_ASSERT(value >= limits<i32>::min.value);
BASED_ASSERT(value <= limits<i32>::max.value);
return i32::underlying_cast(value);
}

consteval operator i64() const // NOLINT(*explicit*)
{
BASED_ASSERT(value >= limits<i64>::min.value);
BASED_ASSERT(value <= limits<i64>::max.value);
return i64::underlying_cast(value);
}
};

auto unary(i) -> i;

struct u64 : strong_type<unsigned long long int, u64>
{
using strong_type::strong_type;
using strong_type::operator=;
};

struct u32 : strong_type<unsigned int, u32>
{
using strong_type::strong_type;
using strong_type::operator=;

explicit constexpr operator u64() { return u64::underlying_cast(value); }

[[nodiscard]] constexpr u64 to_u64() const { return u64::cast(*this); }
};

struct u16 : strong_type<unsigned short int, u16>
{
using strong_type::strong_type;
using strong_type::operator=;

explicit constexpr operator u64() { return u64::underlying_cast(value); }
explicit constexpr operator u32() { return u32::underlying_cast(value); }

[[nodiscard]] constexpr u64 to_u64() const { return u64::cast(*this); }
[[nodiscard]] constexpr u32 to_u32() const { return u32::cast(*this); }
};

struct u8 : strong_type<unsigned char, u8>
{
using strong_type::strong_type;
using strong_type::operator=;

explicit constexpr operator u64() { return u64::underlying_cast(value); }
explicit constexpr operator u32() { return u32::underlying_cast(value); }
explicit constexpr operator u16() { return u16::underlying_cast(value); }

[[nodiscard]] constexpr u64 to_u64() const { return u64::cast(*this); }
[[nodiscard]] constexpr u32 to_u32() const { return u32::cast(*this); }
[[nodiscard]] constexpr u16 to_u16() const { return u16::cast(*this); }
};

template<>
struct limits<u8>
{
static constexpr bool is_integer = true;
static constexpr bool is_signed = false;

static constexpr auto min = u8::underlying_cast(0x00);
static constexpr auto max = u8::underlying_cast(0xFF);
};

template<>
struct limits<u16>
{
static constexpr bool is_integer = true;
static constexpr bool is_signed = false;

static constexpr auto min = u16::underlying_cast(0x0000);
static constexpr auto max = u16::underlying_cast(0xFFFF);
};

template<>
struct limits<u32>
{
static constexpr bool is_integer = true;
static constexpr bool is_signed = false;

static constexpr auto min = u32::underlying_cast(0x00000000);
static constexpr auto max = u32::underlying_cast(0xFFFFFFFF);
};

template<>
struct limits<u64>
{
static constexpr bool is_integer = true;
static constexpr bool is_signed = false;

static constexpr auto min = u64::underlying_cast(0x0000000000000000);
static constexpr auto max = u64::underlying_cast(0xFFFFFFFFFFFFFFFF);
};

struct u : strong_type<unsigned long long int, u>
{
using strong_type::strong_type;

consteval operator u8() const // NOLINT(*explicit*)
{
BASED_ASSERT(value >= limits<u8>::min.value);
BASED_ASSERT(value <= limits<u8>::max.value);
return u8::underlying_cast(value);
}

consteval operator u16() const // NOLINT(*explicit*)
{
BASED_ASSERT(value >= limits<u16>::min.value);
BASED_ASSERT(value <= limits<u16>::max.value);
return u16::underlying_cast(value);
}

consteval operator u32() const // NOLINT(*explicit*)
{
BASED_ASSERT(value >= limits<u32>::min.value);
BASED_ASSERT(value <= limits<u32>::max.value);
return u32::underlying_cast(value);
}

consteval operator u64() const // NOLINT(*explicit*)
{
BASED_ASSERT(value >= limits<u64>::min.value);
BASED_ASSERT(value <= limits<u64>::max.value);
return u64::underlying_cast(value);
}
};

BASED_FOREACH_1(
i, BASED_DETAIL_OP_UNARY, unary, preinc, postinc, predec, postdec
)
BASED_FOREACH_1(
i, BASED_DETAIL_OP_BINARY, compare, order, add, sub, mul, div, mod
)

BASED_FOREACH_1(
u, BASED_DETAIL_OP_UNARY, preinc, postinc, predec, postdec, lnot
)

BASED_FOREACH_1(
u,
BASED_DETAIL_OP_BINARY,
compare,
order,
add,
sub,
mul,
div,
mod,
lshift,
rshift,
land,
lor,
lxor
)

#undef BASED_DETAIL_TYPE
#undef BASED_DETAIL_OP_UNARY
#undef BASED_DETAIL_OP_BINARY

// NOLINTEND(google-runtime-int)

} // namespace based

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

@@ -1,262 +0,0 @@

#pragma once

#include <cassert>
#include <vector>

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

namespace based
{

template<typename T, typename N>
// T semiregular
// N integral
class list_pool
{
public:
using value_type = T;
using list_type = N;

private:
struct node_t
{
value_type value {};
list_type next;
};

std::vector<node_t> m_pool;
list_type m_free_list;

[[nodiscard]] const node_t& node(list_type x) const
{
assert(x != list_type(0));
return m_pool[(x - list_type(1)).value];
}

[[nodiscard]] node_t& node(list_type x)
{
assert(x != list_type(0));
return m_pool[(x - list_type(1)).value];
}

[[nodiscard]] list_type new_node()
{
m_pool.push_back(node_t());
return list_type {static_cast<list_type::basic_type>(m_pool.size())};
}

public:
list_pool()
: m_free_list(node_empty())
{
}

struct iterator
{
using iterator_category = std::forward_iterator_tag;
using difference_type = list_pool::list_type;
using value_type = list_pool::value_type;
using reference = value_type&;
using pointer = value_type*;

iterator() = default;

explicit iterator(list_pool& pool)
: iterator(pool, pool.node_empty())
{
}

iterator(list_pool& pool, list_pool::list_type node)
: m_pool(&pool)
, m_node(node)
{
}

reference operator*() const { return m_pool->value(m_node); }
pointer operator->() const { return &**this; }

iterator& operator++()
{
m_node = m_pool->next(m_node);
return *this;
}

iterator operator++(int)
{
iterator tmp(*this);
++*this;
return tmp;
}

friend bool operator==(const iterator& x, const iterator& y)
{
assert(x.m_pool == y.m_pool);
return x.m_node == y.m_node;
}

friend bool operator!=(const iterator& x, const iterator& y)
{
return !(x == y);
}

private:
list_pool* m_pool;
list_pool::list_type m_node;
};

struct const_iterator
{
using iterator_category = std::forward_iterator_tag;
using difference_type = list_pool::list_type;
using value_type = list_pool::value_type;
using reference = const value_type&;
using pointer = const value_type*;

const_iterator() = default;

explicit const_iterator(const list_pool& pool)
: const_iterator(pool, pool.node_empty())
{
}

const_iterator(const list_pool& pool, list_pool::list_type node)
: m_pool(&pool)
, m_node(node)
{
}

reference operator*() const { return m_pool->value(m_node); }
pointer operator->() const { return &**this; }

const_iterator& operator++()
{
m_node = m_pool->next(m_node);
return *this;
}

const_iterator operator++(int)
{
const_iterator tmp(*this);
++*this;
return tmp;
}

friend bool operator==(const const_iterator& x, const const_iterator& y)
{
assert(x.m_pool == y.m_pool);
return x.m_node == y.m_node;
}

friend bool operator!=(const const_iterator& x, const const_iterator& y)
{
return !(x == y);
}

private:
const list_pool* m_pool;
list_pool::list_type m_node;
};

[[nodiscard]] bool is_empty(list_type x) const { return x == node_empty(); }
[[nodiscard]] list_type node_empty() const { return list_type(0); }

[[nodiscard]] const value_type& value(list_type x) const
{
return node(x).value;
}
[[nodiscard]] value_type& value(list_type x) { return node(x).value; }

[[nodiscard]] const list_type& next(list_type x) const
{
return node(x).next;
}
[[nodiscard]] list_type& next(list_type x) { return node(x).next; }

list_type free(list_type x)
{
const list_type ret = next(x);
next(x) = m_free_list;
m_free_list = x;
return ret;
}

list_type free(
list_type front, // NOLINT(*swappable*)
list_type back
)
{
if (is_empty(front)) {
return node_empty();
}

const list_type ret = next(back);
next(back) = m_free_list;
m_free_list = front;
return ret;
}

[[nodiscard]] list_type allocate(const value_type& val, list_type tail)
{
list_type new_list = m_free_list;

if (is_empty(new_list)) {
new_list = new_node();
} else {
m_free_list = next(m_free_list);
}

value(new_list) = val;
next(new_list) = tail;
return new_list;
}

using queue_t = std::pair<list_type, list_type>;

[[nodiscard]] bool is_empty(const queue_t& queue) const
{
return is_empty(queue.first);
}
[[nodiscard]] queue_t queue_empty() { return {node_empty(), node_empty()}; }

[[nodiscard]] queue_t push_front(const queue_t& queue, const value_type& val)
{
auto new_node = allocate(val, queue.first);
if (is_empty(queue)) {
return {new_node, new_node};
}
return {new_node, queue.second};
}

[[nodiscard]] queue_t push_back(const queue_t& queue, const value_type& val)
{
auto new_node = allocate(val, node_empty());
if (is_empty(queue)) {
return {new_node, new_node};
}
next(queue.second) = new_node;
return {queue.first, new_node};
}

[[nodiscard]] queue_t pop_front(const queue_t& queue)
{
if (is_empty(queue)) {
return queue;
}
queue_t ret = {next(queue.first), queue.second};
free(queue.first);
return ret;
}

void free(const queue_t& queue) { free(queue.first, queue.second); }
};

template<typename T, typename N>
void free_list(list_pool<T, N>& pool, typename list_pool<T, N>::list_type x)
{
while (!pool.is_empty(x)) {
x = pool.free(x);
}
}

} // namespace based

diff --git a/ include/based/memory/nullptr.hpp b/ include/based/memory/nullptr.hpp

@@ -0,0 +1,8 @@

#pragma once

namespace based
{

using nullptr_t = decltype(nullptr);

} // namespace based

diff --git a/ include/based/string/format.hpp b/ include/based/string/format.hpp

@@ -11,7 +11,7 @@ constexpr auto string_format(std::string_view format, auto... args)

std::string_view::size_type last = 0;
std::string res;

const auto func = [&](std::string_view arg)
[[maybe_unused]] const auto func = [&](std::string_view arg)
{
if (auto pos = format.find("{}", last); pos != std::string_view::npos) {
res += format.substr(last, pos - last);

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

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

#pragma once

#include "based/trait/integral_constant.hpp"
#include "based/types/types.hpp"
#include "based/integral/types.hpp"

namespace based
{

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

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


#include "based/trait/is/same.hpp"
#include "based/trait/remove/cv.hpp"
#include "based/types/nullptr.hpp"
#include "based/memory/nullptr.hpp"

namespace based
{

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

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


#include <iterator>

#include "based/types/types.hpp"
#include "based/integral/types.hpp"

namespace based
{

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

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

#pragma once

#include "based/types/types.hpp"
#include "based/integral/types.hpp"

namespace based
{

diff --git a/ include/based/types/builder.hpp b/ include/based/types/builder.hpp

@@ -1,300 +0,0 @@

#pragma once

// NOLINTBEGIN(*macro-usage*,*macro-parentheses*,*naming*)

namespace based
{

template<typename V>
class builder_type
{
protected:
V m_val; // NOLINT (*protected*)

public:
template<class FV1>
using rebind = builder_type<V>;

using value_type = builder_type;
using basic_type = V;

constexpr ~builder_type() = default;

constexpr explicit builder_type()
: m_val(V())
{
}

constexpr explicit builder_type(V value)
: m_val(value)
{
}

constexpr builder_type(const builder_type&) = default;
constexpr builder_type& operator=(const builder_type&) = default;

constexpr builder_type(builder_type&&) = default;
constexpr builder_type& operator=(builder_type&&) = default;

[[nodiscard]] auto value() const { return m_val; }
};

#define BASED_B_DETAIL_COMMON(Name) \
template<class FV1> \
using rebind = Name<V, FV1>; \
\
using base_type::base_type; \
using base_type::operator=; \
\
using value_type = typename base_type::value_type; \
using basic_type = typename value_type::basic_type; \
\
/* NOLINTNEXTLINE(*crtp*) */ \
constexpr explicit Name(value_type value) \
: base_type(value) \
{ \
}

#define BASED_B_DETAIL_TEMPLATE(Name) \
template<class V, class FV = void> \
class Name : public V::template rebind<FV> \
{ \
using base_type = typename V::template rebind<FV>; \
\
public: \
BASED_B_DETAIL_COMMON(Name) X(FV, Name) \
};

#define BASED_B_DETAIL_SPECIALIZATION(Name) \
template<class V> \
class Name<V, void> : public V::template rebind<Name<V>> \
{ \
using base_type = typename V::template rebind<Name<V>>; \
\
public: \
BASED_B_DETAIL_COMMON(Name) X(Name, Name) \
};

#define BASED_BUILDER_DECORATOR(Name) \
BASED_B_DETAIL_TEMPLATE(Name) BASED_B_DETAIL_SPECIALIZATION(Name)

#define X(FV, Name) \
/* NOLINTNEXTLINE(*explicit*) */ \
Name(basic_type rhs) \
: base_type(rhs) \
{ \
} \
\
Name& operator=(V rhs) \
{ \
this->m_val = rhs; \
return *this; \
}

BASED_BUILDER_DECORATOR(ImplicitFrom)
#undef X

#define X(FV, Name) \
operator basic_type() \
{ \
return this->m_val; \
} \
\
operator const basic_type() const \
{ \
return this->m_val; \
}
BASED_BUILDER_DECORATOR(ImplicitTo)
#undef X

#define X(FV, Name) \
friend constexpr bool operator==(FV lhs, FV rhs) \
{ \
return lhs.m_val == rhs.m_val; \
}
BASED_BUILDER_DECORATOR(Comparable)
#undef X

#define X(FV, Name) \
friend constexpr auto operator<=>(FV lhs, FV rhs) \
{ \
return lhs.m_val <=> rhs.m_val; \
}
BASED_BUILDER_DECORATOR(Ordered)
#undef X

#define X(FV, Name) \
constexpr auto& operator+=(FV rhs) \
{ \
this->m_val += rhs.m_val; \
return *this; \
} \
friend constexpr auto operator+(FV lhs, FV rhs) \
{ \
return FV(lhs.m_val + rhs.m_val); \
}
BASED_BUILDER_DECORATOR(Addable)
#undef X

#define X(FV, Name) \
constexpr auto& operator-=(FV rhs) \
{ \
this->m_val -= rhs.m_val; \
return *this; \
} \
friend constexpr auto operator-(FV lhs, FV rhs) \
{ \
return FV(lhs.m_val - rhs.m_val); \
}
BASED_BUILDER_DECORATOR(Subtractable)
#undef X

#define X(FV, Name) \
constexpr auto& operator*=(FV rhs) \
{ \
this->m_val *= rhs.m_val; \
return *this; \
} \
friend constexpr auto operator*(FV lhs, FV rhs) \
{ \
return FV(lhs.m_val * rhs.m_val); \
}
BASED_BUILDER_DECORATOR(Multipliable)
#undef X

#define X(FV, Name) \
constexpr auto& operator/=(FV rhs) \
{ \
this->m_val /= rhs.m_val; \
return *this; \
} \
friend constexpr auto operator/(FV lhs, FV rhs) \
{ \
return FV(lhs.m_val / rhs.m_val); \
}
BASED_BUILDER_DECORATOR(Divisible)
#undef X

#define X(FV, Name) \
constexpr auto& operator%=(FV rhs) \
{ \
this->m_val %= rhs.m_val; \
return *this; \
} \
friend constexpr auto operator%(FV lhs, FV rhs) \
{ \
return FV(lhs.m_val % rhs.m_val); \
}
BASED_BUILDER_DECORATOR(Modable)
#undef X

#define X(FV, Name) \
friend constexpr auto& operator++(FV& lhs) \
{ \
++lhs.value; \
return lhs; \
}
BASED_BUILDER_DECORATOR(PreIncrementable)
#undef X

#define X(FV, Name) \
friend constexpr auto operator++(FV lhs, int) \
{ \
return FV(lhs.m_val++); \
}
BASED_BUILDER_DECORATOR(PostIncrementable)
#undef X

#define X(FV, Name) \
friend constexpr auto& operator--(FV& lhs) \
{ \
--lhs.value; \
return lhs; \
}
BASED_BUILDER_DECORATOR(PreDecrementable)
#undef X

#define X(FV, Name) \
friend constexpr auto operator--(FV lhs, int) \
{ \
return FV(lhs.m_val--); \
}
BASED_BUILDER_DECORATOR(PostDecrementable)
#undef X

#define X(FV, Name) \
friend constexpr auto operator~(FV rhs) \
{ \
return FV(~rhs.m_val); \
}
BASED_BUILDER_DECORATOR(Notable)
#undef X

#define X(FV, Name) \
constexpr auto& operator&=(FV rhs) \
{ \
this->m_val &= rhs.m_val; \
return *this; \
} \
friend constexpr auto operator&(FV lhs, FV rhs) \
{ \
return FV(lhs.m_val & rhs.m_val); \
}
BASED_BUILDER_DECORATOR(Andable)
#undef X

#define X(FV, Name) \
constexpr auto& operator|=(FV rhs) \
{ \
this->m_val |= rhs.m_val; \
return *this; \
} \
friend constexpr auto operator|(FV lhs, FV rhs) \
{ \
return FV(lhs.m_val | rhs.m_val); \
}
BASED_BUILDER_DECORATOR(Orable)
#undef X

#define X(FV, Name) \
constexpr auto& operator^=(FV rhs) \
{ \
this->m_val ^= rhs.m_val; \
return *this; \
} \
friend constexpr auto operator^(FV lhs, FV rhs) \
{ \
return FV(lhs.m_val ^ rhs.m_val); \
}
BASED_BUILDER_DECORATOR(Xorable)
#undef X

#define X(FV, Name) \
constexpr auto& operator<<=(FV rhs) \
{ \
this->m_val <<= rhs.m_val; \
return *this; \
} \
friend constexpr auto operator<<(FV lhs, FV rhs) \
{ \
return FV(lhs.m_val << rhs.m_val); \
}
BASED_BUILDER_DECORATOR(LShiftable)
#undef X

#define X(FV, Name) \
constexpr auto& operator>>=(FV rhs) \
{ \
this->m_val >>= rhs.m_val; \
return *this; \
} \
friend constexpr auto operator>>(FV lhs, FV rhs) \
{ \
return FV(lhs.m_val >> rhs.m_val); \
}
BASED_BUILDER_DECORATOR(RShiftable)
#undef X

} // namespace based

// NOLINTEND(*macro-usage*,*macro-parentheses*,*naming*)

diff --git a/ include/based/types/literals.hpp b/ include/based/types/literals.hpp

@@ -1,76 +0,0 @@

#pragma once

#include "based/types/types.hpp"

// NOLINTBEGIN(google-runtime-int)

namespace based
{

namespace literals
{

consteval auto operator""_i(unsigned long long val)
{
return i::underlying_cast(val);
}

consteval i8 operator""_i8(unsigned long long val)
{
return i::underlying_cast(val);
}

consteval i16 operator""_i16(unsigned long long val)
{
return i::underlying_cast(val);
}

consteval i32 operator""_i32(unsigned long long val)
{
return i::underlying_cast(val);
}

consteval i64 operator""_i64(unsigned long long val)
{
return i::underlying_cast(val);
}

} // namespace literals

// Unsigned

namespace literals
{

consteval auto operator""_u(unsigned long long val)
{
return u::underlying_cast(val);
}

consteval u8 operator""_u8(unsigned long long val)
{
return u::underlying_cast(val);
}

consteval u16 operator""_u16(unsigned long long val)
{
return u::underlying_cast(val);
}

consteval u32 operator""_u32(unsigned long long val)
{
return u::underlying_cast(val);
}

consteval u64 operator""_u64(unsigned long long val)
{
return u::underlying_cast(val);
}

} // namespace literals

using namespace literals; // NOLINT(*namespace*)

} // namespace based

// NOLINTEND(google-runtime-int)

diff --git a/ include/based/types/nullptr.hpp b/ include/based/types/nullptr.hpp

@@ -1,8 +0,0 @@

#pragma once

namespace based
{

using nullptr_t = decltype(nullptr);

} // namespace based

diff --git a/ include/based/types/strong.hpp b/ include/based/types/strong.hpp

@@ -1,354 +0,0 @@

#pragma once

#include <compare>

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

namespace based
{

// NOLINTNEXTLINE(*macro*)
#define BASED_DETAIL_MACRO(decl, val) \
decltype(decl) \
{ \
static_cast<decltype(decl)::basic_type>(val) \
}

template<class V, class Tag>
// NOLINTBEGIN(*crtp*)
struct strong_type
{
using value_type = strong_type;
using basic_type = V;
using tag_type = Tag;

basic_type value;

constexpr ~strong_type() = default;

explicit constexpr strong_type()
: value(0)
{
}

explicit constexpr strong_type(basic_type val)
: value(val)
{
}

explicit constexpr operator basic_type() const { return value; }

constexpr strong_type(const strong_type&) = default;
constexpr strong_type(strong_type&&) = default;

constexpr strong_type& operator=(const strong_type&) = default;
constexpr strong_type& operator=(strong_type&&) = default;

template<class T>
static constexpr Tag underlying_cast(T value)
{
return Tag {static_cast<basic_type>(value)};
}

template<class T>
static constexpr Tag cast(T value)
{
return static_cast<Tag>(value);
}
};
// NOLINTEND(*crtp*)

template<class LHS, class RHS>
concept comparable = requires(LHS lhs, RHS rhs) { compare(lhs, rhs); };

template<class LHS, class RHS>
requires comparable<LHS, RHS>
constexpr bool operator==(LHS lhs, RHS rhs)
{
return lhs.value == rhs.value;
}

template<class LHS, class RHS>
concept ordered = requires(LHS lhs, RHS rhs) { order(lhs, rhs); };

template<class LHS, class RHS>
requires ordered<LHS, RHS>
constexpr auto operator<=>(LHS lhs, RHS rhs)
{
return lhs.value <=> rhs.value;
}

template<class LHS, class RHS>
concept addable = requires(LHS lhs, RHS rhs) { add(lhs, rhs); };

template<class LHS, class RHS>
requires addable<LHS, RHS>
constexpr auto operator+(LHS lhs, RHS rhs)
{
return BASED_DETAIL_MACRO(add(lhs, rhs), lhs.value + rhs.value);
}

template<class LHS, class RHS>
requires(requires(LHS lhs, RHS rhs) {
requires addable<LHS, RHS>;
requires SameAs<LHS, decltype(add(lhs, rhs))>;
})
constexpr auto& operator+=(LHS& lhs, RHS rhs)
{
return lhs = lhs + rhs;
}

template<class LHS, class RHS>
concept subtractable = requires(LHS lhs, RHS rhs) { sub(lhs, rhs); };

template<class LHS, class RHS>
requires subtractable<LHS, RHS>
constexpr auto operator-(LHS lhs, RHS rhs)
{
return BASED_DETAIL_MACRO(sub(lhs, rhs), lhs.value - rhs.value);
}

template<class LHS, class RHS>
requires(requires(LHS lhs, RHS rhs) {
requires subtractable<LHS, RHS>;
requires SameAs<LHS, decltype(sub(lhs, rhs))>;
})
constexpr auto& operator-=(LHS& lhs, RHS rhs)
{
return lhs = lhs - rhs;
}

template<class LHS, class RHS>
concept multiplyable = requires(LHS lhs, RHS rhs) { mul(lhs, rhs); };

template<class LHS, class RHS>
requires multiplyable<LHS, RHS>
constexpr auto operator*(LHS lhs, RHS rhs)
{
return BASED_DETAIL_MACRO(mul(lhs, rhs), lhs.value * rhs.value);
}

template<class LHS, class RHS>
requires(requires(LHS lhs, RHS rhs) {
requires multiplyable<LHS, RHS>;
requires SameAs<LHS, decltype(mul(lhs, rhs))>;
})
constexpr auto& operator*=(LHS& lhs, RHS rhs)
{
return lhs = lhs * rhs;
}

template<class LHS, class RHS>
concept divisible = requires(LHS lhs, RHS rhs) { div(lhs, rhs); };

template<class LHS, class RHS>
requires divisible<LHS, RHS>
constexpr auto operator/(LHS lhs, RHS rhs)
{
return BASED_DETAIL_MACRO(div(lhs, rhs), lhs.value / rhs.value);
}

template<class LHS, class RHS>
requires(requires(LHS lhs, RHS rhs) {
requires divisible<LHS, RHS>;
requires SameAs<LHS, decltype(div(lhs, rhs))>;
})
constexpr auto& operator/=(LHS& lhs, RHS rhs)
{
return lhs = lhs / rhs;
}

template<class LHS, class RHS>
concept modable = requires(LHS lhs, RHS rhs) { mod(lhs, rhs); };

template<class LHS, class RHS>
requires modable<LHS, RHS>
constexpr auto operator%(LHS lhs, RHS rhs)
{
return BASED_DETAIL_MACRO(mod(lhs, rhs), lhs.value % rhs.value);
}

template<class LHS, class RHS>
requires(requires(LHS lhs, RHS rhs) {
requires modable<LHS, RHS>;
requires SameAs<LHS, decltype(mod(lhs, rhs))>;
})
constexpr auto& operator%=(LHS& lhs, RHS rhs)
{
return lhs = lhs % rhs;
}

template<class LHS, class RHS>
concept lshiftable = requires(LHS lhs, RHS rhs) { lshift(lhs, rhs); };

template<class LHS, class RHS>
requires lshiftable<LHS, RHS>
constexpr auto operator<<(LHS lhs, RHS rhs)
{
return BASED_DETAIL_MACRO(lshift(lhs, rhs), lhs.value << rhs.value);
}

template<class LHS, class RHS>
requires(requires(LHS lhs, RHS rhs) {
requires lshiftable<LHS, RHS>;
requires SameAs<LHS, decltype(lshift(lhs, rhs))>;
})
constexpr auto& operator<<=(LHS& lhs, RHS rhs)
{
return lhs = lhs << rhs;
}

template<class LHS, class RHS>
concept rshiftable = requires(LHS lhs, RHS rhs) { rshift(lhs, rhs); };

template<class LHS, class RHS>
requires rshiftable<LHS, RHS>
constexpr auto operator>>(LHS lhs, RHS rhs)
{
return BASED_DETAIL_MACRO(rshift(lhs, rhs), lhs.value >> rhs.value);
}

template<class LHS, class RHS>
requires(requires(LHS lhs, RHS rhs) {
requires rshiftable<LHS, RHS>;
requires SameAs<LHS, decltype(rshift(lhs, rhs))>;
})
constexpr auto& operator>>=(LHS& lhs, RHS rhs)
{
return lhs = lhs >> rhs;
}

template<class LHS, class RHS>
concept andable = requires(LHS lhs, RHS rhs) { land(lhs, rhs); };

template<class LHS, class RHS>
requires andable<LHS, RHS>
constexpr auto operator&(LHS lhs, RHS rhs)
{
return BASED_DETAIL_MACRO(land(lhs, rhs), lhs.value & rhs.value);
}

template<class LHS, class RHS>
requires(requires(LHS lhs, RHS rhs) {
requires andable<LHS, RHS>;
requires SameAs<LHS, decltype(land(lhs, rhs))>;
})
constexpr auto& operator&=(LHS& lhs, RHS rhs)
{
return lhs = lhs & rhs;
}

template<class LHS, class RHS>
concept orable = requires(LHS lhs, RHS rhs) { lor(lhs, rhs); };

template<class LHS, class RHS>
requires orable<LHS, RHS>
constexpr auto operator|(LHS lhs, RHS rhs)
{
return BASED_DETAIL_MACRO(lor(lhs, rhs), lhs.value | rhs.value);
}

template<class LHS, class RHS>
requires(requires(LHS lhs, RHS rhs) {
requires orable<LHS, RHS>;
requires SameAs<LHS, decltype(lor(lhs, rhs))>;
})
constexpr auto& operator|=(LHS& lhs, RHS rhs)
{
return lhs = lhs | rhs;
}

template<class LHS, class RHS>
concept xorable = requires(LHS lhs, RHS rhs) { lxor(lhs, rhs); };

template<class LHS, class RHS>
requires xorable<LHS, RHS>
constexpr auto operator^(LHS lhs, RHS rhs)
{
return BASED_DETAIL_MACRO(lxor(lhs, rhs), lhs.value ^ rhs.value);
}

template<class LHS, class RHS>
requires(requires(LHS lhs, RHS rhs) {
requires xorable<LHS, RHS>;
requires SameAs<LHS, decltype(lxor(lhs, rhs))>;
})
constexpr auto& operator^=(LHS& lhs, RHS rhs)
{
return lhs = lhs ^ rhs;
}

template<class LHS>
concept lnotable = requires(LHS lhs) { lnot(lhs); };

template<class LHS>
requires lnotable<LHS>
constexpr auto operator~(LHS lhs)
{
lhs.value = ~lhs.value;
return lhs;
}

template<class LHS>
concept unariable = requires(LHS lhs) { unary(lhs); };

template<class LHS>
requires unariable<LHS>
constexpr auto operator+(LHS lhs)
{
return decltype(lhs)(+lhs.value);
}

template<class LHS>
requires unariable<LHS>
constexpr auto operator-(LHS lhs)
{
return decltype(lhs)(-lhs.value);
}

template<class LHS>
concept preincable = requires(LHS lhs) { preinc(lhs); };

template<class LHS>
requires preincable<LHS>
constexpr auto& operator++(LHS& lhs)
{
++lhs.value;
return lhs;
}

template<class LHS>
concept postincable = requires(LHS lhs) { postinc(lhs); };

template<class LHS>
requires postincable<LHS>
constexpr auto operator++(LHS& lhs, int)
{
return BASED_DETAIL_MACRO(postinc(lhs), lhs.value++);
}

template<class LHS>
concept predecable = requires(LHS lhs) { predec(lhs); };

template<class LHS>
requires predecable<LHS>
constexpr auto operator--(LHS& lhs)
{
--lhs.value;
return lhs;
}

template<class LHS>
concept postdecable = requires(LHS lhs) { postdec(lhs); };

template<class LHS>
requires postdecable<LHS>
constexpr auto operator--(LHS& lhs, int)
{
return BASED_DETAIL_MACRO(postdec(lhs), lhs.value--);
}

#undef BASED_DETAIL_MACRO

} // namespace based

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

@@ -1,314 +0,0 @@

#pragma once

#include "based/assert.hpp"
#include "based/macro/foreach_1.hpp"
#include "based/types/strong.hpp"

namespace based
{

// NOLINTBEGIN(google-runtime-int)

using size_t = unsigned long long int;

#define BASED_DETAIL_OP_UNARY(Prefix, Name, Index) \
auto Name(Prefix##8)->Prefix##8; \
auto Name(Prefix##16)->Prefix##16; \
auto Name(Prefix##32)->Prefix##32; \
auto Name(Prefix##64)->Prefix##64; \
auto Name(Prefix)->Prefix;

#define BASED_DETAIL_OP_BINARY(Prefix, Name, Index) \
auto Name(Prefix##8, Prefix##8)->Prefix##8; \
auto Name(Prefix##8, Prefix##16)->Prefix##16; \
auto Name(Prefix##8, Prefix##32)->Prefix##32; \
auto Name(Prefix##8, Prefix##64)->Prefix##64; \
\
auto Name(Prefix##16, Prefix##8)->Prefix##16; \
auto Name(Prefix##16, Prefix##16)->Prefix##16; \
auto Name(Prefix##16, Prefix##32)->Prefix##32; \
auto Name(Prefix##16, Prefix##64)->Prefix##64; \
\
auto Name(Prefix##32, Prefix##8)->Prefix##32; \
auto Name(Prefix##32, Prefix##16)->Prefix##32; \
auto Name(Prefix##32, Prefix##32)->Prefix##32; \
auto Name(Prefix##32, Prefix##64)->Prefix##64; \
\
auto Name(Prefix##64, Prefix##8)->Prefix##64; \
auto Name(Prefix##64, Prefix##16)->Prefix##64; \
auto Name(Prefix##64, Prefix##32)->Prefix##64; \
auto Name(Prefix##64, Prefix##64)->Prefix##64; \
\
auto Name(Prefix, Prefix)->Prefix;

template<class T>
struct limits;

struct i64 : strong_type<signed long long int, i64>
{
using strong_type::strong_type;
using strong_type::operator=;
};

struct i32 : strong_type<signed int, i32>
{
using strong_type::strong_type;
using strong_type::operator=;

explicit constexpr operator i64() { return i64::underlying_cast(value); }

[[nodiscard]] constexpr i64 to_i64() const { return i64::cast(*this); }
};

struct i16 : strong_type<signed short int, i16>
{
using strong_type::strong_type;
using strong_type::operator=;

explicit constexpr operator i64() { return i64::underlying_cast(value); }
explicit constexpr operator i32() { return i32::underlying_cast(value); }

[[nodiscard]] constexpr i64 to_i64() const { return i64::cast(*this); }
[[nodiscard]] constexpr i32 to_i32() const { return i32::cast(*this); }
};

struct i8 : strong_type<signed char, i8>
{
using strong_type::strong_type;
using strong_type::operator=;

explicit constexpr operator i64() { return i64::underlying_cast(value); }
explicit constexpr operator i32() { return i32::underlying_cast(value); }
explicit constexpr operator i16() { return i16::underlying_cast(value); }

[[nodiscard]] constexpr i64 to_i64() const { return i64::cast(*this); }
[[nodiscard]] constexpr i32 to_i32() const { return i32::cast(*this); }
[[nodiscard]] constexpr i16 to_i16() const { return i16::cast(*this); }
};

template<>
struct limits<i8>
{
static constexpr bool is_integer = true;
static constexpr bool is_signed = true;

static constexpr auto min = i8::underlying_cast(0x80);
static constexpr auto max = i8::underlying_cast(0x7F);
};

template<>
struct limits<i16>
{
static constexpr bool is_integer = true;
static constexpr bool is_signed = true;

static constexpr auto min = i16::underlying_cast(0x8000);
static constexpr auto max = i16::underlying_cast(0x7FFF);
};

template<>
struct limits<i32>
{
static constexpr bool is_integer = true;
static constexpr bool is_signed = true;

static constexpr auto min = i32::underlying_cast(0x80000000);
static constexpr auto max = i32::underlying_cast(0x7FFFFFFF);
};

template<>
struct limits<i64>
{
static constexpr bool is_integer = true;
static constexpr bool is_signed = true;

static constexpr auto min = i64::underlying_cast(0x8000000000000000);
static constexpr auto max = i64::underlying_cast(0x7FFFFFFFFFFFFFFF);
};

struct i : strong_type<signed long long int, i>
{
using strong_type::strong_type;
using strong_type::operator=;

consteval operator i8() const // NOLINT(*explicit*)
{
BASED_ASSERT(value >= limits<i8>::min.value);
BASED_ASSERT(value <= limits<i8>::max.value);
return i8::underlying_cast(value);
}

consteval operator i16() const // NOLINT(*explicit*)
{
BASED_ASSERT(value >= limits<i16>::min.value);
BASED_ASSERT(value <= limits<i16>::max.value);
return i16::underlying_cast(value);
}

consteval operator i32() const // NOLINT(*explicit*)
{
BASED_ASSERT(value >= limits<i32>::min.value);
BASED_ASSERT(value <= limits<i32>::max.value);
return i32::underlying_cast(value);
}

consteval operator i64() const // NOLINT(*explicit*)
{
BASED_ASSERT(value >= limits<i64>::min.value);
BASED_ASSERT(value <= limits<i64>::max.value);
return i64::underlying_cast(value);
}
};

auto unary(i) -> i;

struct u64 : strong_type<unsigned long long int, u64>
{
using strong_type::strong_type;
using strong_type::operator=;
};

struct u32 : strong_type<unsigned int, u32>
{
using strong_type::strong_type;
using strong_type::operator=;

explicit constexpr operator u64() { return u64::underlying_cast(value); }

[[nodiscard]] constexpr u64 to_u64() const { return u64::cast(*this); }
};

struct u16 : strong_type<unsigned short int, u16>
{
using strong_type::strong_type;
using strong_type::operator=;

explicit constexpr operator u64() { return u64::underlying_cast(value); }
explicit constexpr operator u32() { return u32::underlying_cast(value); }

[[nodiscard]] constexpr u64 to_u64() const { return u64::cast(*this); }
[[nodiscard]] constexpr u32 to_u32() const { return u32::cast(*this); }
};

struct u8 : strong_type<unsigned char, u8>
{
using strong_type::strong_type;
using strong_type::operator=;

explicit constexpr operator u64() { return u64::underlying_cast(value); }
explicit constexpr operator u32() { return u32::underlying_cast(value); }
explicit constexpr operator u16() { return u16::underlying_cast(value); }

[[nodiscard]] constexpr u64 to_u64() const { return u64::cast(*this); }
[[nodiscard]] constexpr u32 to_u32() const { return u32::cast(*this); }
[[nodiscard]] constexpr u16 to_u16() const { return u16::cast(*this); }
};

template<>
struct limits<u8>
{
static constexpr bool is_integer = true;
static constexpr bool is_signed = false;

static constexpr auto min = u8::underlying_cast(0x00);
static constexpr auto max = u8::underlying_cast(0xFF);
};

template<>
struct limits<u16>
{
static constexpr bool is_integer = true;
static constexpr bool is_signed = false;

static constexpr auto min = u16::underlying_cast(0x0000);
static constexpr auto max = u16::underlying_cast(0xFFFF);
};

template<>
struct limits<u32>
{
static constexpr bool is_integer = true;
static constexpr bool is_signed = false;

static constexpr auto min = u32::underlying_cast(0x00000000);
static constexpr auto max = u32::underlying_cast(0xFFFFFFFF);
};

template<>
struct limits<u64>
{
static constexpr bool is_integer = true;
static constexpr bool is_signed = false;

static constexpr auto min = u64::underlying_cast(0x0000000000000000);
static constexpr auto max = u64::underlying_cast(0xFFFFFFFFFFFFFFFF);
};

struct u : strong_type<unsigned long long int, u>
{
using strong_type::strong_type;

consteval operator u8() const // NOLINT(*explicit*)
{
BASED_ASSERT(value >= limits<u8>::min.value);
BASED_ASSERT(value <= limits<u8>::max.value);
return u8::underlying_cast(value);
}

consteval operator u16() const // NOLINT(*explicit*)
{
BASED_ASSERT(value >= limits<u16>::min.value);
BASED_ASSERT(value <= limits<u16>::max.value);
return u16::underlying_cast(value);
}

consteval operator u32() const // NOLINT(*explicit*)
{
BASED_ASSERT(value >= limits<u32>::min.value);
BASED_ASSERT(value <= limits<u32>::max.value);
return u32::underlying_cast(value);
}

consteval operator u64() const // NOLINT(*explicit*)
{
BASED_ASSERT(value >= limits<u64>::min.value);
BASED_ASSERT(value <= limits<u64>::max.value);
return u64::underlying_cast(value);
}
};

BASED_FOREACH_1(
i, BASED_DETAIL_OP_UNARY, unary, preinc, postinc, predec, postdec
)
BASED_FOREACH_1(
i, BASED_DETAIL_OP_BINARY, compare, order, add, sub, mul, div, mod
)

BASED_FOREACH_1(
u, BASED_DETAIL_OP_UNARY, preinc, postinc, predec, postdec, lnot
)

BASED_FOREACH_1(
u,
BASED_DETAIL_OP_BINARY,
compare,
order,
add,
sub,
mul,
div,
mod,
lshift,
rshift,
land,
lor,
lxor
)

#undef BASED_DETAIL_TYPE
#undef BASED_DETAIL_OP_UNARY
#undef BASED_DETAIL_OP_BINARY

// NOLINTEND(google-runtime-int)

} // namespace based

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

@@ -0,0 +1,24 @@

#pragma once

#include <cassert>

#define BASED_ASSERT assert

/*
#ifdef NDEBUG
# define BASED_ASSERT(EX)
#else
# define BASED_ASSERT(EX) \
(void)((EX) || (based::detail::assert(#EX, __FILE__, __LINE__), 0))
#endif

namespace based::detail
{

[[noreturn]] constexpr void assert(const char* msg, const char* file, int line)
{
throw "assertion failsed";
}

} // namespace based::detail
*/

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

@@ -4,7 +4,7 @@

#include <cstring>
#include <utility>

#include "based/types/types.hpp"
#include "based/integral/types.hpp"
#include "based/utility/forward.hpp"

namespace based

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

@@ -25,16 +25,15 @@ function(add_test DIR NAME)

catch_discover_tests("${NAME}")
endfunction()

## ----- Types -----
## ----- Integral -----

add_test(types strong_type_test)
add_test(types type_test)
add_test(types limits)
add_test(types literals)
add_test(integral strong_type_test)
add_test(integral type_test)
add_test(integral limits_test)
add_test(integral literals_test)

## ----- Trait -----


add_test(trait invoke_result_test)
add_test(trait is_array_test)
add_test(trait is_base_of_test)

@@ -53,14 +52,14 @@ add_test(trait remove_reference_test)

add_test(trait remove_volatile_test)
add_test(trait signature_test_test)

## ----- Concepts -----
## ----- Concept -----

add_test(concepts callable_test)
add_test(concept callable_test)

## ----- Algorithm -----

add_test(algorithms max_test)
add_test(algorithms min_test)
add_test(algorithm max_test)
add_test(algorithm min_test)

## ----- Utility -----

@@ -78,10 +77,6 @@ add_test(functional function_test)

add_test(enum standard_test)
add_test(enum bitmask_test)

## ----- List -----

add_test(. list_test)

## ----- String -----

add_test(string literal_test)

@@ -89,7 +84,11 @@ add_test(string format_test)


## ----- Char -----

add_test(char mapper_test)
add_test(character mapper_test)

## ----- Container -----

add_test(container list_test)

# ---- End-of-file commands ----

diff --git a/ test/source/algorithm/max_test.cpp b/ test/source/algorithm/max_test.cpp

@@ -0,0 +1,362 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include "based/algorithm/max.hpp"

#include <catch2/catch_test_macros.hpp>

#include "based/concept/is/same.hpp"
#include "based/utility/move.hpp"

// NOLINTBEGIN(*const-arg*,*const-correctness*,*after-move, *access-moved)

TEST_CASE("max(literal, literal) = right", "[algorithm/max]")
{
using res_t = decltype(based::max(3, 4));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(3, 4) == 4);
}

TEST_CASE("max(literal, literal) = left", "[algorithm/max]")
{
using res_t = decltype(based::max(4, 3));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(4, 3) == 4);
}

TEST_CASE("max(value, literal) = right", "[algorithm/max]")
{
int a = 3;

using res_t = decltype(based::max(a, 4));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, 4) == 4);
}

TEST_CASE("max(value, literal) = left", "[algorithm/max]")
{
int a = 4;

using res_t = decltype(based::max(a, 3));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, 3) == 4);
}

TEST_CASE("max(literal, value) = right", "[algorithm/max]")
{
int b = 4;

using res_t = decltype(based::max(3, b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(3, b) == 4);
}

TEST_CASE("max(literal, value) = left", "[algorithm/max]")
{
int b = 3;

using res_t = decltype(based::max(4, b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(4, b) == 4);
}

TEST_CASE("max(value, value) = right", "[algorithm/max]")
{
int a = 3;
int b = 4;

using res_t = decltype(based::max(a, b));

STATIC_REQUIRE(based::SameAs<int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}

TEST_CASE("max(value, value) = left", "[algorithm/max]")
{
int a = 4;
int b = 3;

using res_t = decltype(based::max(a, b));

STATIC_REQUIRE(based::SameAs<int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}

TEST_CASE("max(const value, literal) = right", "[algorithm/max]")
{
const int a = 3;

using res_t = decltype(based::max(a, 4));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, 4) == 4);
}

TEST_CASE("max(const value, literal) = left", "[algorithm/max]")
{
const int a = 4;

using res_t = decltype(based::max(a, 3));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, 3) == 4);
}

TEST_CASE("max(literal, const value) = right", "[algorithm/max]")
{
const int b = 4;

using res_t = decltype(based::max(3, b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(3, b) == 4);
}

TEST_CASE("max(literal, const value) = left", "[algorithm/max]")
{
const int b = 3;

using res_t = decltype(based::max(4, b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(4, b) == 4);
}

TEST_CASE("max(const value, const value) = right", "[algorithm/max]")
{
const int a = 3;
const int b = 4;

using res_t = decltype(based::max(a, b));

STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}

TEST_CASE("max(const value, const value) = left", "[algorithm/max]")
{
const int a = 4;
const int b = 3;

using res_t = decltype(based::max(a, b));

STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}

TEST_CASE("max(value, const value) = right", "[algorithm/max]")
{
int a = 3;
const int b = 4;

using res_t = decltype(based::max(a, b));

STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}

TEST_CASE("max(value, const value) = left", "[algorithm/max]")
{
int a = 4;
const int b = 3;

using res_t = decltype(based::max(a, b));

STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}

TEST_CASE("max(const value, value) = right", "[algorithm/max]")
{
const int a = 3;
int b = 4;

using res_t = decltype(based::max(a, b));

STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}

TEST_CASE("max(const value, value) = left", "[algorithm/max]")
{
const int a = 4;
int b = 3;

using res_t = decltype(based::max(a, b));

STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}

TEST_CASE("max(move, literal) = right", "[algorithm/max]")
{
int a = 3;

using res_t = decltype(based::max(based::move(a), 4));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(based::move(a), 4) == 4);
}

TEST_CASE("max(move, literal) = left", "[algorithm/max]")
{
int a = 4;

using res_t = decltype(based::max(based::move(a), 3));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(based::move(a), 3) == 4);
}

TEST_CASE("max(move, value) = right", "[algorithm/max]")
{
int a = 3;
int b = 4;

using res_t = decltype(based::max(based::move(a), b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(based::move(a), b) == 4);
}

TEST_CASE("max(move, value) = left", "[algorithm/max]")
{
int a = 4;
int b = 3;

using res_t = decltype(based::max(based::move(a), b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(based::move(a), b) == 4);
}

TEST_CASE("max(move, const value) = right", "[algorithm/max]")
{
int a = 3;
const int b = 4;

using res_t = decltype(based::max(based::move(a), b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(based::move(a), b) == 4);
}

TEST_CASE("max(move, const value) = left", "[algorithm/max]")
{
int a = 4;
const int b = 3;

using res_t = decltype(based::max(based::move(a), b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(based::move(a), b) == 4);
}

TEST_CASE("max(literal, move) = right", "[algorithm/max]")
{
int b = 4;

using res_t = decltype(based::max(3, based::move(b)));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(3, based::move(b)) == 4);
}

TEST_CASE("max(literal, move) = left", "[algorithm/max]")
{
int b = 3;

using res_t = decltype(based::max(4, based::move(b)));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(4, based::move(b)) == 4);
}

TEST_CASE("max(value, move) = right", "[algorithm/max]")
{
int a = 3;
int b = 4;

using res_t = decltype(based::max(a, based::move(b)));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, based::move(b)) == 4);
}

TEST_CASE("max(value, move) = left", "[algorithm/max]")
{
int a = 4;
int b = 3;

using res_t = decltype(based::max(a, based::move(b)));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, based::move(b)) == 4);
}

TEST_CASE("max(const value, move) = right", "[algorithm/max]")
{
const int a = 3;
int b = 4;

using res_t = decltype(based::max(a, based::move(b)));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, based::move(b)) == 4);
}

TEST_CASE("max(const value, move) = left", "[algorithm/max]")
{
const int a = 4;
int b = 3;

using res_t = decltype(based::max(a, based::move(b)));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, based::move(b)) == 4);
}

TEST_CASE("max(move, move) = right", "[algorithm/max]")
{
int a = 3;
int b = 4;

using res_t = decltype(based::max(based::move(a), based::move(b)));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(based::move(a), based::move(b)) == 4);
}

TEST_CASE("max(move, move) = left", "[algorithm/max]")
{
int a = 4;
int b = 3;

using res_t = decltype(based::max(based::move(a), based::move(b)));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(based::move(a), based::move(b)) == 4);
}

// NOLINTEND(*const-arg*,*const-correctness*,*after-move, *access-moved)

TEST_CASE("max-stability", "[algorithm/max]")
{
using type_t = std::pair<int, int>;

static const auto cmp = [](const type_t& x, const type_t& y)
{
return x.first < y.first;
};

const type_t a = {3, 4};
const type_t b = {3, 5};

REQUIRE(based::max(a, b, cmp).second == 5);
REQUIRE(based::max(b, a, cmp).second == 4);
}

diff --git a/ test/source/algorithm/min_test.cpp b/ test/source/algorithm/min_test.cpp

@@ -0,0 +1,361 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include "based/algorithm/min.hpp"

#include <catch2/catch_test_macros.hpp>

#include "based/utility/move.hpp"

// NOLINTBEGIN(*const-arg*,*const-correctness*,*after-move, *access-moved)

TEST_CASE("min(literal, literal) = left", "[algorithm/min]")
{
using res_t = decltype(based::min(3, 4));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(3, 4) == 3);
}

TEST_CASE("min(literal, literal) = right", "[algorithm/min]")
{
using res_t = decltype(based::min(4, 3));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(4, 3) == 3);
}

TEST_CASE("min(value, literal) = left", "[algorithm/min]")
{
int a = 3;

using res_t = decltype(based::min(a, 4));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, 4) == 3);
}

TEST_CASE("min(value, literal) = right", "[algorithm/min]")
{
int a = 4;

using res_t = decltype(based::min(a, 3));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, 3) == 3);
}

TEST_CASE("min(literal, value) = left", "[algorithm/min]")
{
int b = 4;

using res_t = decltype(based::min(3, b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(3, b) == 3);
}

TEST_CASE("min(literal, value) = right", "[algorithm/min]")
{
int b = 3;

using res_t = decltype(based::min(4, b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(4, b) == 3);
}

TEST_CASE("min(value, value) = left", "[algorithm/min]")
{
int a = 3;
int b = 4;

using res_t = decltype(based::min(a, b));

STATIC_REQUIRE(based::SameAs<int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}

TEST_CASE("min(value, value) = right", "[algorithm/min]")
{
int a = 4;
int b = 3;

using res_t = decltype(based::min(a, b));

STATIC_REQUIRE(based::SameAs<int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}

TEST_CASE("min(const value, literal) = left", "[algorithm/min]")
{
const int a = 3;

using res_t = decltype(based::min(a, 4));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, 4) == 3);
}

TEST_CASE("min(const value, literal) = right", "[algorithm/min]")
{
const int a = 4;

using res_t = decltype(based::min(a, 3));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, 3) == 3);
}

TEST_CASE("min(literal, const value) = left", "[algorithm/min]")
{
const int b = 4;

using res_t = decltype(based::min(3, b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(3, b) == 3);
}

TEST_CASE("min(literal, const value) = right", "[algorithm/min]")
{
const int b = 3;

using res_t = decltype(based::min(4, b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(4, b) == 3);
}

TEST_CASE("min(const value, const value) = left", "[algorithm/min]")
{
const int a = 3;
const int b = 4;

using res_t = decltype(based::min(a, b));

STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}

TEST_CASE("min(const value, const value) = right", "[algorithm/min]")
{
const int a = 4;
const int b = 3;

using res_t = decltype(based::min(a, b));

STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}

TEST_CASE("min(value, const value) = left", "[algorithm/min]")
{
int a = 3;
const int b = 4;

using res_t = decltype(based::min(a, b));

STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}

TEST_CASE("min(value, const value) = right", "[algorithm/min]")
{
int a = 4;
const int b = 3;

using res_t = decltype(based::min(a, b));

STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}

TEST_CASE("min(const value, value) = left", "[algorithm/min]")
{
const int a = 3;
int b = 4;

using res_t = decltype(based::min(a, b));

STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}

TEST_CASE("min(const value, value) = right", "[algorithm/min]")
{
const int a = 4;
int b = 3;

using res_t = decltype(based::min(a, b));

STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}

TEST_CASE("min(move, literal) = left", "[algorithm/min]")
{
int a = 3;

using res_t = decltype(based::min(based::move(a), 4));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(based::move(a), 4) == 3);
}

TEST_CASE("min(move, literal) = right", "[algorithm/min]")
{
int a = 4;

using res_t = decltype(based::min(based::move(a), 3));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(based::move(a), 3) == 3);
}

TEST_CASE("min(move, value) = left", "[algorithm/min]")
{
int a = 3;
int b = 4;

using res_t = decltype(based::min(based::move(a), b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(based::move(a), b) == 3);
}

TEST_CASE("min(move, value) = right", "[algorithm/min]")
{
int a = 4;
int b = 3;

using res_t = decltype(based::min(based::move(a), b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(based::move(a), b) == 3);
}

TEST_CASE("min(move, const value) = left", "[algorithm/min]")
{
int a = 3;
const int b = 4;

using res_t = decltype(based::min(based::move(a), b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(based::move(a), b) == 3);
}

TEST_CASE("min(move, const value) = right", "[algorithm/min]")
{
int a = 4;
const int b = 3;

using res_t = decltype(based::min(based::move(a), b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(based::move(a), b) == 3);
}

TEST_CASE("min(literal, move) = left", "[algorithm/min]")
{
int b = 4;

using res_t = decltype(based::min(3, based::move(b)));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(3, based::move(b)) == 3);
}

TEST_CASE("min(literal, move) = right", "[algorithm/min]")
{
int b = 3;

using res_t = decltype(based::min(4, based::move(b)));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(4, based::move(b)) == 3);
}

TEST_CASE("min(value, move) = left", "[algorithm/min]")
{
int a = 3;
int b = 4;

using res_t = decltype(based::min(a, based::move(b)));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, based::move(b)) == 3);
}

TEST_CASE("min(value, move) = right", "[algorithm/min]")
{
int a = 4;
int b = 3;

using res_t = decltype(based::min(a, based::move(b)));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, based::move(b)) == 3);
}

TEST_CASE("min(const value, move) = left", "[algorithm/min]")
{
const int a = 3;
int b = 4;

using res_t = decltype(based::min(a, based::move(b)));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, based::move(b)) == 3);
}

TEST_CASE("min(const value, move) = right", "[algorithm/min]")
{
const int a = 4;
int b = 3;

using res_t = decltype(based::min(a, based::move(b)));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, based::move(b)) == 3);
}

TEST_CASE("min(move, move) = left", "[algorithm/min]")
{
int a = 3;
int b = 4;

using res_t = decltype(based::min(based::move(a), based::move(b)));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(based::move(a), based::move(b)) == 3);
}

TEST_CASE("min(move, move) = right", "[algorithm/min]")
{
int a = 4;
int b = 3;

using res_t = decltype(based::min(based::move(a), based::move(b)));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(based::move(a), based::move(b)) == 3);
}

// NOLINTEND(*const-arg*,*const-correctness*,*after-move, *access-moved)

TEST_CASE("min-stability", "[algorithm/min]")
{
using type_t = std::pair<int, int>;

static const auto cmp = [](const type_t& x, const type_t& y)
{
return x.first < y.first;
};

const type_t a = {3, 4};
const type_t b = {3, 5};

REQUIRE(based::min(a, b, cmp).second == 4);
REQUIRE(based::min(b, a, cmp).second == 5);
}

diff --git a/ test/source/algorithms/max_test.cpp b/ test/source/algorithms/max_test.cpp

@@ -1,362 +0,0 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include "based/algorithms/max.hpp"

#include <catch2/catch_test_macros.hpp>

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

// NOLINTBEGIN(*const-arg*,*const-correctness*,*after-move, *access-moved)

TEST_CASE("max(literal, literal) = right", "[algorithm/max]")
{
using res_t = decltype(based::max(3, 4));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(3, 4) == 4);
}

TEST_CASE("max(literal, literal) = left", "[algorithm/max]")
{
using res_t = decltype(based::max(4, 3));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(4, 3) == 4);
}

TEST_CASE("max(value, literal) = right", "[algorithm/max]")
{
int a = 3;

using res_t = decltype(based::max(a, 4));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, 4) == 4);
}

TEST_CASE("max(value, literal) = left", "[algorithm/max]")
{
int a = 4;

using res_t = decltype(based::max(a, 3));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, 3) == 4);
}

TEST_CASE("max(literal, value) = right", "[algorithm/max]")
{
int b = 4;

using res_t = decltype(based::max(3, b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(3, b) == 4);
}

TEST_CASE("max(literal, value) = left", "[algorithm/max]")
{
int b = 3;

using res_t = decltype(based::max(4, b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(4, b) == 4);
}

TEST_CASE("max(value, value) = right", "[algorithm/max]")
{
int a = 3;
int b = 4;

using res_t = decltype(based::max(a, b));

STATIC_REQUIRE(based::SameAs<int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}

TEST_CASE("max(value, value) = left", "[algorithm/max]")
{
int a = 4;
int b = 3;

using res_t = decltype(based::max(a, b));

STATIC_REQUIRE(based::SameAs<int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}

TEST_CASE("max(const value, literal) = right", "[algorithm/max]")
{
const int a = 3;

using res_t = decltype(based::max(a, 4));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, 4) == 4);
}

TEST_CASE("max(const value, literal) = left", "[algorithm/max]")
{
const int a = 4;

using res_t = decltype(based::max(a, 3));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, 3) == 4);
}

TEST_CASE("max(literal, const value) = right", "[algorithm/max]")
{
const int b = 4;

using res_t = decltype(based::max(3, b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(3, b) == 4);
}

TEST_CASE("max(literal, const value) = left", "[algorithm/max]")
{
const int b = 3;

using res_t = decltype(based::max(4, b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(4, b) == 4);
}

TEST_CASE("max(const value, const value) = right", "[algorithm/max]")
{
const int a = 3;
const int b = 4;

using res_t = decltype(based::max(a, b));

STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}

TEST_CASE("max(const value, const value) = left", "[algorithm/max]")
{
const int a = 4;
const int b = 3;

using res_t = decltype(based::max(a, b));

STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}

TEST_CASE("max(value, const value) = right", "[algorithm/max]")
{
int a = 3;
const int b = 4;

using res_t = decltype(based::max(a, b));

STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}

TEST_CASE("max(value, const value) = left", "[algorithm/max]")
{
int a = 4;
const int b = 3;

using res_t = decltype(based::max(a, b));

STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}

TEST_CASE("max(const value, value) = right", "[algorithm/max]")
{
const int a = 3;
int b = 4;

using res_t = decltype(based::max(a, b));

STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}

TEST_CASE("max(const value, value) = left", "[algorithm/max]")
{
const int a = 4;
int b = 3;

using res_t = decltype(based::max(a, b));

STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::max(a, b) == 4);
}

TEST_CASE("max(move, literal) = right", "[algorithm/max]")
{
int a = 3;

using res_t = decltype(based::max(based::move(a), 4));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(based::move(a), 4) == 4);
}

TEST_CASE("max(move, literal) = left", "[algorithm/max]")
{
int a = 4;

using res_t = decltype(based::max(based::move(a), 3));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(based::move(a), 3) == 4);
}

TEST_CASE("max(move, value) = right", "[algorithm/max]")
{
int a = 3;
int b = 4;

using res_t = decltype(based::max(based::move(a), b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(based::move(a), b) == 4);
}

TEST_CASE("max(move, value) = left", "[algorithm/max]")
{
int a = 4;
int b = 3;

using res_t = decltype(based::max(based::move(a), b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(based::move(a), b) == 4);
}

TEST_CASE("max(move, const value) = right", "[algorithm/max]")
{
int a = 3;
const int b = 4;

using res_t = decltype(based::max(based::move(a), b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(based::move(a), b) == 4);
}

TEST_CASE("max(move, const value) = left", "[algorithm/max]")
{
int a = 4;
const int b = 3;

using res_t = decltype(based::max(based::move(a), b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(based::move(a), b) == 4);
}

TEST_CASE("max(literal, move) = right", "[algorithm/max]")
{
int b = 4;

using res_t = decltype(based::max(3, based::move(b)));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(3, based::move(b)) == 4);
}

TEST_CASE("max(literal, move) = left", "[algorithm/max]")
{
int b = 3;

using res_t = decltype(based::max(4, based::move(b)));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(4, based::move(b)) == 4);
}

TEST_CASE("max(value, move) = right", "[algorithm/max]")
{
int a = 3;
int b = 4;

using res_t = decltype(based::max(a, based::move(b)));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, based::move(b)) == 4);
}

TEST_CASE("max(value, move) = left", "[algorithm/max]")
{
int a = 4;
int b = 3;

using res_t = decltype(based::max(a, based::move(b)));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, based::move(b)) == 4);
}

TEST_CASE("max(const value, move) = right", "[algorithm/max]")
{
const int a = 3;
int b = 4;

using res_t = decltype(based::max(a, based::move(b)));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, based::move(b)) == 4);
}

TEST_CASE("max(const value, move) = left", "[algorithm/max]")
{
const int a = 4;
int b = 3;

using res_t = decltype(based::max(a, based::move(b)));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::max(a, based::move(b)) == 4);
}

TEST_CASE("max(move, move) = right", "[algorithm/max]")
{
int a = 3;
int b = 4;

using res_t = decltype(based::max(based::move(a), based::move(b)));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(based::move(a), based::move(b)) == 4);
}

TEST_CASE("max(move, move) = left", "[algorithm/max]")
{
int a = 4;
int b = 3;

using res_t = decltype(based::max(based::move(a), based::move(b)));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::max(based::move(a), based::move(b)) == 4);
}

// NOLINTEND(*const-arg*,*const-correctness*,*after-move, *access-moved)

TEST_CASE("max-stability", "[algorithm/max]")
{
using type_t = std::pair<int, int>;

static const auto cmp = [](const type_t& x, const type_t& y)
{
return x.first < y.first;
};

const type_t a = {3, 4};
const type_t b = {3, 5};

REQUIRE(based::max(a, b, cmp).second == 5);
REQUIRE(based::max(b, a, cmp).second == 4);
}

diff --git a/ test/source/algorithms/min_test.cpp b/ test/source/algorithms/min_test.cpp

@@ -1,361 +0,0 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include "based/algorithms/min.hpp"

#include <catch2/catch_test_macros.hpp>

#include "based/utility/move.hpp"

// NOLINTBEGIN(*const-arg*,*const-correctness*,*after-move, *access-moved)

TEST_CASE("min(literal, literal) = left", "[algorithm/min]")
{
using res_t = decltype(based::min(3, 4));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(3, 4) == 3);
}

TEST_CASE("min(literal, literal) = right", "[algorithm/min]")
{
using res_t = decltype(based::min(4, 3));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(4, 3) == 3);
}

TEST_CASE("min(value, literal) = left", "[algorithm/min]")
{
int a = 3;

using res_t = decltype(based::min(a, 4));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, 4) == 3);
}

TEST_CASE("min(value, literal) = right", "[algorithm/min]")
{
int a = 4;

using res_t = decltype(based::min(a, 3));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, 3) == 3);
}

TEST_CASE("min(literal, value) = left", "[algorithm/min]")
{
int b = 4;

using res_t = decltype(based::min(3, b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(3, b) == 3);
}

TEST_CASE("min(literal, value) = right", "[algorithm/min]")
{
int b = 3;

using res_t = decltype(based::min(4, b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(4, b) == 3);
}

TEST_CASE("min(value, value) = left", "[algorithm/min]")
{
int a = 3;
int b = 4;

using res_t = decltype(based::min(a, b));

STATIC_REQUIRE(based::SameAs<int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}

TEST_CASE("min(value, value) = right", "[algorithm/min]")
{
int a = 4;
int b = 3;

using res_t = decltype(based::min(a, b));

STATIC_REQUIRE(based::SameAs<int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}

TEST_CASE("min(const value, literal) = left", "[algorithm/min]")
{
const int a = 3;

using res_t = decltype(based::min(a, 4));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, 4) == 3);
}

TEST_CASE("min(const value, literal) = right", "[algorithm/min]")
{
const int a = 4;

using res_t = decltype(based::min(a, 3));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, 3) == 3);
}

TEST_CASE("min(literal, const value) = left", "[algorithm/min]")
{
const int b = 4;

using res_t = decltype(based::min(3, b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(3, b) == 3);
}

TEST_CASE("min(literal, const value) = right", "[algorithm/min]")
{
const int b = 3;

using res_t = decltype(based::min(4, b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(4, b) == 3);
}

TEST_CASE("min(const value, const value) = left", "[algorithm/min]")
{
const int a = 3;
const int b = 4;

using res_t = decltype(based::min(a, b));

STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}

TEST_CASE("min(const value, const value) = right", "[algorithm/min]")
{
const int a = 4;
const int b = 3;

using res_t = decltype(based::min(a, b));

STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}

TEST_CASE("min(value, const value) = left", "[algorithm/min]")
{
int a = 3;
const int b = 4;

using res_t = decltype(based::min(a, b));

STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}

TEST_CASE("min(value, const value) = right", "[algorithm/min]")
{
int a = 4;
const int b = 3;

using res_t = decltype(based::min(a, b));

STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}

TEST_CASE("min(const value, value) = left", "[algorithm/min]")
{
const int a = 3;
int b = 4;

using res_t = decltype(based::min(a, b));

STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}

TEST_CASE("min(const value, value) = right", "[algorithm/min]")
{
const int a = 4;
int b = 3;

using res_t = decltype(based::min(a, b));

STATIC_REQUIRE(based::SameAs<const int&, res_t>);
REQUIRE(based::min(a, b) == 3);
}

TEST_CASE("min(move, literal) = left", "[algorithm/min]")
{
int a = 3;

using res_t = decltype(based::min(based::move(a), 4));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(based::move(a), 4) == 3);
}

TEST_CASE("min(move, literal) = right", "[algorithm/min]")
{
int a = 4;

using res_t = decltype(based::min(based::move(a), 3));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(based::move(a), 3) == 3);
}

TEST_CASE("min(move, value) = left", "[algorithm/min]")
{
int a = 3;
int b = 4;

using res_t = decltype(based::min(based::move(a), b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(based::move(a), b) == 3);
}

TEST_CASE("min(move, value) = right", "[algorithm/min]")
{
int a = 4;
int b = 3;

using res_t = decltype(based::min(based::move(a), b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(based::move(a), b) == 3);
}

TEST_CASE("min(move, const value) = left", "[algorithm/min]")
{
int a = 3;
const int b = 4;

using res_t = decltype(based::min(based::move(a), b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(based::move(a), b) == 3);
}

TEST_CASE("min(move, const value) = right", "[algorithm/min]")
{
int a = 4;
const int b = 3;

using res_t = decltype(based::min(based::move(a), b));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(based::move(a), b) == 3);
}

TEST_CASE("min(literal, move) = left", "[algorithm/min]")
{
int b = 4;

using res_t = decltype(based::min(3, based::move(b)));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(3, based::move(b)) == 3);
}

TEST_CASE("min(literal, move) = right", "[algorithm/min]")
{
int b = 3;

using res_t = decltype(based::min(4, based::move(b)));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(4, based::move(b)) == 3);
}

TEST_CASE("min(value, move) = left", "[algorithm/min]")
{
int a = 3;
int b = 4;

using res_t = decltype(based::min(a, based::move(b)));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, based::move(b)) == 3);
}

TEST_CASE("min(value, move) = right", "[algorithm/min]")
{
int a = 4;
int b = 3;

using res_t = decltype(based::min(a, based::move(b)));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, based::move(b)) == 3);
}

TEST_CASE("min(const value, move) = left", "[algorithm/min]")
{
const int a = 3;
int b = 4;

using res_t = decltype(based::min(a, based::move(b)));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, based::move(b)) == 3);
}

TEST_CASE("min(const value, move) = right", "[algorithm/min]")
{
const int a = 4;
int b = 3;

using res_t = decltype(based::min(a, based::move(b)));

STATIC_REQUIRE(based::SameAs<int, res_t>);
REQUIRE(based::min(a, based::move(b)) == 3);
}

TEST_CASE("min(move, move) = left", "[algorithm/min]")
{
int a = 3;
int b = 4;

using res_t = decltype(based::min(based::move(a), based::move(b)));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(based::move(a), based::move(b)) == 3);
}

TEST_CASE("min(move, move) = right", "[algorithm/min]")
{
int a = 4;
int b = 3;

using res_t = decltype(based::min(based::move(a), based::move(b)));

STATIC_REQUIRE(based::SameAs<int&&, res_t>);
REQUIRE(based::min(based::move(a), based::move(b)) == 3);
}

// NOLINTEND(*const-arg*,*const-correctness*,*after-move, *access-moved)

TEST_CASE("min-stability", "[algorithm/min]")
{
using type_t = std::pair<int, int>;

static const auto cmp = [](const type_t& x, const type_t& y)
{
return x.first < y.first;
};

const type_t a = {3, 4};
const type_t b = {3, 5};

REQUIRE(based::min(a, b, cmp).second == 4);
REQUIRE(based::min(b, a, cmp).second == 5);
}

diff --git a/ test/source/char/mapper_test.cpp b/ test/source/char/mapper_test.cpp

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

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include "based/char/mapper.hpp"

#include <catch2/catch_test_macros.hpp>

#include "based/char/character.hpp"

struct test
{
constexpr bool operator()(based::character chr) const { return chr >= '\0'; }
};

template class based::mapper<test>;

TEST_CASE("mapper", "[char/mapper]")
{
REQUIRE(true);
}

diff --git a/ test/source/character/mapper_test.cpp b/ test/source/character/mapper_test.cpp

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

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include "based/character/mapper.hpp"

#include <catch2/catch_test_macros.hpp>

#include "based/character/type.hpp"

struct test
{
constexpr bool operator()(based::character chr) const { return chr >= '\0'; }
};

template class based::mapper<test>;

TEST_CASE("mapper", "[character/mapper]")
{
REQUIRE(true);
}

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

@@ -0,0 +1,60 @@

// #define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include "based/concept/callable.hpp"

#include <catch2/catch_test_macros.hpp>

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

namespace
{

// NOLINTNEXTLINE(*need*)
int free_func(int a, double b)
{
return static_cast<int>(a + b);
}

} // namespace

using based::SameAs;

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

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

TEST_CASE("lambda", "[concept/callable]")
{
const auto func = [](int a, double b)
{
return static_cast<int>(a + b);
};
using type_t = decltype(func);

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

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

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

// based::error_template<decltype(&func::template operator()<int, double>)>();
STATIC_REQUIRE(based::Callable<func>);
STATIC_REQUIRE(SameAs<based::callable_sig_t<func>, int(int, double)>);
STATIC_REQUIRE(SameAs<based::callable_ret_t<func>, int>);
}
*/

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

@@ -1,60 +0,0 @@

// #define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include "based/concepts/callable.hpp"

#include <catch2/catch_test_macros.hpp>

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

namespace
{

// NOLINTNEXTLINE(*need*)
int free_func(int a, double b)
{
return static_cast<int>(a + b);
}

} // namespace

using based::SameAs;

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

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

TEST_CASE("lambda", "[trait/callable]")
{
const auto func = [](int a, double b)
{
return static_cast<int>(a + b);
};
using type_t = decltype(func);

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

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

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

// based::error_template<decltype(&func::template operator()<int, double>)>();
STATIC_REQUIRE(based::Callable<func>);
STATIC_REQUIRE(SameAs<based::callable_sig_t<func>, int(int, double)>);
STATIC_REQUIRE(SameAs<based::callable_ret_t<func>, int>);
}
*/

diff --git a/ test/source/container/list_test.cpp b/ test/source/container/list_test.cpp

@@ -0,0 +1,209 @@

#include <numeric>

#include "based/container/list.hpp"

#include <catch2/catch_test_macros.hpp>

#include "based/integral/literals.hpp"

template class based::list_pool<based::u8, based::u8>;

// NOLINTBEGIN(*complexity*)

TEST_CASE("list_pool", "[container/list_pool]")
{
using namespace based::literals; // NOLINT(*namespace*)
using list_pool = based::list_pool<based::u8, based::u8>;

auto pool = list_pool();
auto head = pool.node_empty();

SECTION("node_empty is empty")
{
REQUIRE(pool.is_empty(head) == true);
REQUIRE(pool.node_empty() == head);
}

SECTION("add one node")
{
head = pool.allocate(1_u8, head);

REQUIRE(pool.is_empty(head) == false);
REQUIRE(pool.value(head) == 1_u8);

REQUIRE(pool.next(head) == pool.node_empty());

SECTION("add two nodes")
{
head = pool.allocate(2_u8, head);

REQUIRE(pool.is_empty(head) == false);
REQUIRE(pool.value(head) == 2_u8);

REQUIRE(pool.value(pool.next(head)) == 1_u8);
REQUIRE(pool.next(pool.next(head)) == pool.node_empty());

head = pool.free(head);
}

SECTION("alloc after free")
{
head = pool.allocate(2_u8, head);
head = pool.free(head);
head = pool.allocate(3_u8, head);

REQUIRE(pool.is_empty(head) == false);
REQUIRE(pool.value(head) == 3_u8);

head = pool.free(head);
}

head = pool.free(head);
}

REQUIRE(pool.is_empty(head) == true);
REQUIRE(pool.node_empty() == head);
}

TEST_CASE("list_pool iterator", "[container/list_pool]")
{
using namespace based::literals; // NOLINT(*namespace*)
using list_pool = based::list_pool<based::u8, based::u8>;

auto pool = list_pool();
auto head = pool.node_empty();

static constexpr auto iter_count = 255_u8;
for (auto i = 0_u8; i < iter_count; i++) {
head = pool.allocate(i, head);
}

SECTION("for-loop")
{
using iter = list_pool::iterator;

auto sum = 0_u32;
for (auto it = iter(pool, head); it != iter(pool); it++) {
sum += *it.operator->();
sum += *it;
}

REQUIRE(sum == 255_u32 * 254_u32);
}

SECTION("accumulate")
{
using iter = list_pool::iterator;

const auto sum = std::accumulate(
iter(pool, head),
iter(pool),
based::u32 {0},
[](auto a, auto b)
{
return a + b;
}
);

REQUIRE(sum == 255_u32 * 254_u32 / 2_u32);
}

based::free_list(pool, head);
}

TEST_CASE("list_pool const iterator", "[container/list_pool]")
{
using namespace based::literals; // NOLINT(*namespace*)
using list_pool = based::list_pool<based::u8, based::u8>;

auto pool = list_pool();
auto head = pool.node_empty();

static constexpr auto iter_count = 255_u8;
for (auto i = 0_u8; i < iter_count; i++) {
head = pool.allocate(i, head);
}

SECTION("const for-loop")
{
using iter = list_pool::const_iterator;

auto sum = 0_u32;
for (auto it = iter(pool, head); it != iter(pool); it++) {
sum += *it.operator->();
sum += *it;
}

REQUIRE(sum == 255_u32 * 254_u32);
}

SECTION("const accumulate")
{
using iter = list_pool::const_iterator;

static const auto sum =
[](const list_pool& lpool, const list_pool::list_type& lhead)
{
return std::accumulate(
iter(lpool, lhead),
iter(lpool),
based::u32 {0},
[](auto a, auto b)
{
return a + b;
}
);
};

REQUIRE(sum(pool, head) == 255_u32 * 254_u32 / 2_u32);
}

based::free_list(pool, head);
}

TEST_CASE("list_pool queue", "[container/list_pool/queue]")
{
using list_pool = based::list_pool<based::u8, based::u8>;
using iter = list_pool::iterator;

auto pool = list_pool();
auto queue = pool.queue_empty();

SECTION("free(empty, empty)")
{
REQUIRE(pool.free(queue.first, queue.second) == pool.node_empty());
}

SECTION("pop_front(empty)")
{
REQUIRE(pool.pop_front(queue) == queue);
}

SECTION("operation")
{
using namespace based::literals; // NOLINT(*namespace*)
static constexpr auto iter_count = 255_u8;
for (auto i = 0_u8; i < iter_count; i++) {
if (i % 2_u8 == 0_u8) {
queue = pool.push_front(queue, i);
} else {
queue = pool.push_back(queue, i);
}

if (i % 3_u8 == 0_u8) {
queue = pool.pop_front(queue);
}
}

auto sum = 0_u64;
for (auto it = iter(pool, queue.first); it != iter(pool); ++it) {
sum += *it;
}

pool.free(queue);

REQUIRE(sum == 21717_u64);
}
}

// NOLINTEND(*complexity*)

diff --git a/ test/source/enum/bitmask_test.cpp b/ test/source/enum/bitmask_test.cpp

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


#include <catch2/catch_test_macros.hpp>

#include "based/concepts/is/same.hpp"
#include "based/types/types.hpp"
#include "based/concept/is/same.hpp"
#include "based/integral/types.hpp"

BASED_ENUM_BITMASK(var, based::u8) {
a = 1,

diff --git a/ test/source/enum/standard_test.cpp b/ test/source/enum/standard_test.cpp

@@ -2,9 +2,9 @@


#include <catch2/catch_test_macros.hpp>

#include "based/concepts/is/invocable.hpp"
#include "based/concept/is/invocable.hpp"
#include "based/enum/enum.hpp"
#include "based/types/types.hpp"
#include "based/integral/types.hpp"

struct test
{

diff --git a/ test/source/integral/limits_test.cpp b/ test/source/integral/limits_test.cpp

@@ -0,0 +1,33 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include <catch2/catch_test_macros.hpp>

#include "based/integral/types.hpp"

using based::limits;

TEST_CASE("unsigned", "[integral/literals]")
{
STATIC_REQUIRE(limits<based::u8>::min.value == 0ULL);
STATIC_REQUIRE(limits<based::u16>::min.value == 0ULL);
STATIC_REQUIRE(limits<based::u32>::min.value == 0ULL);
STATIC_REQUIRE(limits<based::u64>::min.value == 0ULL);

STATIC_REQUIRE(limits<based::u8>::max.value == 255ULL);
STATIC_REQUIRE(limits<based::u16>::max.value == 65535ULL);
STATIC_REQUIRE(limits<based::u32>::max.value == 4294967295ULL);
STATIC_REQUIRE(limits<based::u64>::max.value == 18446744073709551615ULL);
}

TEST_CASE("signed", "[integral/literals]")
{
STATIC_REQUIRE(limits<based::i8>::min.value == -128LL);
STATIC_REQUIRE(limits<based::i16>::min.value == -32768LL);
STATIC_REQUIRE(limits<based::i32>::min.value == -2147483648LL);
STATIC_REQUIRE(limits<based::i64>::min.value == -9223372036854775807LL - 1);

STATIC_REQUIRE(limits<based::i8>::max.value == 127LL);
STATIC_REQUIRE(limits<based::i16>::max.value == 32767LL);
STATIC_REQUIRE(limits<based::i32>::max.value == 2147483647LL);
STATIC_REQUIRE(limits<based::i64>::max.value == 9223372036854775807LL);
}

diff --git a/ test/source/integral/literals_test.cpp b/ test/source/integral/literals_test.cpp

@@ -0,0 +1,41 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include "based/integral/literals.hpp"

#include <catch2/catch_test_macros.hpp>

#include "based/concept/is/castable.hpp"

using namespace based::literals; // NOLINT(*namespace*)

using based::CastableTo;

TEST_CASE("unsigned", "[integral/literals]")
{
STATIC_REQUIRE(CastableTo<decltype(0_u), based::u8>);
STATIC_REQUIRE(CastableTo<decltype(255_u), based::u8>);
STATIC_REQUIRE(CastableTo<decltype(256_u), based::u16>);
STATIC_REQUIRE(CastableTo<decltype(65535_u), based::u16>);
STATIC_REQUIRE(CastableTo<decltype(65536_u), based::u32>);
STATIC_REQUIRE(CastableTo<decltype(4294967295_u), based::u32>);
STATIC_REQUIRE(CastableTo<decltype(4294967296_u), based::u64>);
STATIC_REQUIRE(CastableTo<decltype(18446744073709551615_u), based::u64>);
}

TEST_CASE("signed", "[integral/literals]")
{
STATIC_REQUIRE(CastableTo<decltype(0_i), based::i8>);
STATIC_REQUIRE(CastableTo<decltype(127_i), based::i8>);
STATIC_REQUIRE(CastableTo<decltype(128_i), based::i16>);
STATIC_REQUIRE(CastableTo<decltype(32767_i), based::i16>);
STATIC_REQUIRE(CastableTo<decltype(2147483647_i), based::i32>);
STATIC_REQUIRE(CastableTo<decltype(2147483648_i), based::i64>);
STATIC_REQUIRE(CastableTo<decltype(9223372036854775807_i), based::i64>);

STATIC_REQUIRE(CastableTo<decltype(-127_i), based::i8>);
STATIC_REQUIRE(CastableTo<decltype(-128_i), based::i16>);
STATIC_REQUIRE(CastableTo<decltype(-32767_i), based::i16>);
STATIC_REQUIRE(CastableTo<decltype(-2147483647_i), based::i32>);
STATIC_REQUIRE(CastableTo<decltype(-2147483648_i), based::i64>);
STATIC_REQUIRE(CastableTo<decltype(-9223372036854775807_i), based::i64>);
}

diff --git a/ test/source/integral/strong_type_test.cpp b/ test/source/integral/strong_type_test.cpp

@@ -0,0 +1,41 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include "based/integral/strong.hpp"

#include <catch2/catch_test_macros.hpp>

#include "based/integral/literals.hpp"

struct t1 : based::strong_type<based::u8, t1>
{
using strong_type::strong_type;
using strong_type::operator=;
};

struct t2 : based::strong_type<based::u8, t2>
{
using strong_type::strong_type;
using strong_type::operator=;
};

// NOLINTBEGIN(*needed*,*internal-linkage*)
auto compare(t1, t1) -> bool;
auto compare(t2, t2) -> bool;

auto add(t1, t1) -> t1;
auto add(t1, t2) -> t1;
auto add(t2, t1) -> t2;
// NOLINTEND(*needed*,*internal-linkage*)

TEST_CASE("strong_type", "[integral/strong_type]")
{
STATIC_REQUIRE(based::addable<t1, t1>);
STATIC_REQUIRE(!based::addable<t2, t2>);
STATIC_REQUIRE(based::addable<t1, t2>);
STATIC_REQUIRE(based::addable<t2, t1>);

using namespace based::literals; // NOLINT(*namespace*)
REQUIRE(t1 {10_u8} + t1 {20_u8} == t1 {30_u8});
REQUIRE(t1 {10_u8} + t2 {20_u8} == t1 {30_u8});
REQUIRE(t2 {10_u8} + t1 {20_u8} == t2 {30_u8});
}

diff --git a/ test/source/integral/type_test.cpp b/ test/source/integral/type_test.cpp

@@ -0,0 +1,543 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include <catch2/catch_test_macros.hpp>

#include "based/concept/is/same.hpp"
#include "based/integral/types.hpp"

using based::SameAs;
using based::u16;
using based::u32;
using based::u64;
using based::u8;

TEST_CASE("u8", "[integral/types/u8]")
{
// clang-format off
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs + rhs } -> SameAs<u8>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs - rhs } -> SameAs<u8>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs * rhs } -> SameAs<u8>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs / rhs } -> SameAs<u8>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs % rhs } -> SameAs<u8>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs & rhs } -> SameAs<u8>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs | rhs } -> SameAs<u8>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs ^ rhs } -> SameAs<u8>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs << rhs } -> SameAs<u8>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs >> rhs } -> SameAs<u8>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs += rhs } -> SameAs<u8&>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs -= rhs } -> SameAs<u8&>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs *= rhs } -> SameAs<u8&>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs /= rhs } -> SameAs<u8&>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs %= rhs } -> SameAs<u8&>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs &= rhs } -> SameAs<u8&>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs |= rhs } -> SameAs<u8&>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs ^= rhs } -> SameAs<u8&>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs <<= rhs } -> SameAs<u8&>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs >>= rhs } -> SameAs<u8&>; });

STATIC_REQUIRE(requires(u8 lhs, u16 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u8 lhs, u16 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u8 lhs, u16 rhs) { { lhs + rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u8 lhs, u16 rhs) { { lhs - rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u8 lhs, u16 rhs) { { lhs * rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u8 lhs, u16 rhs) { { lhs / rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u8 lhs, u16 rhs) { { lhs << rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u8 lhs, u16 rhs) { { lhs >> rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u8 lhs, u16 rhs) { { lhs % rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u8 lhs, u16 rhs) { { lhs & rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u8 lhs, u16 rhs) { { lhs | rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u8 lhs, u16 rhs) { { lhs ^ rhs } -> SameAs<u16>; });

STATIC_REQUIRE(requires(u8 lhs, u32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u8 lhs, u32 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u8 lhs, u32 rhs) { { lhs + rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u8 lhs, u32 rhs) { { lhs - rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u8 lhs, u32 rhs) { { lhs * rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u8 lhs, u32 rhs) { { lhs / rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u8 lhs, u32 rhs) { { lhs % rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u8 lhs, u32 rhs) { { lhs << rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u8 lhs, u32 rhs) { { lhs >> rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u8 lhs, u32 rhs) { { lhs & rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u8 lhs, u32 rhs) { { lhs | rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u8 lhs, u32 rhs) { { lhs ^ rhs } -> SameAs<u32>; });

STATIC_REQUIRE(requires(u8 lhs, u32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u8 lhs, u64 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u8 lhs, u64 rhs) { { lhs + rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u8 lhs, u64 rhs) { { lhs - rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u8 lhs, u64 rhs) { { lhs * rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u8 lhs, u64 rhs) { { lhs / rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u8 lhs, u64 rhs) { { lhs % rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u8 lhs, u64 rhs) { { lhs << rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u8 lhs, u64 rhs) { { lhs >> rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u8 lhs, u64 rhs) { { lhs & rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u8 lhs, u64 rhs) { { lhs | rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u8 lhs, u64 rhs) { { lhs ^ rhs } -> SameAs<u64>; });
// clang-format on
}

TEST_CASE("u16", "[integral/types/u16]")
{
// clang-format off
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs + rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs - rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs * rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs / rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs % rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs << rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs >> rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs & rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs | rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs ^ rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs += rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs -= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs *= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs /= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs %= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs &= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs |= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs ^= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs <<= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs >>= rhs } -> SameAs<u16&>; });

STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs + rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs - rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs * rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs / rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs % rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs << rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs >> rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs & rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs | rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs ^ rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs += rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs -= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs *= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs /= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs %= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs &= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs |= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs ^= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs <<= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs >>= rhs } -> SameAs<u16&>; });

STATIC_REQUIRE(requires(u16 lhs, u32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u16 lhs, u32 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u16 lhs, u32 rhs) { { lhs + rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u16 lhs, u32 rhs) { { lhs - rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u16 lhs, u32 rhs) { { lhs * rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u16 lhs, u32 rhs) { { lhs / rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u16 lhs, u32 rhs) { { lhs % rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u16 lhs, u32 rhs) { { lhs << rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u16 lhs, u32 rhs) { { lhs >> rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u16 lhs, u32 rhs) { { lhs & rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u16 lhs, u32 rhs) { { lhs | rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u16 lhs, u32 rhs) { { lhs ^ rhs } -> SameAs<u32>; });

STATIC_REQUIRE(requires(u16 lhs, u32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u16 lhs, u64 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u16 lhs, u64 rhs) { { lhs + rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u16 lhs, u64 rhs) { { lhs - rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u16 lhs, u64 rhs) { { lhs * rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u16 lhs, u64 rhs) { { lhs / rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u16 lhs, u64 rhs) { { lhs % rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u16 lhs, u64 rhs) { { lhs << rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u16 lhs, u64 rhs) { { lhs >> rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u16 lhs, u64 rhs) { { lhs & rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u16 lhs, u64 rhs) { { lhs | rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u16 lhs, u64 rhs) { { lhs ^ rhs } -> SameAs<u64>; });
// clang-format on
}

TEST_CASE("u32", "[integral/types/u32]")
{
// clang-format off
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs + rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs - rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs * rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs / rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs % rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs << rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs >> rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs & rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs | rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs ^ rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs += rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs -= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs *= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs /= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs %= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs &= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs |= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs ^= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs <<= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs >>= rhs } -> SameAs<u32&>; });

STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs + rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs - rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs * rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs / rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs % rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs << rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs >> rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs & rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs | rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs ^ rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs += rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs -= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs *= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs /= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs %= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs &= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs |= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs ^= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs <<= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs >>= rhs } -> SameAs<u32&>; });

STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs + rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs - rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs * rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs / rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs % rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs << rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs >> rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs & rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs | rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs ^ rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs += rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs -= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs *= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs /= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs %= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs &= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs |= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs ^= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs <<= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs >>= rhs } -> SameAs<u32&>; });

STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u32 lhs, u64 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u32 lhs, u64 rhs) { { lhs + rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u32 lhs, u64 rhs) { { lhs - rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u32 lhs, u64 rhs) { { lhs * rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u32 lhs, u64 rhs) { { lhs / rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u32 lhs, u64 rhs) { { lhs % rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u32 lhs, u64 rhs) { { lhs << rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u32 lhs, u64 rhs) { { lhs >> rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u32 lhs, u64 rhs) { { lhs & rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u32 lhs, u64 rhs) { { lhs | rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u32 lhs, u64 rhs) { { lhs ^ rhs } -> SameAs<u64>; });
// clang-format on
}

TEST_CASE("u64", "[integral/types/u64]")
{
// clang-format off
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs + rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs - rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs * rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs / rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs % rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs << rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs >> rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs & rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs | rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs ^ rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs += rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs -= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs *= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs /= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs %= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs &= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs |= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs ^= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs <<= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs >>= rhs } -> SameAs<u64&>; });

STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs + rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs - rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs * rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs / rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs % rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs << rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs >> rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs & rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs | rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs ^ rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs += rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs -= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs *= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs /= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs %= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs &= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs |= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs ^= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs <<= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs >>= rhs } -> SameAs<u64&>; });

STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs + rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs - rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs * rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs / rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs % rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs << rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs >> rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs & rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs | rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs ^ rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs += rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs -= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs *= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs /= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs %= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs &= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs |= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs ^= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs <<= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs >>= rhs } -> SameAs<u64&>; });

STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs + rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs - rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs * rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs / rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs % rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs << rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs >> rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs & rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs | rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs ^ rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs += rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs -= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs *= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs /= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs %= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs &= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs |= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs ^= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs <<= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs >>= rhs } -> SameAs<u64&>; });
// clang-format on
}

using based::i16;
using based::i32;
using based::i64;
using based::i8;

TEST_CASE("i8", "[integral/types/i8]")
{
// clang-format off
STATIC_REQUIRE(requires(i8 lhs, i8 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i8 lhs, i8 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i8 lhs, i8 rhs) { { lhs + rhs } -> SameAs<i8>; });
STATIC_REQUIRE(requires(i8 lhs, i8 rhs) { { lhs - rhs } -> SameAs<i8>; });
STATIC_REQUIRE(requires(i8 lhs, i8 rhs) { { lhs * rhs } -> SameAs<i8>; });
STATIC_REQUIRE(requires(i8 lhs, i8 rhs) { { lhs / rhs } -> SameAs<i8>; });
STATIC_REQUIRE(requires(i8 lhs, i8 rhs) { { lhs % rhs } -> SameAs<i8>; });
STATIC_REQUIRE(requires(i8 lhs, i8 rhs) { { lhs += rhs } -> SameAs<i8&>; });
STATIC_REQUIRE(requires(i8 lhs, i8 rhs) { { lhs -= rhs } -> SameAs<i8&>; });
STATIC_REQUIRE(requires(i8 lhs, i8 rhs) { { lhs *= rhs } -> SameAs<i8&>; });
STATIC_REQUIRE(requires(i8 lhs, i8 rhs) { { lhs /= rhs } -> SameAs<i8&>; });
STATIC_REQUIRE(requires(i8 lhs, i8 rhs) { { lhs %= rhs } -> SameAs<i8&>; });

STATIC_REQUIRE(requires(i8 lhs, i16 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i8 lhs, i16 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i8 lhs, i16 rhs) { { lhs + rhs } -> SameAs<i16>; });
STATIC_REQUIRE(requires(i8 lhs, i16 rhs) { { lhs - rhs } -> SameAs<i16>; });
STATIC_REQUIRE(requires(i8 lhs, i16 rhs) { { lhs * rhs } -> SameAs<i16>; });
STATIC_REQUIRE(requires(i8 lhs, i16 rhs) { { lhs / rhs } -> SameAs<i16>; });
STATIC_REQUIRE(requires(i8 lhs, i16 rhs) { { lhs % rhs } -> SameAs<i16>; });

STATIC_REQUIRE(requires(i8 lhs, i32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i8 lhs, i32 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i8 lhs, i32 rhs) { { lhs + rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i8 lhs, i32 rhs) { { lhs - rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i8 lhs, i32 rhs) { { lhs * rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i8 lhs, i32 rhs) { { lhs / rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i8 lhs, i32 rhs) { { lhs % rhs } -> SameAs<i32>; });

STATIC_REQUIRE(requires(i8 lhs, i32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i8 lhs, i64 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i8 lhs, i64 rhs) { { lhs + rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i8 lhs, i64 rhs) { { lhs - rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i8 lhs, i64 rhs) { { lhs * rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i8 lhs, i64 rhs) { { lhs / rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i8 lhs, i64 rhs) { { lhs % rhs } -> SameAs<i64>; });
// clang-format on
}

TEST_CASE("i16", "[integral/types/i16]")
{
// clang-format off
STATIC_REQUIRE(requires(i16 lhs, i8 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i16 lhs, i8 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i16 lhs, i8 rhs) { { lhs + rhs } -> SameAs<i16>; });
STATIC_REQUIRE(requires(i16 lhs, i8 rhs) { { lhs - rhs } -> SameAs<i16>; });
STATIC_REQUIRE(requires(i16 lhs, i8 rhs) { { lhs * rhs } -> SameAs<i16>; });
STATIC_REQUIRE(requires(i16 lhs, i8 rhs) { { lhs / rhs } -> SameAs<i16>; });
STATIC_REQUIRE(requires(i16 lhs, i8 rhs) { { lhs % rhs } -> SameAs<i16>; });
STATIC_REQUIRE(requires(i16 lhs, i8 rhs) { { lhs += rhs } -> SameAs<i16&>; });
STATIC_REQUIRE(requires(i16 lhs, i8 rhs) { { lhs -= rhs } -> SameAs<i16&>; });
STATIC_REQUIRE(requires(i16 lhs, i8 rhs) { { lhs *= rhs } -> SameAs<i16&>; });
STATIC_REQUIRE(requires(i16 lhs, i8 rhs) { { lhs /= rhs } -> SameAs<i16&>; });
STATIC_REQUIRE(requires(i16 lhs, i8 rhs) { { lhs %= rhs } -> SameAs<i16&>; });

STATIC_REQUIRE(requires(i16 lhs, i16 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i16 lhs, i16 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i16 lhs, i16 rhs) { { lhs + rhs } -> SameAs<i16>; });
STATIC_REQUIRE(requires(i16 lhs, i16 rhs) { { lhs - rhs } -> SameAs<i16>; });
STATIC_REQUIRE(requires(i16 lhs, i16 rhs) { { lhs * rhs } -> SameAs<i16>; });
STATIC_REQUIRE(requires(i16 lhs, i16 rhs) { { lhs / rhs } -> SameAs<i16>; });
STATIC_REQUIRE(requires(i16 lhs, i16 rhs) { { lhs % rhs } -> SameAs<i16>; });
STATIC_REQUIRE(requires(i16 lhs, i16 rhs) { { lhs += rhs } -> SameAs<i16&>; });
STATIC_REQUIRE(requires(i16 lhs, i16 rhs) { { lhs -= rhs } -> SameAs<i16&>; });
STATIC_REQUIRE(requires(i16 lhs, i16 rhs) { { lhs *= rhs } -> SameAs<i16&>; });
STATIC_REQUIRE(requires(i16 lhs, i16 rhs) { { lhs /= rhs } -> SameAs<i16&>; });
STATIC_REQUIRE(requires(i16 lhs, i16 rhs) { { lhs %= rhs } -> SameAs<i16&>; });

STATIC_REQUIRE(requires(i16 lhs, i32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i16 lhs, i32 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i16 lhs, i32 rhs) { { lhs + rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i16 lhs, i32 rhs) { { lhs - rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i16 lhs, i32 rhs) { { lhs * rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i16 lhs, i32 rhs) { { lhs / rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i16 lhs, i32 rhs) { { lhs % rhs } -> SameAs<i32>; });

STATIC_REQUIRE(requires(i16 lhs, i32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i16 lhs, i64 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i16 lhs, i64 rhs) { { lhs + rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i16 lhs, i64 rhs) { { lhs - rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i16 lhs, i64 rhs) { { lhs * rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i16 lhs, i64 rhs) { { lhs / rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i16 lhs, i64 rhs) { { lhs % rhs } -> SameAs<i64>; });
// clang-format on
}

TEST_CASE("i32", "[integral/types/i32]")
{
// clang-format off
STATIC_REQUIRE(requires(i32 lhs, i8 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i32 lhs, i8 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i32 lhs, i8 rhs) { { lhs + rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i8 rhs) { { lhs - rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i8 rhs) { { lhs * rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i8 rhs) { { lhs / rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i8 rhs) { { lhs % rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i8 rhs) { { lhs += rhs } -> SameAs<i32&>; });
STATIC_REQUIRE(requires(i32 lhs, i8 rhs) { { lhs -= rhs } -> SameAs<i32&>; });
STATIC_REQUIRE(requires(i32 lhs, i8 rhs) { { lhs *= rhs } -> SameAs<i32&>; });
STATIC_REQUIRE(requires(i32 lhs, i8 rhs) { { lhs /= rhs } -> SameAs<i32&>; });
STATIC_REQUIRE(requires(i32 lhs, i8 rhs) { { lhs %= rhs } -> SameAs<i32&>; });

STATIC_REQUIRE(requires(i32 lhs, i16 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i32 lhs, i16 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i32 lhs, i16 rhs) { { lhs + rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i16 rhs) { { lhs - rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i16 rhs) { { lhs * rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i16 rhs) { { lhs / rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i16 rhs) { { lhs % rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i16 rhs) { { lhs += rhs } -> SameAs<i32&>; });
STATIC_REQUIRE(requires(i32 lhs, i16 rhs) { { lhs -= rhs } -> SameAs<i32&>; });
STATIC_REQUIRE(requires(i32 lhs, i16 rhs) { { lhs *= rhs } -> SameAs<i32&>; });
STATIC_REQUIRE(requires(i32 lhs, i16 rhs) { { lhs /= rhs } -> SameAs<i32&>; });
STATIC_REQUIRE(requires(i32 lhs, i16 rhs) { { lhs %= rhs } -> SameAs<i32&>; });

STATIC_REQUIRE(requires(i32 lhs, i32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i32 lhs, i32 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i32 lhs, i32 rhs) { { lhs + rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i32 rhs) { { lhs - rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i32 rhs) { { lhs * rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i32 rhs) { { lhs / rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i32 rhs) { { lhs % rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i32 rhs) { { lhs += rhs } -> SameAs<i32&>; });
STATIC_REQUIRE(requires(i32 lhs, i32 rhs) { { lhs -= rhs } -> SameAs<i32&>; });
STATIC_REQUIRE(requires(i32 lhs, i32 rhs) { { lhs *= rhs } -> SameAs<i32&>; });
STATIC_REQUIRE(requires(i32 lhs, i32 rhs) { { lhs /= rhs } -> SameAs<i32&>; });
STATIC_REQUIRE(requires(i32 lhs, i32 rhs) { { lhs %= rhs } -> SameAs<i32&>; });

STATIC_REQUIRE(requires(i32 lhs, i32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i32 lhs, i64 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i32 lhs, i64 rhs) { { lhs + rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i32 lhs, i64 rhs) { { lhs - rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i32 lhs, i64 rhs) { { lhs * rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i32 lhs, i64 rhs) { { lhs / rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i32 lhs, i64 rhs) { { lhs % rhs } -> SameAs<i64>; });
// clang-format on
}

TEST_CASE("i64", "[integral/types/i64]")
{
// clang-format off
STATIC_REQUIRE(requires(i64 lhs, i8 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i64 lhs, i8 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i64 lhs, i8 rhs) { { lhs + rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i8 rhs) { { lhs - rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i8 rhs) { { lhs * rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i8 rhs) { { lhs / rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i8 rhs) { { lhs % rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i8 rhs) { { lhs += rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i8 rhs) { { lhs -= rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i8 rhs) { { lhs *= rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i8 rhs) { { lhs /= rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i8 rhs) { { lhs %= rhs } -> SameAs<i64&>; });

STATIC_REQUIRE(requires(i64 lhs, i16 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i64 lhs, i16 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i64 lhs, i16 rhs) { { lhs + rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i16 rhs) { { lhs - rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i16 rhs) { { lhs * rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i16 rhs) { { lhs / rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i16 rhs) { { lhs % rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i16 rhs) { { lhs += rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i16 rhs) { { lhs -= rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i16 rhs) { { lhs *= rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i16 rhs) { { lhs /= rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i16 rhs) { { lhs %= rhs } -> SameAs<i64&>; });

STATIC_REQUIRE(requires(i64 lhs, i32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i64 lhs, i32 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i64 lhs, i32 rhs) { { lhs + rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i32 rhs) { { lhs - rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i32 rhs) { { lhs * rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i32 rhs) { { lhs / rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i32 rhs) { { lhs % rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i32 rhs) { { lhs += rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i32 rhs) { { lhs -= rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i32 rhs) { { lhs *= rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i32 rhs) { { lhs /= rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i32 rhs) { { lhs %= rhs } -> SameAs<i64&>; });

STATIC_REQUIRE(requires(i64 lhs, i32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i64 lhs, i64 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i64 lhs, i64 rhs) { { lhs + rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i64 rhs) { { lhs - rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i64 rhs) { { lhs * rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i64 rhs) { { lhs / rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i64 rhs) { { lhs % rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i64 rhs) { { lhs += rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i64 rhs) { { lhs -= rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i64 rhs) { { lhs *= rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i64 rhs) { { lhs /= rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i64 rhs) { { lhs %= rhs } -> SameAs<i64&>; });
// clang-format on
}

diff --git a/ test/source/list_test.cpp b/ test/source/list_test.cpp

@@ -1,209 +0,0 @@

#include <numeric>

#include "based/list.hpp"

#include <catch2/catch_test_macros.hpp>

#include "based/types/literals.hpp"

template class based::list_pool<based::u8, based::u8>;

// NOLINTBEGIN(*complexity*)

TEST_CASE("list_pool", "[list/list_pool]")
{
using namespace based::literals; // NOLINT(*namespace*)
using list_pool = based::list_pool<based::u8, based::u8>;

auto pool = list_pool();
auto head = pool.node_empty();

SECTION("node_empty is empty")
{
REQUIRE(pool.is_empty(head) == true);
REQUIRE(pool.node_empty() == head);
}

SECTION("add one node")
{
head = pool.allocate(1_u8, head);

REQUIRE(pool.is_empty(head) == false);
REQUIRE(pool.value(head) == 1_u8);

REQUIRE(pool.next(head) == pool.node_empty());

SECTION("add two nodes")
{
head = pool.allocate(2_u8, head);

REQUIRE(pool.is_empty(head) == false);
REQUIRE(pool.value(head) == 2_u8);

REQUIRE(pool.value(pool.next(head)) == 1_u8);
REQUIRE(pool.next(pool.next(head)) == pool.node_empty());

head = pool.free(head);
}

SECTION("alloc after free")
{
head = pool.allocate(2_u8, head);
head = pool.free(head);
head = pool.allocate(3_u8, head);

REQUIRE(pool.is_empty(head) == false);
REQUIRE(pool.value(head) == 3_u8);

head = pool.free(head);
}

head = pool.free(head);
}

REQUIRE(pool.is_empty(head) == true);
REQUIRE(pool.node_empty() == head);
}

TEST_CASE("list_pool iterator", "[list/list_pool]")
{
using namespace based::literals; // NOLINT(*namespace*)
using list_pool = based::list_pool<based::u8, based::u8>;

auto pool = list_pool();
auto head = pool.node_empty();

static constexpr auto iter_count = 255_u8;
for (auto i = 0_u8; i < iter_count; i++) {
head = pool.allocate(i, head);
}

SECTION("for-loop")
{
using iter = list_pool::iterator;

auto sum = 0_u32;
for (auto it = iter(pool, head); it != iter(pool); it++) {
sum += *it.operator->();
sum += *it;
}

REQUIRE(sum == 255_u32 * 254_u32);
}

SECTION("accumulate")
{
using iter = list_pool::iterator;

const auto sum = std::accumulate(
iter(pool, head),
iter(pool),
based::u32 {0},
[](auto a, auto b)
{
return a + b;
}
);

REQUIRE(sum == 255_u32 * 254_u32 / 2_u32);
}

based::free_list(pool, head);
}

TEST_CASE("list_pool const iterator", "[list/list_pool]")
{
using namespace based::literals; // NOLINT(*namespace*)
using list_pool = based::list_pool<based::u8, based::u8>;

auto pool = list_pool();
auto head = pool.node_empty();

static constexpr auto iter_count = 255_u8;
for (auto i = 0_u8; i < iter_count; i++) {
head = pool.allocate(i, head);
}

SECTION("const for-loop")
{
using iter = list_pool::const_iterator;

auto sum = 0_u32;
for (auto it = iter(pool, head); it != iter(pool); it++) {
sum += *it.operator->();
sum += *it;
}

REQUIRE(sum == 255_u32 * 254_u32);
}

SECTION("const accumulate")
{
using iter = list_pool::const_iterator;

static const auto sum =
[](const list_pool& lpool, const list_pool::list_type& lhead)
{
return std::accumulate(
iter(lpool, lhead),
iter(lpool),
based::u32 {0},
[](auto a, auto b)
{
return a + b;
}
);
};

REQUIRE(sum(pool, head) == 255_u32 * 254_u32 / 2_u32);
}

based::free_list(pool, head);
}

TEST_CASE("list_pool queue", "[list/list_pool/queue]")
{
using list_pool = based::list_pool<based::u8, based::u8>;
using iter = list_pool::iterator;

auto pool = list_pool();
auto queue = pool.queue_empty();

SECTION("free(empty, empty)")
{
REQUIRE(pool.free(queue.first, queue.second) == pool.node_empty());
}

SECTION("pop_front(empty)")
{
REQUIRE(pool.pop_front(queue) == queue);
}

SECTION("operation")
{
using namespace based::literals; // NOLINT(*namespace*)
static constexpr auto iter_count = 255_u8;
for (auto i = 0_u8; i < iter_count; i++) {
if (i % 2_u8 == 0_u8) {
queue = pool.push_front(queue, i);
} else {
queue = pool.push_back(queue, i);
}

if (i % 3_u8 == 0_u8) {
queue = pool.pop_front(queue);
}
}

auto sum = 0_u64;
for (auto it = iter(pool, queue.first); it != iter(pool); ++it) {
sum += *it;
}

pool.free(queue);

REQUIRE(sum == 21717_u64);
}
}

// NOLINTEND(*complexity*)

diff --git a/ test/source/string/literal_test.cpp b/ test/source/string/literal_test.cpp

@@ -1,12 +1,12 @@

#include <catch2/catch_test_macros.hpp>

#include "based/string/literal.hpp"

#include <catch2/catch_test_macros.hpp>

TEST_CASE("empty", "[string/literal]")
{
const based::string_literal sltr = "";

REQUIRE(sltr.size() == 1);
REQUIRE(sltr.size() == 0);
REQUIRE(std::memcmp(sltr.data(), "", sltr.size()) == 0);
}

@@ -14,7 +14,7 @@ TEST_CASE("nonempty", "[string/literal]")

{
const based::string_literal sltr = "nonempty";

REQUIRE(sltr.size() == 9);
REQUIRE(sltr.size() == 8);
REQUIRE(std::memcmp(sltr.data(), "nonempty", sltr.size()) == 0);
}

@@ -30,9 +30,9 @@ TEST_CASE("template", "[string/literal]")

return l.size();
};

REQUIRE(size.operator()<"">() == 1);
REQUIRE(size.operator()<"nonempty">() == 9);
REQUIRE(size.operator()<"">() == 0);
REQUIRE(size.operator()<"nonempty">() == 8);

REQUIRE(std::memcmp(data.operator()<"">(), "", 1) == 0);
REQUIRE(std::memcmp(data.operator()<"nonempty">(), "nonempty", 9) == 0);
REQUIRE(std::memcmp(data.operator()<"">(), "", 0) == 0);
REQUIRE(std::memcmp(data.operator()<"nonempty">(), "nonempty", 8) == 0);
}

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

@@ -4,7 +4,7 @@


#include <catch2/catch_test_macros.hpp>

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

namespace
{

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

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


#include <catch2/catch_test_macros.hpp>

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

using based::SameAs;

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

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


#include <catch2/catch_test_macros.hpp>

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

using based::SameAs;

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

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


#include <catch2/catch_test_macros.hpp>

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

using based::SameAs;

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

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


#include <catch2/catch_test_macros.hpp>

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

using based::SameAs;

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

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


#include <catch2/catch_test_macros.hpp>

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

using based::SameAs;

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

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


#include <catch2/catch_test_macros.hpp>

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

using based::SameAs;

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

@@ -4,7 +4,7 @@


#include <catch2/catch_test_macros.hpp>

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

// NOLINTBEGIN(*cognitive-complexity*)

diff --git a/ test/source/types/limits.cpp b/ test/source/types/limits.cpp

@@ -1,33 +0,0 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include <catch2/catch_test_macros.hpp>

#include "based/types/types.hpp"

using based::limits;

TEST_CASE("unsigned", "[types/literals]")
{
STATIC_REQUIRE(limits<based::u8>::min.value == 0ULL);
STATIC_REQUIRE(limits<based::u16>::min.value == 0ULL);
STATIC_REQUIRE(limits<based::u32>::min.value == 0ULL);
STATIC_REQUIRE(limits<based::u64>::min.value == 0ULL);

STATIC_REQUIRE(limits<based::u8>::max.value == 255ULL);
STATIC_REQUIRE(limits<based::u16>::max.value == 65535ULL);
STATIC_REQUIRE(limits<based::u32>::max.value == 4294967295ULL);
STATIC_REQUIRE(limits<based::u64>::max.value == 18446744073709551615ULL);
}

TEST_CASE("signed", "[types/literals]")
{
STATIC_REQUIRE(limits<based::i8>::min.value == -128LL);
STATIC_REQUIRE(limits<based::i16>::min.value == -32768LL);
STATIC_REQUIRE(limits<based::i32>::min.value == -2147483648LL);
STATIC_REQUIRE(limits<based::i64>::min.value == -9223372036854775807LL - 1);

STATIC_REQUIRE(limits<based::i8>::max.value == 127LL);
STATIC_REQUIRE(limits<based::i16>::max.value == 32767LL);
STATIC_REQUIRE(limits<based::i32>::max.value == 2147483647LL);
STATIC_REQUIRE(limits<based::i64>::max.value == 9223372036854775807LL);
}

diff --git a/ test/source/types/literals.cpp b/ test/source/types/literals.cpp

@@ -1,41 +0,0 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include "based/types/literals.hpp"

#include <catch2/catch_test_macros.hpp>

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

using namespace based::literals; // NOLINT(*namespace*)

using based::CastableTo;

TEST_CASE("unsigned", "[types/literals]")
{
STATIC_REQUIRE(CastableTo<decltype(0_u), based::u8>);
STATIC_REQUIRE(CastableTo<decltype(255_u), based::u8>);
STATIC_REQUIRE(CastableTo<decltype(256_u), based::u16>);
STATIC_REQUIRE(CastableTo<decltype(65535_u), based::u16>);
STATIC_REQUIRE(CastableTo<decltype(65536_u), based::u32>);
STATIC_REQUIRE(CastableTo<decltype(4294967295_u), based::u32>);
STATIC_REQUIRE(CastableTo<decltype(4294967296_u), based::u64>);
STATIC_REQUIRE(CastableTo<decltype(18446744073709551615_u), based::u64>);
}

TEST_CASE("signed", "[types/literals]")
{
STATIC_REQUIRE(CastableTo<decltype(0_i), based::i8>);
STATIC_REQUIRE(CastableTo<decltype(127_i), based::i8>);
STATIC_REQUIRE(CastableTo<decltype(128_i), based::i16>);
STATIC_REQUIRE(CastableTo<decltype(32767_i), based::i16>);
STATIC_REQUIRE(CastableTo<decltype(2147483647_i), based::i32>);
STATIC_REQUIRE(CastableTo<decltype(2147483648_i), based::i64>);
STATIC_REQUIRE(CastableTo<decltype(9223372036854775807_i), based::i64>);

STATIC_REQUIRE(CastableTo<decltype(-127_i), based::i8>);
STATIC_REQUIRE(CastableTo<decltype(-128_i), based::i16>);
STATIC_REQUIRE(CastableTo<decltype(-32767_i), based::i16>);
STATIC_REQUIRE(CastableTo<decltype(-2147483647_i), based::i32>);
STATIC_REQUIRE(CastableTo<decltype(-2147483648_i), based::i64>);
STATIC_REQUIRE(CastableTo<decltype(-9223372036854775807_i), based::i64>);
}

diff --git a/ test/source/types/strong_type_test.cpp b/ test/source/types/strong_type_test.cpp

@@ -1,41 +0,0 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include "based/types/strong.hpp"

#include <catch2/catch_test_macros.hpp>

#include "based/types/literals.hpp"

struct t1 : based::strong_type<based::u8, t1>
{
using strong_type::strong_type;
using strong_type::operator=;
};

struct t2 : based::strong_type<based::u8, t2>
{
using strong_type::strong_type;
using strong_type::operator=;
};

// NOLINTBEGIN(*needed*,*internal-linkage*)
auto compare(t1, t1) -> bool;
auto compare(t2, t2) -> bool;

auto add(t1, t1) -> t1;
auto add(t1, t2) -> t1;
auto add(t2, t1) -> t2;
// NOLINTEND(*needed*,*internal-linkage*)

TEST_CASE("strong_type", "[types/strong_type]")
{
STATIC_REQUIRE(based::addable<t1, t1>);
STATIC_REQUIRE(!based::addable<t2, t2>);
STATIC_REQUIRE(based::addable<t1, t2>);
STATIC_REQUIRE(based::addable<t2, t1>);

using namespace based::literals; // NOLINT(*namespace*)
REQUIRE(t1 {10_u8} + t1 {20_u8} == t1 {30_u8});
REQUIRE(t1 {10_u8} + t2 {20_u8} == t1 {30_u8});
REQUIRE(t2 {10_u8} + t1 {20_u8} == t2 {30_u8});
}

diff --git a/ test/source/types/type_test.cpp b/ test/source/types/type_test.cpp

@@ -1,543 +0,0 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include <catch2/catch_test_macros.hpp>

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

using based::SameAs;
using based::u16;
using based::u32;
using based::u64;
using based::u8;

TEST_CASE("u8", "[types/u8]")
{
// clang-format off
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs + rhs } -> SameAs<u8>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs - rhs } -> SameAs<u8>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs * rhs } -> SameAs<u8>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs / rhs } -> SameAs<u8>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs % rhs } -> SameAs<u8>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs & rhs } -> SameAs<u8>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs | rhs } -> SameAs<u8>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs ^ rhs } -> SameAs<u8>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs << rhs } -> SameAs<u8>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs >> rhs } -> SameAs<u8>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs += rhs } -> SameAs<u8&>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs -= rhs } -> SameAs<u8&>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs *= rhs } -> SameAs<u8&>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs /= rhs } -> SameAs<u8&>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs %= rhs } -> SameAs<u8&>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs &= rhs } -> SameAs<u8&>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs |= rhs } -> SameAs<u8&>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs ^= rhs } -> SameAs<u8&>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs <<= rhs } -> SameAs<u8&>; });
STATIC_REQUIRE(requires(u8 lhs, u8 rhs) { { lhs >>= rhs } -> SameAs<u8&>; });

STATIC_REQUIRE(requires(u8 lhs, u16 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u8 lhs, u16 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u8 lhs, u16 rhs) { { lhs + rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u8 lhs, u16 rhs) { { lhs - rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u8 lhs, u16 rhs) { { lhs * rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u8 lhs, u16 rhs) { { lhs / rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u8 lhs, u16 rhs) { { lhs << rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u8 lhs, u16 rhs) { { lhs >> rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u8 lhs, u16 rhs) { { lhs % rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u8 lhs, u16 rhs) { { lhs & rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u8 lhs, u16 rhs) { { lhs | rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u8 lhs, u16 rhs) { { lhs ^ rhs } -> SameAs<u16>; });

STATIC_REQUIRE(requires(u8 lhs, u32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u8 lhs, u32 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u8 lhs, u32 rhs) { { lhs + rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u8 lhs, u32 rhs) { { lhs - rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u8 lhs, u32 rhs) { { lhs * rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u8 lhs, u32 rhs) { { lhs / rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u8 lhs, u32 rhs) { { lhs % rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u8 lhs, u32 rhs) { { lhs << rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u8 lhs, u32 rhs) { { lhs >> rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u8 lhs, u32 rhs) { { lhs & rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u8 lhs, u32 rhs) { { lhs | rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u8 lhs, u32 rhs) { { lhs ^ rhs } -> SameAs<u32>; });

STATIC_REQUIRE(requires(u8 lhs, u32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u8 lhs, u64 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u8 lhs, u64 rhs) { { lhs + rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u8 lhs, u64 rhs) { { lhs - rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u8 lhs, u64 rhs) { { lhs * rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u8 lhs, u64 rhs) { { lhs / rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u8 lhs, u64 rhs) { { lhs % rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u8 lhs, u64 rhs) { { lhs << rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u8 lhs, u64 rhs) { { lhs >> rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u8 lhs, u64 rhs) { { lhs & rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u8 lhs, u64 rhs) { { lhs | rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u8 lhs, u64 rhs) { { lhs ^ rhs } -> SameAs<u64>; });
// clang-format on
}

TEST_CASE("u16", "[types/u16]")
{
// clang-format off
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs + rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs - rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs * rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs / rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs % rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs << rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs >> rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs & rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs | rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs ^ rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs += rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs -= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs *= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs /= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs %= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs &= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs |= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs ^= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs <<= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u8 rhs) { { lhs >>= rhs } -> SameAs<u16&>; });

STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs + rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs - rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs * rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs / rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs % rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs << rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs >> rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs & rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs | rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs ^ rhs } -> SameAs<u16>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs += rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs -= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs *= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs /= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs %= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs &= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs |= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs ^= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs <<= rhs } -> SameAs<u16&>; });
STATIC_REQUIRE(requires(u16 lhs, u16 rhs) { { lhs >>= rhs } -> SameAs<u16&>; });

STATIC_REQUIRE(requires(u16 lhs, u32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u16 lhs, u32 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u16 lhs, u32 rhs) { { lhs + rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u16 lhs, u32 rhs) { { lhs - rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u16 lhs, u32 rhs) { { lhs * rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u16 lhs, u32 rhs) { { lhs / rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u16 lhs, u32 rhs) { { lhs % rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u16 lhs, u32 rhs) { { lhs << rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u16 lhs, u32 rhs) { { lhs >> rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u16 lhs, u32 rhs) { { lhs & rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u16 lhs, u32 rhs) { { lhs | rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u16 lhs, u32 rhs) { { lhs ^ rhs } -> SameAs<u32>; });

STATIC_REQUIRE(requires(u16 lhs, u32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u16 lhs, u64 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u16 lhs, u64 rhs) { { lhs + rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u16 lhs, u64 rhs) { { lhs - rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u16 lhs, u64 rhs) { { lhs * rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u16 lhs, u64 rhs) { { lhs / rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u16 lhs, u64 rhs) { { lhs % rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u16 lhs, u64 rhs) { { lhs << rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u16 lhs, u64 rhs) { { lhs >> rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u16 lhs, u64 rhs) { { lhs & rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u16 lhs, u64 rhs) { { lhs | rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u16 lhs, u64 rhs) { { lhs ^ rhs } -> SameAs<u64>; });
// clang-format on
}

TEST_CASE("u32", "[types/u32]")
{
// clang-format off
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs + rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs - rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs * rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs / rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs % rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs << rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs >> rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs & rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs | rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs ^ rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs += rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs -= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs *= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs /= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs %= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs &= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs |= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs ^= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs <<= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u8 rhs) { { lhs >>= rhs } -> SameAs<u32&>; });

STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs + rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs - rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs * rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs / rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs % rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs << rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs >> rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs & rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs | rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs ^ rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs += rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs -= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs *= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs /= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs %= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs &= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs |= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs ^= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs <<= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u16 rhs) { { lhs >>= rhs } -> SameAs<u32&>; });

STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs + rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs - rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs * rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs / rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs % rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs << rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs >> rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs & rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs | rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs ^ rhs } -> SameAs<u32>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs += rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs -= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs *= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs /= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs %= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs &= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs |= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs ^= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs <<= rhs } -> SameAs<u32&>; });
STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs >>= rhs } -> SameAs<u32&>; });

STATIC_REQUIRE(requires(u32 lhs, u32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u32 lhs, u64 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u32 lhs, u64 rhs) { { lhs + rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u32 lhs, u64 rhs) { { lhs - rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u32 lhs, u64 rhs) { { lhs * rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u32 lhs, u64 rhs) { { lhs / rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u32 lhs, u64 rhs) { { lhs % rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u32 lhs, u64 rhs) { { lhs << rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u32 lhs, u64 rhs) { { lhs >> rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u32 lhs, u64 rhs) { { lhs & rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u32 lhs, u64 rhs) { { lhs | rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u32 lhs, u64 rhs) { { lhs ^ rhs } -> SameAs<u64>; });
// clang-format on
}

TEST_CASE("u64", "[types/u64]")
{
// clang-format off
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs + rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs - rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs * rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs / rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs % rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs << rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs >> rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs & rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs | rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs ^ rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs += rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs -= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs *= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs /= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs %= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs &= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs |= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs ^= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs <<= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u8 rhs) { { lhs >>= rhs } -> SameAs<u64&>; });

STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs + rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs - rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs * rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs / rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs % rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs << rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs >> rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs & rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs | rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs ^ rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs += rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs -= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs *= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs /= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs %= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs &= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs |= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs ^= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs <<= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u16 rhs) { { lhs >>= rhs } -> SameAs<u64&>; });

STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs + rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs - rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs * rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs / rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs % rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs << rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs >> rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs & rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs | rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs ^ rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs += rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs -= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs *= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs /= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs %= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs &= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs |= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs ^= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs <<= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs >>= rhs } -> SameAs<u64&>; });

STATIC_REQUIRE(requires(u64 lhs, u32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs + rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs - rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs * rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs / rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs % rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs << rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs >> rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs & rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs | rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs ^ rhs } -> SameAs<u64>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs += rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs -= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs *= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs /= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs %= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs &= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs |= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs ^= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs <<= rhs } -> SameAs<u64&>; });
STATIC_REQUIRE(requires(u64 lhs, u64 rhs) { { lhs >>= rhs } -> SameAs<u64&>; });
// clang-format on
}

using based::i16;
using based::i32;
using based::i64;
using based::i8;

TEST_CASE("i8", "[types/i8]")
{
// clang-format off
STATIC_REQUIRE(requires(i8 lhs, i8 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i8 lhs, i8 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i8 lhs, i8 rhs) { { lhs + rhs } -> SameAs<i8>; });
STATIC_REQUIRE(requires(i8 lhs, i8 rhs) { { lhs - rhs } -> SameAs<i8>; });
STATIC_REQUIRE(requires(i8 lhs, i8 rhs) { { lhs * rhs } -> SameAs<i8>; });
STATIC_REQUIRE(requires(i8 lhs, i8 rhs) { { lhs / rhs } -> SameAs<i8>; });
STATIC_REQUIRE(requires(i8 lhs, i8 rhs) { { lhs % rhs } -> SameAs<i8>; });
STATIC_REQUIRE(requires(i8 lhs, i8 rhs) { { lhs += rhs } -> SameAs<i8&>; });
STATIC_REQUIRE(requires(i8 lhs, i8 rhs) { { lhs -= rhs } -> SameAs<i8&>; });
STATIC_REQUIRE(requires(i8 lhs, i8 rhs) { { lhs *= rhs } -> SameAs<i8&>; });
STATIC_REQUIRE(requires(i8 lhs, i8 rhs) { { lhs /= rhs } -> SameAs<i8&>; });
STATIC_REQUIRE(requires(i8 lhs, i8 rhs) { { lhs %= rhs } -> SameAs<i8&>; });

STATIC_REQUIRE(requires(i8 lhs, i16 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i8 lhs, i16 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i8 lhs, i16 rhs) { { lhs + rhs } -> SameAs<i16>; });
STATIC_REQUIRE(requires(i8 lhs, i16 rhs) { { lhs - rhs } -> SameAs<i16>; });
STATIC_REQUIRE(requires(i8 lhs, i16 rhs) { { lhs * rhs } -> SameAs<i16>; });
STATIC_REQUIRE(requires(i8 lhs, i16 rhs) { { lhs / rhs } -> SameAs<i16>; });
STATIC_REQUIRE(requires(i8 lhs, i16 rhs) { { lhs % rhs } -> SameAs<i16>; });

STATIC_REQUIRE(requires(i8 lhs, i32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i8 lhs, i32 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i8 lhs, i32 rhs) { { lhs + rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i8 lhs, i32 rhs) { { lhs - rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i8 lhs, i32 rhs) { { lhs * rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i8 lhs, i32 rhs) { { lhs / rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i8 lhs, i32 rhs) { { lhs % rhs } -> SameAs<i32>; });

STATIC_REQUIRE(requires(i8 lhs, i32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i8 lhs, i64 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i8 lhs, i64 rhs) { { lhs + rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i8 lhs, i64 rhs) { { lhs - rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i8 lhs, i64 rhs) { { lhs * rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i8 lhs, i64 rhs) { { lhs / rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i8 lhs, i64 rhs) { { lhs % rhs } -> SameAs<i64>; });
// clang-format on
}

TEST_CASE("i16", "[types/i16]")
{
// clang-format off
STATIC_REQUIRE(requires(i16 lhs, i8 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i16 lhs, i8 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i16 lhs, i8 rhs) { { lhs + rhs } -> SameAs<i16>; });
STATIC_REQUIRE(requires(i16 lhs, i8 rhs) { { lhs - rhs } -> SameAs<i16>; });
STATIC_REQUIRE(requires(i16 lhs, i8 rhs) { { lhs * rhs } -> SameAs<i16>; });
STATIC_REQUIRE(requires(i16 lhs, i8 rhs) { { lhs / rhs } -> SameAs<i16>; });
STATIC_REQUIRE(requires(i16 lhs, i8 rhs) { { lhs % rhs } -> SameAs<i16>; });
STATIC_REQUIRE(requires(i16 lhs, i8 rhs) { { lhs += rhs } -> SameAs<i16&>; });
STATIC_REQUIRE(requires(i16 lhs, i8 rhs) { { lhs -= rhs } -> SameAs<i16&>; });
STATIC_REQUIRE(requires(i16 lhs, i8 rhs) { { lhs *= rhs } -> SameAs<i16&>; });
STATIC_REQUIRE(requires(i16 lhs, i8 rhs) { { lhs /= rhs } -> SameAs<i16&>; });
STATIC_REQUIRE(requires(i16 lhs, i8 rhs) { { lhs %= rhs } -> SameAs<i16&>; });

STATIC_REQUIRE(requires(i16 lhs, i16 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i16 lhs, i16 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i16 lhs, i16 rhs) { { lhs + rhs } -> SameAs<i16>; });
STATIC_REQUIRE(requires(i16 lhs, i16 rhs) { { lhs - rhs } -> SameAs<i16>; });
STATIC_REQUIRE(requires(i16 lhs, i16 rhs) { { lhs * rhs } -> SameAs<i16>; });
STATIC_REQUIRE(requires(i16 lhs, i16 rhs) { { lhs / rhs } -> SameAs<i16>; });
STATIC_REQUIRE(requires(i16 lhs, i16 rhs) { { lhs % rhs } -> SameAs<i16>; });
STATIC_REQUIRE(requires(i16 lhs, i16 rhs) { { lhs += rhs } -> SameAs<i16&>; });
STATIC_REQUIRE(requires(i16 lhs, i16 rhs) { { lhs -= rhs } -> SameAs<i16&>; });
STATIC_REQUIRE(requires(i16 lhs, i16 rhs) { { lhs *= rhs } -> SameAs<i16&>; });
STATIC_REQUIRE(requires(i16 lhs, i16 rhs) { { lhs /= rhs } -> SameAs<i16&>; });
STATIC_REQUIRE(requires(i16 lhs, i16 rhs) { { lhs %= rhs } -> SameAs<i16&>; });

STATIC_REQUIRE(requires(i16 lhs, i32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i16 lhs, i32 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i16 lhs, i32 rhs) { { lhs + rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i16 lhs, i32 rhs) { { lhs - rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i16 lhs, i32 rhs) { { lhs * rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i16 lhs, i32 rhs) { { lhs / rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i16 lhs, i32 rhs) { { lhs % rhs } -> SameAs<i32>; });

STATIC_REQUIRE(requires(i16 lhs, i32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i16 lhs, i64 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i16 lhs, i64 rhs) { { lhs + rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i16 lhs, i64 rhs) { { lhs - rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i16 lhs, i64 rhs) { { lhs * rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i16 lhs, i64 rhs) { { lhs / rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i16 lhs, i64 rhs) { { lhs % rhs } -> SameAs<i64>; });
// clang-format on
}

TEST_CASE("i32", "[types/i32]")
{
// clang-format off
STATIC_REQUIRE(requires(i32 lhs, i8 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i32 lhs, i8 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i32 lhs, i8 rhs) { { lhs + rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i8 rhs) { { lhs - rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i8 rhs) { { lhs * rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i8 rhs) { { lhs / rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i8 rhs) { { lhs % rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i8 rhs) { { lhs += rhs } -> SameAs<i32&>; });
STATIC_REQUIRE(requires(i32 lhs, i8 rhs) { { lhs -= rhs } -> SameAs<i32&>; });
STATIC_REQUIRE(requires(i32 lhs, i8 rhs) { { lhs *= rhs } -> SameAs<i32&>; });
STATIC_REQUIRE(requires(i32 lhs, i8 rhs) { { lhs /= rhs } -> SameAs<i32&>; });
STATIC_REQUIRE(requires(i32 lhs, i8 rhs) { { lhs %= rhs } -> SameAs<i32&>; });

STATIC_REQUIRE(requires(i32 lhs, i16 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i32 lhs, i16 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i32 lhs, i16 rhs) { { lhs + rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i16 rhs) { { lhs - rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i16 rhs) { { lhs * rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i16 rhs) { { lhs / rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i16 rhs) { { lhs % rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i16 rhs) { { lhs += rhs } -> SameAs<i32&>; });
STATIC_REQUIRE(requires(i32 lhs, i16 rhs) { { lhs -= rhs } -> SameAs<i32&>; });
STATIC_REQUIRE(requires(i32 lhs, i16 rhs) { { lhs *= rhs } -> SameAs<i32&>; });
STATIC_REQUIRE(requires(i32 lhs, i16 rhs) { { lhs /= rhs } -> SameAs<i32&>; });
STATIC_REQUIRE(requires(i32 lhs, i16 rhs) { { lhs %= rhs } -> SameAs<i32&>; });

STATIC_REQUIRE(requires(i32 lhs, i32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i32 lhs, i32 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i32 lhs, i32 rhs) { { lhs + rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i32 rhs) { { lhs - rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i32 rhs) { { lhs * rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i32 rhs) { { lhs / rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i32 rhs) { { lhs % rhs } -> SameAs<i32>; });
STATIC_REQUIRE(requires(i32 lhs, i32 rhs) { { lhs += rhs } -> SameAs<i32&>; });
STATIC_REQUIRE(requires(i32 lhs, i32 rhs) { { lhs -= rhs } -> SameAs<i32&>; });
STATIC_REQUIRE(requires(i32 lhs, i32 rhs) { { lhs *= rhs } -> SameAs<i32&>; });
STATIC_REQUIRE(requires(i32 lhs, i32 rhs) { { lhs /= rhs } -> SameAs<i32&>; });
STATIC_REQUIRE(requires(i32 lhs, i32 rhs) { { lhs %= rhs } -> SameAs<i32&>; });

STATIC_REQUIRE(requires(i32 lhs, i32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i32 lhs, i64 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i32 lhs, i64 rhs) { { lhs + rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i32 lhs, i64 rhs) { { lhs - rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i32 lhs, i64 rhs) { { lhs * rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i32 lhs, i64 rhs) { { lhs / rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i32 lhs, i64 rhs) { { lhs % rhs } -> SameAs<i64>; });
// clang-format on
}

TEST_CASE("i64", "[types/i64]")
{
// clang-format off
STATIC_REQUIRE(requires(i64 lhs, i8 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i64 lhs, i8 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i64 lhs, i8 rhs) { { lhs + rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i8 rhs) { { lhs - rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i8 rhs) { { lhs * rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i8 rhs) { { lhs / rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i8 rhs) { { lhs % rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i8 rhs) { { lhs += rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i8 rhs) { { lhs -= rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i8 rhs) { { lhs *= rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i8 rhs) { { lhs /= rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i8 rhs) { { lhs %= rhs } -> SameAs<i64&>; });

STATIC_REQUIRE(requires(i64 lhs, i16 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i64 lhs, i16 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i64 lhs, i16 rhs) { { lhs + rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i16 rhs) { { lhs - rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i16 rhs) { { lhs * rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i16 rhs) { { lhs / rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i16 rhs) { { lhs % rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i16 rhs) { { lhs += rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i16 rhs) { { lhs -= rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i16 rhs) { { lhs *= rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i16 rhs) { { lhs /= rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i16 rhs) { { lhs %= rhs } -> SameAs<i64&>; });

STATIC_REQUIRE(requires(i64 lhs, i32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i64 lhs, i32 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i64 lhs, i32 rhs) { { lhs + rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i32 rhs) { { lhs - rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i32 rhs) { { lhs * rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i32 rhs) { { lhs / rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i32 rhs) { { lhs % rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i32 rhs) { { lhs += rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i32 rhs) { { lhs -= rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i32 rhs) { { lhs *= rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i32 rhs) { { lhs /= rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i32 rhs) { { lhs %= rhs } -> SameAs<i64&>; });

STATIC_REQUIRE(requires(i64 lhs, i32 rhs) { { lhs == rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i64 lhs, i64 rhs) { { lhs <= rhs } -> SameAs<bool>; });
STATIC_REQUIRE(requires(i64 lhs, i64 rhs) { { lhs + rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i64 rhs) { { lhs - rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i64 rhs) { { lhs * rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i64 rhs) { { lhs / rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i64 rhs) { { lhs % rhs } -> SameAs<i64>; });
STATIC_REQUIRE(requires(i64 lhs, i64 rhs) { { lhs += rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i64 rhs) { { lhs -= rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i64 rhs) { { lhs *= rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i64 rhs) { { lhs /= rhs } -> SameAs<i64&>; });
STATIC_REQUIRE(requires(i64 lhs, i64 rhs) { { lhs %= rhs } -> SameAs<i64&>; });
// clang-format on
}

diff --git a/ test/source/utility/buffer_test.cpp b/ test/source/utility/buffer_test.cpp

@@ -4,7 +4,7 @@


#include <catch2/catch_test_macros.hpp>

#include "based/types/literals.hpp"
#include "based/integral/literals.hpp"

template struct based::buffer<sizeof(void*)>;