based

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

commit e34ac5ad6024931bb29429f4bb5e88c2f89b3fba
parent 5c92017e0635dd36a1a92271dd85edcfd7217415
author Dimitrije Dobrota < mail@dimitrijedobrota.com >
date Fri, 16 May 2025 21:26:31 +0200

Big step towards type safety

Diffstat:
M include/based/enum/enum.hpp | ++++++++ ------
M include/based/enum/enum_flag.hpp | +
M include/based/list.hpp | ++++++++++++ -------
M include/based/types/strong.hpp | ++++++++++++++++++++++++++++++ ----------------------------------------------------
M include/based/types/types.hpp | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ---------
M test/CMakeLists.txt | +
M test/source/enum_flag_test.cpp | +++ ---
M test/source/enum_test.cpp | +++ ---
M test/source/list_test.cpp | ++++++++++++++++++++++++++++ ------------------------
M test/source/types/strong_type_test.cpp | +++++++++++ ------
A test/source/types/type_test.cpp | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
M test/source/utility/buffer_test.cpp | ++++++ ----

12 files changed, 633 insertions(+), 203 deletions(-)


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

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


#define BASED_E_DETAIL_DEFINE_VAL(Qualifier, Initial, Name, Index) \
inline constexpr BASED_E_DETAIL_SET( \
Qualifier::Name, (Initial) + Qualifier::type::size - (Index) - 1 \
Qualifier::Name, \
Qualifier::type::value_type {Initial} + Qualifier::type::size - (Index) \
- 1 \
)

#define BASED_E_DETAIL_DEFINE_NAMES(Qualifier, ...) \

@@ -68,7 +70,7 @@

} \
\
template<class... Args> \
requires(sizeof...(Args) == Name::type::size) \
requires(Name::type::size_type(sizeof...(Args)) == Name::type::size) \
constexpr explicit array(Args&&... args \
) noexcept /* NOLINTNEXTLINE(*decay*) */ \
: base({based::forward<Args>(args)...}) \

@@ -77,22 +79,22 @@

\
const T& operator[](Name::type val) const \
{ \
return base::operator[](val.value - (Initial)); \
return base::operator[](val.value - Name::type::value_type {Initial}); \
} \
\
T& operator[](Name::type val) \
{ \
return base::operator[](val.value - (Initial)); \
return base::operator[](val.value - Name::type::value_type {Initial}); \
} \
\
const T& at(Name::type val) const \
{ \
return base::operator[](val.value - (Initial)); \
return base::operator[](val.value - Name::type::value_type {Initial}); \
} \
\
T& at(Name::type val) \
{ \
return base::operator[](val.value - (Initial)); \
return base::operator[](val.value - Name::type::value_type {Initial}); \
} \
};

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

@@ -58,6 +58,7 @@

class type \
{ \
friend Name; \
friend struct based::enum_flag_wrapper<type>; \
\
constexpr explicit type(Type enum_value) \
: value(enum_value) \

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

@@ -3,6 +3,9 @@

#include <cassert>
#include <vector>

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

namespace based
{

@@ -19,7 +22,7 @@ private:

struct node_t
{
value_type value {};
list_type next = list_type(0);
list_type next;
};

std::vector<node_t> m_pool;

@@ -27,20 +30,20 @@ private:


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

[[nodiscard]] node_t& node(list_type x)
{
assert(x != 0);
return m_pool[x - 1];
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(m_pool.size());
return list_type {static_cast<list_type::basic_type>(m_pool.size())};
}

public:

@@ -212,7 +215,9 @@ public:


[[nodiscard]] bool is_empty(const queue_t& queue) const
{
return is_empty(queue.first); } [[nodiscard]] queue_t queue_empty() { return {node_empty(), node_empty()}; }
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)
{

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

@@ -9,18 +9,58 @@ namespace based

#define BASED_DETAIL_MACRO(decl, val) \
decltype(decl) \
{ \
static_cast<decltype(decl)::value_type>(val) \
static_cast<decltype(decl)::basic_type>(val) \
}

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

ValueType value;
constexpr ~strong_type() = default;

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

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

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;

basic_type 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); };

@@ -33,6 +73,17 @@ constexpr auto operator+(LHS lhs, RHS rhs)

}

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)
{
lhs.value += rhs.value;
return lhs;
}

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

template<class LHS, class RHS>

@@ -72,58 +123,6 @@ constexpr auto operator%(LHS lhs, RHS rhs)

return BASED_DETAIL_MACRO(mod(lhs, rhs), lhs.value % rhs.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--);
}

template<class LHS>
concept neggable = requires(LHS lhs) { lneg(lhs); };

template<class LHS>
requires neggable<LHS>
constexpr auto operator~(LHS lhs)
{
return BASED_DETAIL_MACRO(lneg(lhs), ~lhs.value);
}

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

@@ -154,106 +153,46 @@ constexpr auto operator^(LHS lhs, RHS rhs)

return BASED_DETAIL_MACRO(lxor(lhs, rhs), lhs.value ^ rhs.value);
}

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

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

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

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

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

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

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

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

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

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

template<class LHS, class RHS = LHS>
concept equal_andable = requires(LHS lhs, RHS rhs) { eland(lhs, rhs); };
template<class LHS>
concept preincable = requires(LHS lhs) { preinc(lhs); };

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

template<class LHS, class RHS = LHS>
concept equal_orable = requires(LHS lhs, RHS rhs) { elor(lhs, rhs); };
template<class LHS>
concept postincable = requires(LHS lhs) { postinc(lhs); };

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

template<class LHS, class RHS = LHS>
concept equal_xorable = requires(LHS lhs, RHS rhs) { elxor(lhs, rhs); };
template<class LHS>
concept predecable = requires(LHS lhs) { predec(lhs); };

template<class LHS, class RHS = LHS>
requires equal_xorable<LHS, RHS>
constexpr auto& operator^=(LHS& lhs, RHS rhs)
template<class LHS>
requires predecable<LHS>
constexpr auto operator--(LHS& lhs)
{
lhs.value ^= rhs.value;
--lhs.value;
return lhs;
}

template<class LHS, class RHS>
concept equalable = requires(LHS lhs, RHS rhs) {
{
equal(lhs, rhs)
} -> SameAs<bool>;
};
template<class LHS>
concept postdecable = requires(LHS lhs) { postdec(lhs); };

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

#undef BASED_DETAIL_MACRO

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

@@ -1,21 +1,99 @@

#pragma once

#include "based/macro/foreach_1.hpp"
#include "based/types/strong.hpp"

namespace based
{

// NOLINTBEGIN(google-runtime-int)

using i8 = signed char;
using i16 = signed short int;
using i32 = signed int;
using i64 = signed long int;
using bi8 = signed char;
using bi16 = signed short int;
using bi32 = signed int;
using bi64 = signed long int;

using bu8 = unsigned char;
using bu16 = unsigned short int;
using bu32 = unsigned int;
using bu64 = unsigned long int;

using size_t = bu64;

#define TYPE(Name) \
/* NOLINTNEXTLINE(*macro*) */ \
struct Name : strong_type<b##Name, Name> \
{ \
using strong_type::strong_type; \
using strong_type::operator=; \
}; \
\
namespace literals \
{ \
constexpr auto operator""_##Name(unsigned long long val) \
{ \
/* NOLINTNEXTLINE(*macro*) */ \
return Name {static_cast<Name::basic_type>(val)}; \
} \
} // namespace literals

TYPE(i8)
TYPE(i16)
TYPE(i32)
TYPE(i64)

#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;

#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;

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

using u8 = unsigned char;
using u16 = unsigned short int;
using u32 = unsigned int;
using u64 = unsigned long int;
TYPE(u8)
TYPE(u16)
TYPE(u32)
TYPE(u64)

using size_t = u64;
BASED_FOREACH_1(u, BASED_DETAIL_OP_UNARY, preinc, postinc, predec, postdec)
BASED_FOREACH_1(
u,
BASED_DETAIL_OP_BINARY,
compare,
order,
add,
sub,
mul,
div,
mod,
land,
lor,
lxor
)

// NOLINTEND(google-runtime-int)

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

@@ -28,6 +28,7 @@ endfunction()

## ----- Types -----

add_test(types strong_type_test)
add_test(types type_test)

## ----- Trait -----

diff --git a/ test/source/enum_flag_test.cpp b/ test/source/enum_flag_test.cpp

@@ -12,8 +12,8 @@

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

BASED_DECLARE_ENUM_FLAG(var, based::u8, empty, a, b, c)
BASED_DEFINE_ENUM_FLAG(var, based::u8, empty, a, b, c)
BASED_DECLARE_ENUM_FLAG(var, based::bu8, empty, a, b, c)
BASED_DEFINE_ENUM_FLAG(var, based::bu8, empty, a, b, c)

TEST_CASE("types", "[enum/enum_flag]")
{

@@ -72,7 +72,7 @@ TEST_CASE("operations", "[enum/enum_flag]")


TEST_CASE("enum_flag_wrapper", "[enum/enum_flag_wrapper]")
{
based::u8 flags = 0;
based::bu8 flags = 0;

{
auto wrapper = based::enum_flag_wrapper<var::type>(flags);

diff --git a/ test/source/enum_test.cpp b/ test/source/enum_test.cpp

@@ -15,7 +15,7 @@


struct test
{
BASED_DECLARE_ENUM(var, based::u8, 0, a, b, c)
BASED_DECLARE_ENUM(var, based::bu8, 0, a, b, c)

[[nodiscard]] int get_var(var::type req) const;

@@ -25,7 +25,7 @@ private:

int m_c = 3;
};

BASED_DEFINE_ENUM_CLASS(test, var, based::u8, 0, a, b, c)
BASED_DEFINE_ENUM_CLASS(test, var, based::bu8, 0, a, b, c)

inline int test::get_var(var::type req) const
{

@@ -61,7 +61,7 @@ TEST_CASE("safety", "[enum/enum]")

REQUIRE(crnt.get_var(test::var::b) == 2);
REQUIRE(crnt.get_var(test::var::c) == 3);

REQUIRE(!based::Invocable<decltype(&test::get_var), based::u8>);
REQUIRE(!based::Invocable<decltype(&test::get_var), based::bu8>);
REQUIRE(!based::Invocable<decltype(&test::get_var), int>);
}

diff --git a/ test/source/list_test.cpp b/ test/source/list_test.cpp

@@ -10,6 +10,7 @@ template class based::list_pool<based::u8, based::u8>;


TEST_CASE("list_pool", "[list/list_pool]")
{
using namespace based::literals; // NOLINT
using list_pool = based::list_pool<based::u8, based::u8>;

auto pool = list_pool();

@@ -23,21 +24,21 @@ TEST_CASE("list_pool", "[list/list_pool]")


SECTION("add one node")
{
head = pool.allocate(1, head);
head = pool.allocate(1_u8, head);

REQUIRE(pool.is_empty(head) == false);
REQUIRE(pool.value(head) == 1);
REQUIRE(pool.value(head) == 1_u8);

REQUIRE(pool.next(head) == pool.node_empty());

SECTION("add two nodes")
{
head = pool.allocate(2, head);
head = pool.allocate(2_u8, head);

REQUIRE(pool.is_empty(head) == false);
REQUIRE(pool.value(head) == 2);
REQUIRE(pool.value(head) == 2_u8);

REQUIRE(pool.value(pool.next(head)) == 1);
REQUIRE(pool.value(pool.next(head)) == 1_u8);
REQUIRE(pool.next(pool.next(head)) == pool.node_empty());

head = pool.free(head);

@@ -45,12 +46,12 @@ TEST_CASE("list_pool", "[list/list_pool]")


SECTION("alloc after free")
{
head = pool.allocate(2, head);
head = pool.allocate(2_u8, head);
head = pool.free(head);
head = pool.allocate(3, head);
head = pool.allocate(3_u8, head);

REQUIRE(pool.is_empty(head) == false);
REQUIRE(pool.value(head) == 3);
REQUIRE(pool.value(head) == 3_u8);

head = pool.free(head);
}

@@ -64,13 +65,14 @@ TEST_CASE("list_pool", "[list/list_pool]")


TEST_CASE("list_pool iterator", "[list/list_pool]")
{
using namespace based::literals; // NOLINT
using list_pool = based::list_pool<based::u8, based::u8>;

auto pool = list_pool();
auto head = pool.node_empty();

static constexpr based::size_t iter_count = 0xFF;
for (based::u8 i = 0; i < iter_count; i++) {
static constexpr auto iter_count = 0xFF_u8;
for (auto i = 0_u8; i < iter_count; i++) {
head = pool.allocate(i, head);
}

@@ -78,13 +80,13 @@ TEST_CASE("list_pool iterator", "[list/list_pool]")

{
using iter = list_pool::iterator;

based::u32 sum = 0;
auto sum = 0_u32;
for (auto it = iter(pool, head); it != iter(pool); it++) {
sum += *it.operator->();
sum += *it;
}

REQUIRE(sum == 0xFF * 0xFE);
REQUIRE(sum == 0xFF_u32 * 0xFE_u32);
}

SECTION("accumulate")

@@ -101,7 +103,7 @@ TEST_CASE("list_pool iterator", "[list/list_pool]")

}
);

REQUIRE(sum == 0xFF * 0xFE / 2);
REQUIRE(sum == 0xFF_u32 * 0xFE_u32 / 2_u32);
}

based::free_list(pool, head);

@@ -109,13 +111,14 @@ TEST_CASE("list_pool iterator", "[list/list_pool]")


TEST_CASE("list_pool const iterator", "[list/list_pool]")
{
using namespace based::literals; // NOLINT
using list_pool = based::list_pool<based::u8, based::u8>;

auto pool = list_pool();
auto head = pool.node_empty();

static constexpr based::size_t iter_count = 0xFF;
for (based::u8 i = 0; i < iter_count; i++) {
static constexpr auto iter_count = 0xFF_u8;
for (auto i = 0_u8; i < iter_count; i++) {
head = pool.allocate(i, head);
}

@@ -123,13 +126,13 @@ TEST_CASE("list_pool const iterator", "[list/list_pool]")

{
using iter = list_pool::const_iterator;

based::u32 sum = 0;
auto sum = 0_u32;
for (auto it = iter(pool, head); it != iter(pool); it++) {
sum += *it.operator->();
sum += *it;
}

REQUIRE(sum == 0xFF * 0xFE);
REQUIRE(sum == 0xFF_u32 * 0xFE_u32);
}

SECTION("const accumulate")

@@ -150,7 +153,7 @@ TEST_CASE("list_pool const iterator", "[list/list_pool]")

);
};

REQUIRE(sum(pool, head) == 0xFF * 0xFE / 2);
REQUIRE(sum(pool, head) == 0xFF_u32 * 0xFE_u32 / 2_u32);
}

based::free_list(pool, head);

@@ -174,25 +177,26 @@ TEST_CASE("list_pool queue", "[list/list_pool/queue]")

REQUIRE(pool.pop_front(queue) == queue);
}

static constexpr based::size_t iter_count = 0xFF;
for (based::u8 i = 0; i < iter_count; i++) {
if (i % 2 == 0) {
using namespace based::literals; // NOLINT
static constexpr auto iter_count = 0xFF_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 == 0) {
if (i % 3_u8 == 0_u8) {
queue = pool.pop_front(queue);
}
}

based::u64 sum = 0;
auto sum = 0_u64;
for (auto it = iter(pool, queue.first); it != iter(pool); ++it) {
sum += *it;
}

pool.free(queue);

REQUIRE(sum == 21717);
REQUIRE(sum == 21717_u64);
}

diff --git a/ test/source/types/strong_type_test.cpp b/ test/source/types/strong_type_test.cpp

@@ -1,4 +1,4 @@

// #define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE
#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include "based/types/strong.hpp"

@@ -8,15 +8,19 @@


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 equal(t1, t1) -> bool;
auto equal(t2, t2) -> bool;
auto compare(t1, t1) -> bool;
auto compare(t2, t2) -> bool;

auto add(t1, t1) -> t1;
auto add(t1, t2) -> t1;

@@ -30,7 +34,8 @@ TEST_CASE("strong_type", "[types/strong_type]")

STATIC_REQUIRE(based::addable<t1, t2>);
STATIC_REQUIRE(based::addable<t2, t1>);

REQUIRE(t1 {10} + t1 {20} == t1 {30});
REQUIRE(t1 {10} + t2 {20} == t1 {30});
REQUIRE(t2 {10} + t1 {20} == t2 {30});
using namespace based::literals; // NOLINT
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

@@ -0,0 +1,393 @@

#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, 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, 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<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>; });
// 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, 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, 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<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>; });
// 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, 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, 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<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>; });
// 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, 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, 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<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>; });
// 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, 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, 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<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>; });
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, 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, 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<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>; });
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, 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, 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<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>; });
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, 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, 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<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>; });
// clang-format on
}

diff --git a/ test/source/utility/buffer_test.cpp b/ test/source/utility/buffer_test.cpp

@@ -31,16 +31,17 @@ TEST_CASE("valid type", "[template/buffer]")


TEST_CASE("buffer", "[template/buffer]")
{
using namespace based::literals; // NOLINT
using buffer = based::buffer<sizeof(based::size_t)>;

static constexpr based::u8 value = 8;
static constexpr auto value = 8_u8;
buffer buf(std::in_place_type<based::u8>, value);

REQUIRE(*buf.as<based::u8>() == value);

SECTION("emplace")
{
static constexpr based::u16 new_value = 10;
static constexpr auto new_value = 10_u16;
buf.emplace<based::u16>(new_value);

REQUIRE(*buf.as<based::u16>() == new_value);

@@ -48,7 +49,7 @@ TEST_CASE("buffer", "[template/buffer]")


SECTION("swap")
{
static constexpr based::u16 new_value = 10;
static constexpr auto new_value = 10_u16;
buffer new_buf(std::in_place_type<based::u16>, new_value);
buf.swap(new_buf);

@@ -59,9 +60,10 @@ TEST_CASE("buffer", "[template/buffer]")


TEST_CASE("const buffer", "[template/buffer]")
{
using namespace based::literals; // NOLINT
using buffer = based::buffer<sizeof(based::size_t)>;

static constexpr based::u8 value = 8;
static constexpr auto value = 8_u8;
const buffer buf(std::in_place_type<based::u8>, value);

REQUIRE(*buf.as<based::u8>() == value);