based

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

commit 3856d3137cdba85b4727fc08a4c6cd9678771686
parent 510a7d2b0afcfb88e852707aeebb2fed23a8176f
author Dimitrije Dobrota < mail@dimitrijedobrota.com >
date Wed, 4 Jun 2025 15:10:40 +0200

Rework type conversions and literals

Diffstat:
M include/based/char/character.hpp | +++++++++ --------------------
M include/based/char/mapper.hpp | +++ ----
M include/based/container/array.hpp | ++ --
D include/based/types/limits.hpp | ---------------------------------------------------------------------------------
M include/based/types/literals.hpp | ++++++++++++++++++ ------------------------------------
M include/based/types/strong.hpp | ++ ---
M include/based/types/types.hpp | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -------------
M test/source/types/limits.cpp | ++ --
M test/source/types/literals.cpp | ++++++++++++++++++++++++ ------------------------

9 files changed, 271 insertions(+), 223 deletions(-)


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

@@ -5,53 +5,42 @@

namespace based
{

class character : public strong_type<unsigned char, character>
struct character : public strong_type<char, character>
{
static constexpr auto cast(char pos)
{
return static_cast<unsigned char>(pos);
}

static constexpr auto cast(unsigned char pos)
{
return static_cast<char>(pos);
}

public:
using strong_type::strong_type;
using strong_type::operator=;

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

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

[[nodiscard]] char chr() const { return cast(value); }
[[nodiscard]] u8 ord() const { return u8::basic_cast(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 == cast(rhs);
return lhs.value == rhs;
}

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

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

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

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

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

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

namespace based

@@ -24,7 +23,7 @@ class mapper


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

@@ -36,7 +35,7 @@ class mapper

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

@@ -50,7 +49,7 @@ class mapper


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

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

@@ -8,9 +8,9 @@ namespace based

{

template<class T, class U, U n>
class array : public std::array<T, u64::basic_cast(n).value>
class array : public std::array<T, u64::cast(n).value>
{
using base = std::array<T, u64::basic_cast(n).value>;
using base = std::array<T, u64::cast(n).value>;

static constexpr auto cast(U pos)
{

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

@@ -1,95 +0,0 @@

#pragma once

#include "based/types/types.hpp"

namespace based
{

template<class T>
struct limits;

// Signed

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

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

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

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

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

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

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

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

// Unsigned

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

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

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

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

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

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

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

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

} // namespace based

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

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


#include "based/char/is/digit.hpp"
#include "based/concepts/is/castable.hpp"
#include "based/types/limits.hpp"
#include "based/types/types.hpp"

// NOLINTBEGIN(google-runtime-int)

@@ -11,26 +10,17 @@ namespace based

{

// Signed

namespace detail
{

template<signed long long val>
constexpr auto make_signed_itnernal()
consteval i make_signed_itnernal()
{
if constexpr (val <= limits<i8>::max.value) {
return i8::basic_cast(val);
} else if constexpr (val <= limits<i16>::max.value) {
return i16::basic_cast(val);
} else if constexpr (val <= limits<i32>::max.value) {
return i32::basic_cast(val);
} else {
return i64::basic_cast(val);
}
return i::underlying_cast(val);
}

template<signed long long v, char c, char... cs>
constexpr auto make_signed_itnernal()
consteval auto make_signed_itnernal()
{
const signed long long radix = 10;

@@ -41,7 +31,7 @@ constexpr auto make_signed_itnernal()

}

template<char... cs>
constexpr auto make_signed()
consteval auto make_signed()
{
return make_signed_itnernal<0, cs...>();
}

@@ -52,7 +42,7 @@ namespace literals

{

template<char... cs>
auto operator"" _i()
consteval auto operator"" _i()
{
return detail::make_signed<cs...>();
}

@@ -61,28 +51,28 @@ template<char... cs>

requires CastableTo<decltype(detail::make_signed<cs...>()), u8>
consteval auto operator"" _i8()
{
return static_cast<u8>(detail::make_signed<cs...>());
return i8::cast(detail::make_signed<cs...>());
}

template<char... cs>
requires CastableTo<decltype(detail::make_signed<cs...>()), u16>
consteval auto operator"" _i16()
{
return static_cast<u16>(detail::make_signed<cs...>());
return i16::cast(detail::make_signed<cs...>());
}

template<char... cs>
requires CastableTo<decltype(detail::make_signed<cs...>()), u32>
consteval auto operator"" _i32()
{
return static_cast<u32>(detail::make_signed<cs...>());
return i32::cast(detail::make_signed<cs...>());
}

template<char... cs>
requires CastableTo<decltype(detail::make_signed<cs...>()), u64>
consteval auto operator"" _i64()
{
return static_cast<u64>(detail::make_signed<cs...>());
return i64::cast(detail::make_signed<cs...>());
}

} // namespace literals

@@ -93,21 +83,13 @@ namespace detail

{

template<unsigned long long val>
constexpr auto make_unsigned_internal()
consteval u make_unsigned_internal()
{
if constexpr (val <= limits<u8>::max.value) {
return u8::basic_cast(val);
} else if constexpr (val <= limits<u16>::max.value) {
return u16::basic_cast(val);
} else if constexpr (val <= limits<u32>::max.value) {
return u32::basic_cast(val);
} else {
return u64::basic_cast(val);
}
return u::underlying_cast(val);
}

template<unsigned long long v, char c, char... cs>
constexpr auto make_unsigned_internal()
consteval auto make_unsigned_internal()
{
const unsigned long long radix = 10;

@@ -118,7 +100,7 @@ constexpr auto make_unsigned_internal()

}

template<char... cs>
constexpr auto make_unsigned()
consteval auto make_unsigned()
{
return make_unsigned_internal<0, cs...>();
}

@@ -129,7 +111,7 @@ namespace literals

{

template<char... cs>
auto operator"" _u()
consteval auto operator"" _u()
{
return detail::make_unsigned<cs...>();
}

@@ -138,28 +120,28 @@ template<char... cs>

requires CastableTo<decltype(detail::make_unsigned<cs...>()), u8>
consteval auto operator"" _u8()
{
return static_cast<u8>(detail::make_unsigned<cs...>());
return u8::cast(detail::make_unsigned<cs...>());
}

template<char... cs>
requires CastableTo<decltype(detail::make_unsigned<cs...>()), u16>
consteval auto operator"" _u16()
{
return static_cast<u16>(detail::make_unsigned<cs...>());
return u16::cast(detail::make_unsigned<cs...>());
}

template<char... cs>
requires CastableTo<decltype(detail::make_unsigned<cs...>()), u32>
consteval auto operator"" _u32()
{
return static_cast<u32>(detail::make_unsigned<cs...>());
return u32::cast(detail::make_unsigned<cs...>());
}

template<char... cs>
requires CastableTo<decltype(detail::make_unsigned<cs...>()), u64>
consteval auto operator"" _u64()
{
return static_cast<u64>(detail::make_unsigned<cs...>());
return u64::cast(detail::make_unsigned<cs...>());
}

} // namespace literals

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

@@ -46,14 +46,13 @@ struct strong_type

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

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

template<class T>
requires is_class_v<T>
static constexpr Tag basic_cast(T value)
static constexpr Tag cast(T value)
{
return static_cast<Tag>(value);
}

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

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

#pragma once

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

@@ -20,6 +21,39 @@ using bu64 = unsigned long long int;


using size_t = bu64;

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

@@ -31,7 +65,9 @@ struct i32 : strong_type<signed int, i32>

using strong_type::strong_type;
using strong_type::operator=;

explicit constexpr operator i64() { return i64::basic_cast(value); }
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>

@@ -39,8 +75,11 @@ struct i16 : strong_type<signed short int, i16>

using strong_type::strong_type;
using strong_type::operator=;

explicit constexpr operator i64() { return i64::basic_cast(value); }
explicit constexpr operator i32() { return i32::basic_cast(value); }
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>

@@ -48,11 +87,91 @@ struct i8 : strong_type<signed char, i8>

using strong_type::strong_type;
using strong_type::operator=;

explicit constexpr operator i64() { return i64::basic_cast(value); }
explicit constexpr operator i32() { return i32::basic_cast(value); }
explicit constexpr operator i16() { return i16::basic_cast(value); }
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;

@@ -64,7 +183,9 @@ struct u32 : strong_type<unsigned int, u32>

using strong_type::strong_type;
using strong_type::operator=;

explicit constexpr operator u64() { return u64::basic_cast(value); }
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>

@@ -72,8 +193,11 @@ struct u16 : strong_type<unsigned short int, u16>

using strong_type::strong_type;
using strong_type::operator=;

explicit constexpr operator u64() { return u64::basic_cast(value); }
explicit constexpr operator u32() { return u32::basic_cast(value); }
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>

@@ -81,37 +205,87 @@ struct u8 : strong_type<unsigned char, u8>

using strong_type::strong_type;
using strong_type::operator=;

explicit constexpr operator u64() { return u64::basic_cast(value); }
explicit constexpr operator u32() { return u32::basic_cast(value); }
explicit constexpr operator u16() { return u16::basic_cast(value); }
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); }
};

#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;
template<>
struct limits<u8>
{
static constexpr bool is_integer = true;
static constexpr bool is_signed = false;

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

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

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

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include "based/types/limits.hpp"

#include <catch2/catch_test_macros.hpp>

#include "based/types/types.hpp"

using based::limits;

TEST_CASE("unsigned", "[types/literals]")

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

@@ -4,38 +4,38 @@


#include <catch2/catch_test_macros.hpp>

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

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

using based::SameAs;
using based::CastableTo;

TEST_CASE("unsigned", "[types/literals]")
{
STATIC_REQUIRE(SameAs<decltype(0_u), based::u8>);
STATIC_REQUIRE(SameAs<decltype(255_u), based::u8>);
STATIC_REQUIRE(SameAs<decltype(256_u), based::u16>);
STATIC_REQUIRE(SameAs<decltype(65535_u), based::u16>);
STATIC_REQUIRE(SameAs<decltype(65536_u), based::u32>);
STATIC_REQUIRE(SameAs<decltype(4294967295_u), based::u32>);
STATIC_REQUIRE(SameAs<decltype(4294967296_u), based::u64>);
STATIC_REQUIRE(SameAs<decltype(18446744073709551615_u), based::u64>);
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(SameAs<decltype(0_i), based::i8>);
STATIC_REQUIRE(SameAs<decltype(127_i), based::i8>);
STATIC_REQUIRE(SameAs<decltype(128_i), based::i16>);
STATIC_REQUIRE(SameAs<decltype(32767_i), based::i16>);
STATIC_REQUIRE(SameAs<decltype(2147483647_i), based::i32>);
STATIC_REQUIRE(SameAs<decltype(2147483648_i), based::i64>);
STATIC_REQUIRE(SameAs<decltype(9223372036854775807_i), based::i64>);

STATIC_REQUIRE(SameAs<decltype(-127_i), based::i8>);
STATIC_REQUIRE(SameAs<decltype(-128_i), based::i16>);
STATIC_REQUIRE(SameAs<decltype(-32767_i), based::i16>);
STATIC_REQUIRE(SameAs<decltype(-2147483647_i), based::i32>);
STATIC_REQUIRE(SameAs<decltype(-2147483648_i), based::i64>);
STATIC_REQUIRE(SameAs<decltype(-9223372036854775807_i), based::i64>);
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>);
}