From a141c401f78467bc15f62882fca5d55a007cacbb Mon Sep 17 00:00:00 2001 From: Steven Le Rouzic Date: Mon, 17 Feb 2025 00:21:48 +0100 Subject: Reorganize everything --- asl/base/BUILD.bazel | 36 ++++++ asl/base/annotations.hpp | 9 ++ asl/base/assert.cpp | 12 ++ asl/base/assert.hpp | 33 +++++ asl/base/config.hpp | 17 +++ asl/base/float.hpp | 17 +++ asl/base/float_tests.cpp | 23 ++++ asl/base/functional.hpp | 65 ++++++++++ asl/base/functional_tests.cpp | 73 +++++++++++ asl/base/integers.hpp | 40 ++++++ asl/base/integers_tests.cpp | 15 +++ asl/base/meta.hpp | 248 ++++++++++++++++++++++++++++++++++++ asl/base/meta_tests.cpp | 289 ++++++++++++++++++++++++++++++++++++++++++ asl/base/utility.hpp | 95 ++++++++++++++ asl/base/utility_tests.cpp | 1 + 15 files changed, 973 insertions(+) create mode 100644 asl/base/BUILD.bazel create mode 100644 asl/base/annotations.hpp create mode 100644 asl/base/assert.cpp create mode 100644 asl/base/assert.hpp create mode 100644 asl/base/config.hpp create mode 100644 asl/base/float.hpp create mode 100644 asl/base/float_tests.cpp create mode 100644 asl/base/functional.hpp create mode 100644 asl/base/functional_tests.cpp create mode 100644 asl/base/integers.hpp create mode 100644 asl/base/integers_tests.cpp create mode 100644 asl/base/meta.hpp create mode 100644 asl/base/meta_tests.cpp create mode 100644 asl/base/utility.hpp create mode 100644 asl/base/utility_tests.cpp (limited to 'asl/base') diff --git a/asl/base/BUILD.bazel b/asl/base/BUILD.bazel new file mode 100644 index 0000000..317c20b --- /dev/null +++ b/asl/base/BUILD.bazel @@ -0,0 +1,36 @@ +cc_library( + name = "base", + hdrs = [ + "annotations.hpp", + "assert.hpp", + "config.hpp", + "float.hpp", + "functional.hpp", + "integers.hpp", + "meta.hpp", + "utility.hpp", + ], + srcs = [ + "assert.cpp", + ], + visibility = ["//visibility:public"], +) + +[cc_test( + name = "%s_tests" % name, + srcs = [ + "%s_tests.cpp" % name, + ], + deps = [ + ":base", + "//asl/tests:utils", + "//asl/testing", + "//asl/types:box", + ], +) for name in [ + "float", + "functional", + "integers", + "meta", + "utility", +]] diff --git a/asl/base/annotations.hpp b/asl/base/annotations.hpp new file mode 100644 index 0000000..b87dbde --- /dev/null +++ b/asl/base/annotations.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "asl/base/config.hpp" + +#if ASL_COMPILER_CLANG_CL + #define ASL_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]] +#elif ASL_COMPILER_CLANG + #define ASL_NO_UNIQUE_ADDRESS [[no_unique_address]] +#endif diff --git a/asl/base/assert.cpp b/asl/base/assert.cpp new file mode 100644 index 0000000..2383e9e --- /dev/null +++ b/asl/base/assert.cpp @@ -0,0 +1,12 @@ +#include "asl/base/assert.hpp" +// #include "asl/io/print.hpp" + + +void asl::report_assert_failure(const char* msg, const source_location& sl) +{ + // @Todo(org) + // eprint("------------------------------------------------------------\n"); + // eprint("Assertion failure at {}, line {}:\n", sl.file, sl.line); + // eprint("{}\n", msg); + // eprint("------------------------------------------------------------\n"); +} diff --git a/asl/base/assert.hpp b/asl/base/assert.hpp new file mode 100644 index 0000000..42e8635 --- /dev/null +++ b/asl/base/assert.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include "asl/base/config.hpp" +#include "asl/base/meta.hpp" + +namespace asl +{ + +void report_assert_failure(const char* msg, const source_location& sl = source_location{}); + +} // namespace asl + +#if ASL_COMPILER_CLANG_CL + #define ASL_DEBUG_BREAK() __debugbreak() +#elif ASL_COMPILER_CLANG + #define ASL_DEBUG_BREAK() __builtin_debugtrap() +#endif + +#define ASL_ASSERT(...) \ + if (__VA_ARGS__) {} \ + else \ + { \ + ::asl::report_assert_failure(#__VA_ARGS__); \ + ASL_DEBUG_BREAK(); \ + } + +#define ASL_ASSERT_RELEASE(...) \ + if (__VA_ARGS__) {} \ + else \ + { \ + ::asl::report_assert_failure(#__VA_ARGS__); \ + ASL_DEBUG_BREAK(); \ + } diff --git a/asl/base/config.hpp b/asl/base/config.hpp new file mode 100644 index 0000000..e182569 --- /dev/null +++ b/asl/base/config.hpp @@ -0,0 +1,17 @@ +#pragma once + +#if defined(_WIN32) + #define ASL_OS_WINDOWS 1 +#elif defined(__linux__) + #define ASL_OS_LINUX 1 +#else + #error Unknown OS +#endif + +#if defined(__clang__) && defined(_MSC_VER) + #define ASL_COMPILER_CLANG_CL 1 +#elif defined(__clang__) + #define ASL_COMPILER_CLANG 1 +#else + #error Unknown compiler +#endif diff --git a/asl/base/float.hpp b/asl/base/float.hpp new file mode 100644 index 0000000..2de2e0c --- /dev/null +++ b/asl/base/float.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include "asl/base/meta.hpp" + +namespace asl +{ + +template constexpr T infinity() { return __builtin_inf(); } + +template constexpr T nan() { return static_cast(__builtin_nanf("")); } + +template constexpr bool is_infinity(T f) { return __builtin_isinf(f); } + +template constexpr bool is_nan(T f) { return __builtin_isnan(f); } + +} // namespace asl + diff --git a/asl/base/float_tests.cpp b/asl/base/float_tests.cpp new file mode 100644 index 0000000..0a5bebf --- /dev/null +++ b/asl/base/float_tests.cpp @@ -0,0 +1,23 @@ +#include "asl/base/float.hpp" + +#include "asl/testing/testing.hpp" + +ASL_TEST(is_infinity) +{ + ASL_TEST_EXPECT(!asl::is_infinity(0.0F)); + ASL_TEST_EXPECT(!asl::is_infinity(-25.0F)); + ASL_TEST_EXPECT(asl::is_infinity(45.0F / 0.0F)); + ASL_TEST_EXPECT(asl::is_infinity(-45.0F / 0.0F)); + ASL_TEST_EXPECT(asl::is_infinity(asl::infinity())); + ASL_TEST_EXPECT(asl::is_infinity(-asl::infinity())); +} + +ASL_TEST(is_nan) +{ + ASL_TEST_EXPECT(!asl::is_nan(0.0F)); + ASL_TEST_EXPECT(!asl::is_nan(-25.0F)); + ASL_TEST_EXPECT(!asl::is_nan(45.0F / 0.0F)); + ASL_TEST_EXPECT(asl::is_nan(asl::nan())); + ASL_TEST_EXPECT(asl::is_nan(asl::nan())); +} + diff --git a/asl/base/functional.hpp b/asl/base/functional.hpp new file mode 100644 index 0000000..d820bce --- /dev/null +++ b/asl/base/functional.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include "asl/base/meta.hpp" +#include "asl/base/utility.hpp" + +namespace asl { + +template +constexpr auto invoke(is_func auto C::* f, auto&& self, Args&&... args) + requires requires { + (self.*f)(ASL_FWD(args)...); + } +{ + return (ASL_FWD(self).*f)(ASL_FWD(args)...); +} + +template +constexpr auto invoke(is_func auto C::* f, auto* self, Args&&... args) + requires requires { + (self->*f)(ASL_FWD(args)...); + } +{ + return (self->*f)(ASL_FWD(args)...); +} + +template +constexpr auto invoke(is_object auto C::* m, auto&& self, Args&&...) + requires ( + sizeof...(Args) == 0 && + requires { self.*m; } + ) +{ + return ASL_FWD(self).*m; +} + +template +constexpr auto invoke(is_object auto C::* m, auto* self, Args&&...) + requires ( + sizeof...(Args) == 0 && + requires { self->*m; } + ) +{ + return self->*m; +} + +template +constexpr auto invoke(auto&& f, Args&&... args) + requires requires { + f(ASL_FWD(args)...); + } +{ + return ASL_FWD(f)(ASL_FWD(args)...); +} + +template struct _result_of_helper; + +template +struct _result_of_helper +{ + using type = decltype(invoke(declval(), declval()...)); +}; + +template using result_of_t = _result_of_helper::type; + +} // namespace asl diff --git a/asl/base/functional_tests.cpp b/asl/base/functional_tests.cpp new file mode 100644 index 0000000..92c5c7b --- /dev/null +++ b/asl/base/functional_tests.cpp @@ -0,0 +1,73 @@ +#include "asl/base/functional.hpp" +#include "asl/testing/testing.hpp" + +struct HasFunction +{ + void do_something(int, float) {} +}; + +struct HasMember +{ + int member{}; + int member_array[4]{}; + void (*member_fn)(){}; +}; + +struct Functor +{ + int64_t operator()() { return 35; } + int operator()(int x) { return x; } +}; + +static int some_func0() { return 1; } +static int some_func1(int x) { return x + 1; } +[[maybe_unused]] static float some_func1(float x) { return x + 1; } +static int some_func2(int x, int b) { return x + b; } + +static_assert(asl::same_as, int64_t>); +static_assert(asl::same_as, int>); +static_assert(asl::same_as(some_func1))(float)>, float>); +static_assert(asl::same_as, void>); +static_assert(asl::same_as, int>); + +ASL_TEST(invoke_member_function) +{ + HasFunction c; + asl::invoke(&HasFunction::do_something, c, 5, 5.0F); + asl::invoke(&HasFunction::do_something, &c, 5, 5.0F); +} + +ASL_TEST(invoke_member_data) +{ + HasMember c; + + asl::invoke(&HasMember::member, c); + asl::invoke(&HasMember::member_array, c); + asl::invoke(&HasMember::member_fn, c); + asl::invoke(&HasMember::member, &c); + asl::invoke(&HasMember::member_array, &c); + asl::invoke(&HasMember::member_fn, &c); +} + +ASL_TEST(invoke_fn) +{ + ASL_TEST_EXPECT(asl::invoke(some_func0) == 1); + ASL_TEST_EXPECT(asl::invoke(static_cast(some_func1), 8) == 9); + ASL_TEST_EXPECT(asl::invoke(some_func2, 4, 8) == 12); + ASL_TEST_EXPECT(asl::invoke(&some_func0) == 1); + ASL_TEST_EXPECT(asl::invoke(static_cast(&some_func1), 8) == 9); + ASL_TEST_EXPECT(asl::invoke(&some_func2, 4, 8) == 12); +} + +ASL_TEST(invoke_operator_call) +{ + Functor f; + ASL_TEST_EXPECT(asl::invoke(f) == 35); + ASL_TEST_EXPECT(asl::invoke(f, 8) == 8); +} + +ASL_TEST(invoke_lambda) +{ + ASL_TEST_EXPECT(asl::invoke([](){ return 35; }) == 35); + ASL_TEST_EXPECT(asl::invoke([](int x){ return x + 2; }, 6) == 8); +} diff --git a/asl/base/integers.hpp b/asl/base/integers.hpp new file mode 100644 index 0000000..c18c850 --- /dev/null +++ b/asl/base/integers.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include "asl/base/config.hpp" + +using int8_t = signed char; +using int16_t = signed short; +using int32_t = signed int; +#if ASL_OS_WINDOWS + using int64_t = signed long long; +#elif ASL_OS_LINUX + using int64_t = signed long; +#endif + +using uint8_t = unsigned char; +using uint16_t = unsigned short; +using uint32_t = unsigned int; +#if ASL_OS_WINDOWS + using uint64_t = unsigned long long; +#elif ASL_OS_LINUX + using uint64_t = unsigned long; +#endif + +struct uint128_t +{ + uint64_t high; + uint64_t low; +}; + +using size_t = uint64_t; +using isize_t = int64_t; + +using uintptr_t = size_t; + +namespace asl +{ + +enum class byte : uint8_t {}; + +} // namespace asl + diff --git a/asl/base/integers_tests.cpp b/asl/base/integers_tests.cpp new file mode 100644 index 0000000..52feb85 --- /dev/null +++ b/asl/base/integers_tests.cpp @@ -0,0 +1,15 @@ +#include "asl/base/integers.hpp" + +static_assert(sizeof(int8_t) == 1); +static_assert(sizeof(int16_t) == 2); +static_assert(sizeof(int32_t) == 4); +static_assert(sizeof(int64_t) == 8); + +static_assert(sizeof(uint8_t) == 1); +static_assert(sizeof(uint16_t) == 2); +static_assert(sizeof(uint32_t) == 4); +static_assert(sizeof(uint64_t) == 8); + +static_assert(sizeof(asl::byte) == 1); + +static_assert(sizeof(uintptr_t) == sizeof(void*)); diff --git a/asl/base/meta.hpp b/asl/base/meta.hpp new file mode 100644 index 0000000..ce17420 --- /dev/null +++ b/asl/base/meta.hpp @@ -0,0 +1,248 @@ +#pragma once + +#include "asl/base/integers.hpp" + +namespace asl { + +struct source_location +{ + const char* file; + int line; + + explicit source_location( + const char* file_ = __builtin_FILE(), + int line_ = __builtin_LINE()) + : file{file_} + , line{line_} + {} +}; + +struct empty {}; + +template struct id { using type = T; }; + +template static constexpr isize_t types_count = sizeof...(Args); + +template struct integral_constant { static constexpr T value = kValue; }; +template using bool_constant = integral_constant; + +using true_type = bool_constant; +using false_type = bool_constant; + +template struct _select_helper { using type = V; }; +template struct _select_helper { using type = U; }; + +template using select_t = _select_helper::type; + +template struct _same_as_helper : false_type {}; +template struct _same_as_helper : true_type {}; + +template concept same_as = _same_as_helper::value && _same_as_helper::value; + +template auto _as_lref_helper(int) -> id; +template auto _as_lref_helper(...) -> id; + +template auto _as_rref_helper(int) -> id; +template auto _as_rref_helper(...) -> id; + +template using as_lref_t = decltype(_as_lref_helper(0))::type; +template using as_rref_t = decltype(_as_rref_helper(0))::type; + +template consteval as_rref_t declval() {} + +template struct _un_ref_t { using type = T; }; +template struct _un_ref_t { using type = T; }; +template struct _un_ref_t { using type = T; }; + +template using un_ref_t = _un_ref_t::type; + +template concept constructible_from = __is_constructible(T, Args...); + +template concept default_constructible = constructible_from; +template concept copy_constructible = constructible_from>; +template concept move_constructible = constructible_from>; + +template concept trivially_constructible_from = __is_trivially_constructible(T, Args...); + +template concept trivially_default_constructible = trivially_constructible_from; +template concept trivially_copy_constructible = trivially_constructible_from>; +template concept trivially_move_constructible = trivially_constructible_from>; + +template concept assignable_from = __is_assignable(T, Args...); + +template concept copy_assignable = assignable_from, as_lref_t>; +template concept move_assignable = assignable_from, as_rref_t>; + +template concept trivially_assignable_from = __is_trivially_assignable(T, Args...); + +template concept trivially_copy_assignable = trivially_assignable_from, as_lref_t>; +template concept trivially_move_assignable = trivially_assignable_from, as_rref_t>; + +template concept trivially_destructible = __is_trivially_destructible(T); + +template concept copyable = copy_constructible && copy_assignable; +template concept moveable = move_constructible && move_assignable; + +template +concept convertible_from = __is_convertible(From, To); + +template +concept derived_from = __is_class(Derived) && __is_class(Base) && convertible_from; + +using nullptr_t = decltype(nullptr); + +template struct _un_const_helper { using type = T; }; +template struct _un_const_helper { using type = T; }; + +template using un_const_t = _un_const_helper::type; + +template struct _is_const_helper : false_type {}; +template struct _is_const_helper : true_type {}; + +template concept is_const = _is_const_helper::value; + +template struct _un_volatile_helper { using type = T; }; +template struct _un_volatile_helper { using type = T; }; + +template using un_volatile_t = _un_volatile_helper::type; + +template using un_cv_t = un_volatile_t>; + +template using un_cvref_t = un_ref_t>; + +template concept is_void = same_as>; + +template struct _is_ref_helper { static constexpr bool l = false; static constexpr bool r = false; }; +template struct _is_ref_helper { static constexpr bool l = true; static constexpr bool r = false; }; +template struct _is_ref_helper { static constexpr bool l = false; static constexpr bool r = true; }; + +template concept is_ref = _is_ref_helper::l || _is_ref_helper::r; +template concept is_rref = _is_ref_helper::r; +template concept is_lref = _is_ref_helper::l; + +template struct _is_ptr_helper : false_type {}; +template struct _is_ptr_helper : true_type {}; + +template concept is_ptr = _is_ptr_helper>::value; + +template struct _tame_helper { using type = T; }; + +#define TAME_HELPER_IMPL(TRAILING) \ + template \ + struct _tame_helper { using type = R(Args...); } + +TAME_HELPER_IMPL(); +TAME_HELPER_IMPL(&); +TAME_HELPER_IMPL(&&); +TAME_HELPER_IMPL(const); +TAME_HELPER_IMPL(const &); +TAME_HELPER_IMPL(const &&); +TAME_HELPER_IMPL(volatile); +TAME_HELPER_IMPL(volatile &); +TAME_HELPER_IMPL(volatile &&); +TAME_HELPER_IMPL(const volatile); +TAME_HELPER_IMPL(const volatile &); +TAME_HELPER_IMPL(const volatile &&); +TAME_HELPER_IMPL(noexcept); +TAME_HELPER_IMPL(& noexcept); +TAME_HELPER_IMPL(&& noexcept); +TAME_HELPER_IMPL(const noexcept); +TAME_HELPER_IMPL(const & noexcept); +TAME_HELPER_IMPL(const && noexcept); +TAME_HELPER_IMPL(volatile noexcept); +TAME_HELPER_IMPL(volatile & noexcept); +TAME_HELPER_IMPL(volatile && noexcept); +TAME_HELPER_IMPL(const volatile noexcept); +TAME_HELPER_IMPL(const volatile & noexcept); +TAME_HELPER_IMPL(const volatile && noexcept); + +#undef TAME_HELPER_IMPL + +template using tame_t = _tame_helper::type; + +template struct _is_func_helper : false_type {}; +template struct _is_func_helper : true_type {}; + +template concept is_func = _is_func_helper>::value; + +template concept is_object = !is_void && !is_ref && !is_func; + +template struct _is_array_helper : false_type {}; +template struct _is_array_helper : true_type {}; +template struct _is_array_helper : true_type {}; + +template concept is_array = _is_array_helper::value; + +template struct _is_floating_point_helper : false_type {}; +template<> struct _is_floating_point_helper : true_type {}; +template<> struct _is_floating_point_helper : true_type {}; + +template concept is_floating_point = _is_floating_point_helper>::value; + +template struct _is_integer_helper : false_type {}; +template<> struct _is_integer_helper : true_type {}; +template<> struct _is_integer_helper : true_type {}; +template<> struct _is_integer_helper : true_type {}; +template<> struct _is_integer_helper : true_type {}; +template<> struct _is_integer_helper : true_type {}; +template<> struct _is_integer_helper : true_type {}; +template<> struct _is_integer_helper : true_type {}; +template<> struct _is_integer_helper : true_type {}; + +template concept is_integer = _is_integer_helper>::value; + +template concept is_enum = __is_enum(T); + +template struct is_uniquely_represented : false_type {}; +template struct is_uniquely_represented : true_type {}; +template struct is_uniquely_represented : true_type {}; +template<> struct is_uniquely_represented : true_type {}; +template<> struct is_uniquely_represented : true_type {}; + +template concept uniquely_represented = is_uniquely_represented>::value; + +template +concept equality_comparable_with = requires (const un_cvref_t& a, const un_cvref_t& b) +{ + { a == b } -> same_as; + { b == a } -> same_as; + { a != b } -> same_as; + { b != a } -> same_as; +}; + +template concept equality_comparable = equality_comparable_with; + +struct niche_t {}; + +template +concept has_niche = constructible_from && equality_comparable_with; + +template +concept is_niche = same_as, niche_t>; + +template +concept _derefs_with_indirection_as = requires(T& t) +{ + *t; + requires convertible_from; +}; + +template +concept _derefs_reference_as = is_ref && convertible_from; + +template +concept _derefs_value_as = !is_ref && convertible_from; + +template T> +constexpr U& deref(T&& t) { return static_cast(*t); } + +template T> +constexpr U& deref(T&& t) { return static_cast(t); } + +template T> +constexpr U& deref(T&& t) { return static_cast(t); } + +template +concept derefs_as = _derefs_with_indirection_as || _derefs_reference_as || _derefs_value_as; + +} // namespace asl diff --git a/asl/base/meta_tests.cpp b/asl/base/meta_tests.cpp new file mode 100644 index 0000000..7aa7145 --- /dev/null +++ b/asl/base/meta_tests.cpp @@ -0,0 +1,289 @@ +#include "asl/base/meta.hpp" +#include "asl/tests/types.hpp" +#include "asl/testing/testing.hpp" +#include "asl/types/box.hpp" + +struct Struct {}; +union Union {}; +enum Enum : uint8_t { EnumVariant = 0, }; +enum class EnumClass : uint8_t { Variant = 0, }; + +static_assert(!asl::same_as); +static_assert(asl::same_as); + +static_assert(asl::same_as, float>); +static_assert(asl::same_as, int>); + +static_assert(asl::default_constructible); +static_assert(asl::default_constructible); +static_assert(asl::default_constructible); + +static_assert(asl::trivially_default_constructible); +static_assert(asl::trivially_default_constructible); +static_assert(!asl::trivially_default_constructible); + +static_assert(asl::copy_constructible); +static_assert(asl::copy_constructible); +static_assert(asl::copy_constructible); +static_assert(!asl::copy_constructible); +static_assert(!asl::copy_constructible); + +static_assert(asl::trivially_copy_constructible); +static_assert(asl::trivially_copy_constructible); +static_assert(asl::trivially_copy_constructible); +static_assert(!asl::trivially_copy_constructible); +static_assert(!asl::trivially_copy_constructible); +static_assert(!asl::trivially_copy_constructible); +static_assert(!asl::trivially_copy_constructible); + +static_assert(asl::move_constructible); +static_assert(asl::move_constructible); +static_assert(asl::move_constructible); +static_assert(asl::move_constructible); +static_assert(!asl::move_constructible); + +static_assert(asl::trivially_move_constructible); +static_assert(asl::trivially_move_constructible); +static_assert(asl::trivially_move_constructible); +static_assert(!asl::trivially_move_constructible); +static_assert(!asl::trivially_move_constructible); +static_assert(!asl::trivially_move_constructible); +static_assert(!asl::trivially_move_constructible); + +static_assert(asl::copy_assignable); +static_assert(asl::copy_assignable); +static_assert(asl::copy_assignable); +static_assert(!asl::copy_assignable); +static_assert(!asl::copy_assignable); + +static_assert(asl::trivially_copy_assignable); +static_assert(asl::trivially_copy_assignable); +static_assert(asl::trivially_copy_assignable); +static_assert(asl::trivially_copy_assignable); +static_assert(!asl::trivially_copy_assignable); +static_assert(!asl::trivially_copy_assignable); +static_assert(!asl::trivially_copy_assignable); + +static_assert(asl::copyable); +static_assert(asl::copyable); +static_assert(asl::copyable); +static_assert(!asl::copyable); +static_assert(!asl::copyable); + +static_assert(asl::moveable); +static_assert(asl::moveable); +static_assert(asl::moveable); +static_assert(asl::moveable); +static_assert(!asl::moveable); + +static_assert(asl::move_assignable); +static_assert(asl::move_assignable); +static_assert(asl::move_assignable); +static_assert(asl::move_assignable); +static_assert(!asl::move_assignable); + +static_assert(asl::trivially_move_assignable); +static_assert(asl::trivially_move_assignable); +static_assert(asl::trivially_move_assignable); +static_assert(asl::trivially_move_assignable); +static_assert(!asl::trivially_move_assignable); +static_assert(!asl::trivially_move_assignable); +static_assert(!asl::trivially_move_assignable); + +static_assert(asl::trivially_destructible); +static_assert(asl::trivially_destructible); +static_assert(asl::trivially_destructible); +static_assert(!asl::trivially_destructible); +static_assert(asl::trivially_destructible); +static_assert(asl::trivially_destructible); +static_assert(asl::trivially_destructible); + +static_assert(asl::same_as>); +static_assert(asl::same_as>); +static_assert(asl::same_as>); + +static_assert(asl::same_as>); +static_assert(asl::same_as>); +static_assert(asl::same_as>); + +static_assert(asl::same_as>); +static_assert(asl::same_as>); +static_assert(asl::same_as>); +static_assert(asl::same_as>); + +static_assert(asl::is_void); +static_assert(asl::is_void); +static_assert(asl::is_void); +static_assert(asl::is_void); +static_assert(!asl::is_void); +static_assert(!asl::is_void); +static_assert(!asl::is_void); +static_assert(!asl::is_void); +static_assert(!asl::is_void); +static_assert(!asl::is_void); + +static_assert(asl::is_ref); +static_assert(asl::is_ref); +static_assert(asl::is_ref); +static_assert(asl::is_ref); +static_assert(!asl::is_ref); +static_assert(!asl::is_ref); +static_assert(!asl::is_ref); +static_assert(!asl::is_ref); + +static_assert(asl::is_ptr); +static_assert(asl::is_ptr); +static_assert(asl::is_ptr); +static_assert(!asl::is_ptr); +static_assert(!asl::is_ptr); +static_assert(!asl::is_ptr); +static_assert(!asl::is_ptr); + +static_assert(asl::same_as>); +static_assert(asl::same_as>); +static_assert(asl::same_as>); +static_assert(asl::same_as>); +static_assert(asl::same_as>); +static_assert(asl::same_as>); +static_assert(asl::same_as>); +static_assert(asl::same_as>); + +static_assert(asl::is_func); +static_assert(asl::is_func); +static_assert(asl::is_func); +static_assert(asl::is_func); +static_assert(asl::is_func); +static_assert(asl::is_func); +static_assert(!asl::is_func); +static_assert(!asl::is_func); +static_assert(!asl::is_func); +static_assert(!asl::is_func); + +static_assert(asl::is_object); +static_assert(asl::is_object); +static_assert(asl::is_object); +static_assert(asl::is_object); +static_assert(asl::is_object); +static_assert(asl::is_object); +static_assert(asl::is_object); +static_assert(asl::is_object); +static_assert(!asl::is_object); +static_assert(!asl::is_object); +static_assert(!asl::is_object); +static_assert(!asl::is_object); + +static_assert(!asl::is_array); +static_assert(!asl::is_array); +static_assert(!asl::is_array); +static_assert(!asl::is_array); +static_assert(!asl::is_array); +static_assert(asl::is_array); +static_assert(asl::is_array); +static_assert(!asl::is_array); +static_assert(!asl::is_array); +static_assert(!asl::is_array); +static_assert(!asl::is_array); +static_assert(!asl::is_array); + +static_assert(asl::same_as>); +static_assert(asl::same_as>); +static_assert(asl::same_as>); +static_assert(asl::same_as>); + +static_assert(asl::types_count == 2); +static_assert(asl::types_count == 2); +static_assert(asl::types_count == 1); +static_assert(asl::types_count<> == 0); + +class Base {}; +class Derived : public Base {}; +class C {}; +class D { public: operator C() { return c; } C c; }; // NOLINT +class E { public: template E(T&&) {} }; // NOLINT + +static_assert(asl::convertible_from); +static_assert(!asl::convertible_from); +static_assert(asl::convertible_from); +static_assert(!asl::convertible_from); +static_assert(asl::convertible_from); + +static_assert(!asl::convertible_from); +static_assert(asl::convertible_from); +static_assert(asl::convertible_from); +static_assert(asl::convertible_from); +static_assert(!asl::convertible_from); +static_assert(!asl::convertible_from); +static_assert(!asl::convertible_from); + +static_assert(asl::derived_from); +static_assert(!asl::derived_from); +static_assert(!asl::derived_from); +static_assert(!asl::derived_from); +static_assert(!asl::derived_from); +static_assert(!asl::derived_from); +static_assert(!asl::derived_from); + +static_assert(!asl::is_const); +static_assert(asl::is_const); +static_assert(!asl::is_const); +static_assert(asl::is_const); + +static_assert(asl::is_floating_point); +static_assert(asl::is_floating_point); +static_assert(asl::is_floating_point); +static_assert(!asl::is_floating_point); +static_assert(!asl::is_floating_point); +static_assert(!asl::is_floating_point); + +static_assert(asl::uniquely_represented); +static_assert(asl::uniquely_represented); +static_assert(!asl::uniquely_represented); + +enum Enum1 {}; +enum class Enum2 {}; + +static_assert(asl::uniquely_represented); +static_assert(asl::uniquely_represented); + +static_assert(!asl::is_enum); +static_assert(asl::is_enum); +static_assert(asl::is_enum); + +static_assert(asl::derefs_as); +static_assert(asl::derefs_as); +static_assert(asl::derefs_as); +static_assert(asl::derefs_as, int>); + +static_assert(asl::derefs_as); +static_assert(asl::derefs_as); +static_assert(asl::derefs_as); +static_assert(asl::derefs_as, Base>); + +static void wants_int(int) {} +static void wants_base(Base&) {} +static void wants_base_ptr(Base*) {} + +ASL_TEST(deref) +{ + int a = 4; + auto b = asl::make_box(5); + + wants_int(asl::deref(5)); + wants_int(asl::deref(a)); + wants_int(asl::deref(&a)); + wants_int(asl::deref(b)); + + Derived c{}; + auto d = asl::make_box(); + + wants_base(asl::deref(Derived{})); + wants_base(asl::deref(c)); + wants_base(asl::deref(&c)); + wants_base(asl::deref(d)); + + wants_base_ptr(&asl::deref(Derived{})); + wants_base_ptr(&asl::deref(c)); + wants_base_ptr(&asl::deref(&c)); + wants_base_ptr(&asl::deref(d)); +} + diff --git a/asl/base/utility.hpp b/asl/base/utility.hpp new file mode 100644 index 0000000..c03554f --- /dev/null +++ b/asl/base/utility.hpp @@ -0,0 +1,95 @@ +#pragma once + +#include "asl/base/meta.hpp" +#include "asl/base/assert.hpp" + +#define ASL_MOVE(...) (static_cast<::asl::un_ref_t&&>(__VA_ARGS__)) + +#define ASL_FWD(expr_) (static_cast(expr_)) + +namespace asl +{ + +struct in_place_t {}; +static constexpr in_place_t in_place{}; + +template +constexpr void swap(T& a, T& b) +{ + T tmp{ASL_MOVE(a)}; + a = ASL_MOVE(b); + b = ASL_MOVE(tmp); +} + +template +T exchange(T& obj, U&& new_value) +{ + T old_value = ASL_MOVE(obj); + obj = ASL_FWD(new_value); + return old_value; +} + +template +constexpr U bit_cast(T value) requires (sizeof(T) == sizeof(U)) +{ + return __builtin_bit_cast(U, value); +} + +template +constexpr T min(T a, T b) +{ + return (a <= b) ? a : b; +} + +template +constexpr T max(T a, T b) +{ + return (a >= b) ? a : b; +} + +constexpr uint64_t round_up_pow2(uint64_t v) +{ + ASL_ASSERT(v <= 0x8000'0000'0000'0000); + + v -= 1; + + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v |= v >> 32; + + return v + 1; +} + +constexpr bool is_pow2(isize_t v) +{ + return v > 0 && ((v - 1) & v) == 0; +} + +#define ASL_DELETE_COPY(T) \ + T(const T&) = delete; \ + T& operator=(const T&) = delete; + +#define ASL_DELETE_MOVE(T) \ + T(T&&) = delete; \ + T& operator=(T&&) = delete; + +#define ASL_DELETE_COPY_MOVE(T) \ + ASL_DELETE_COPY(T) \ + ASL_DELETE_MOVE(T) + +#define ASL_DEFAULT_COPY(T) \ + T(const T&) = default; \ + T& operator=(const T&) = default; + +#define ASL_DEFAULT_MOVE(T) \ + T(T&&) = default; \ + T& operator=(T&&) = default; + +#define ASL_DEFAULT_COPY_MOVE(T) \ + ASL_DEFAULT_COPY(T) \ + ASL_DEFAULT_MOVE(T) + +} // namespace asl diff --git a/asl/base/utility_tests.cpp b/asl/base/utility_tests.cpp new file mode 100644 index 0000000..4b8e3d1 --- /dev/null +++ b/asl/base/utility_tests.cpp @@ -0,0 +1 @@ +#include "asl/base/utility.hpp" -- cgit