From a141c401f78467bc15f62882fca5d55a007cacbb Mon Sep 17 00:00:00 2001 From: Steven Le Rouzic <steven.lerouzic@gmail.com> Date: Mon, 17 Feb 2025 00:21:48 +0100 Subject: Reorganize everything --- asl/BUILD.bazel | 78 ----- asl/allocator.cpp | 56 ---- asl/allocator.hpp | 58 ---- asl/annotations.hpp | 9 - asl/assert.cpp | 11 - asl/assert.hpp | 33 -- asl/atomic.hpp | 51 --- 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 + asl/box.hpp | 134 -------- asl/buffer.hpp | 459 -------------------------- asl/config.hpp | 17 - asl/containers/BUILD.bazel | 58 ++++ asl/containers/buffer.hpp | 459 ++++++++++++++++++++++++++ asl/containers/buffer_tests.cpp | 603 +++++++++++++++++++++++++++++++++++ asl/containers/hash_map.hpp | 178 +++++++++++ asl/containers/hash_map_tests.cpp | 48 +++ asl/containers/hash_set.hpp | 418 ++++++++++++++++++++++++ asl/containers/hash_set_tests.cpp | 185 +++++++++++ asl/float.hpp | 17 - asl/format.cpp | 201 ------------ asl/format.hpp | 109 ------- asl/format_float.cpp | 98 ------ asl/formatting/BUILD.bazel | 32 ++ asl/formatting/format.cpp | 201 ++++++++++++ asl/formatting/format.hpp | 109 +++++++ asl/formatting/format_float.cpp | 98 ++++++ asl/formatting/format_tests.cpp | 110 +++++++ asl/functional.hpp | 65 ---- asl/hash.hpp | 138 -------- asl/hash_cityhash.cpp | 517 ------------------------------ asl/hash_map.hpp | 178 ----------- asl/hash_set.hpp | 418 ------------------------ asl/hashing/BUILD.bazel | 33 ++ asl/hashing/hash.hpp | 138 ++++++++ asl/hashing/hash_cityhash.cpp | 517 ++++++++++++++++++++++++++++++ asl/hashing/hash_tests.cpp | 260 +++++++++++++++ asl/integers.hpp | 40 --- asl/io.hpp | 20 -- asl/io/BUILD.bazel | 26 ++ asl/io/print.cpp | 31 ++ asl/io/print.hpp | 30 ++ asl/io/writer.hpp | 20 ++ asl/layout.hpp | 37 --- asl/logging/BUILD.bazel | 6 +- asl/logging/logging.cpp | 4 +- asl/logging/logging.hpp | 6 +- asl/logging/logging_tests.cpp | 2 +- asl/maybe_uninit.hpp | 72 ----- asl/memory.hpp | 137 -------- asl/memory/BUILD.bazel | 16 + asl/memory/allocator.cpp | 54 ++++ asl/memory/allocator.hpp | 58 ++++ asl/memory/layout.hpp | 37 +++ asl/memory/memory.hpp | 137 ++++++++ asl/meta.hpp | 248 -------------- asl/option.hpp | 509 ----------------------------- asl/print.cpp | 31 -- asl/print.hpp | 29 -- asl/span.hpp | 235 -------------- asl/status.cpp | 96 ------ asl/status.hpp | 157 --------- asl/status_or.hpp | 186 ----------- asl/string.hpp | 77 ----- asl/string_builder.hpp | 156 --------- asl/string_view.hpp | 107 ------- asl/strings/BUILD.bazel | 56 ++++ asl/strings/string.hpp | 77 +++++ asl/strings/string_builder.hpp | 156 +++++++++ asl/strings/string_builder_tests.cpp | 23 ++ asl/strings/string_tests.cpp | 21 ++ asl/strings/string_view.hpp | 107 +++++++ asl/strings/string_view_tests.cpp | 117 +++++++ asl/synchronization/BUILD.bazel | 10 + asl/synchronization/atomic.hpp | 51 +++ asl/testing/BUILD.bazel | 4 +- asl/testing/testing.cpp | 2 +- asl/testing/testing.hpp | 2 +- asl/tests/BUILD.bazel | 10 + asl/tests/box_tests.cpp | 102 ------ asl/tests/buffer_tests.cpp | 603 ----------------------------------- asl/tests/float_tests.cpp | 23 -- asl/tests/format_tests.cpp | 110 ------- asl/tests/functional_tests.cpp | 73 ----- asl/tests/hash_map_tests.cpp | 48 --- asl/tests/hash_set_tests.cpp | 185 ----------- asl/tests/hash_tests.cpp | 260 --------------- asl/tests/integers_tests.cpp | 15 - asl/tests/maybe_uninit_tests.cpp | 22 -- asl/tests/meta_tests.cpp | 289 ----------------- asl/tests/option_tests.cpp | 330 ------------------- asl/tests/span_tests.cpp | 444 -------------------------- asl/tests/status_or_tests.cpp | 84 ----- asl/tests/status_tests.cpp | 82 ----- asl/tests/string_builder_tests.cpp | 23 -- asl/tests/string_tests.cpp | 21 -- asl/tests/string_view_tests.cpp | 117 ------- asl/tests/test_types.hpp | 92 ------ asl/tests/types.hpp | 89 ++++++ asl/tests/utility_tests.cpp | 1 - asl/types/BUILD.bazel | 135 ++++++++ asl/types/box.hpp | 134 ++++++++ asl/types/box_tests.cpp | 102 ++++++ asl/types/maybe_uninit.hpp | 72 +++++ asl/types/maybe_uninit_tests.cpp | 22 ++ asl/types/option.hpp | 509 +++++++++++++++++++++++++++++ asl/types/option_tests.cpp | 330 +++++++++++++++++++ asl/types/span.hpp | 235 ++++++++++++++ asl/types/span_tests.cpp | 444 ++++++++++++++++++++++++++ asl/types/status.cpp | 96 ++++++ asl/types/status.hpp | 157 +++++++++ asl/types/status_or.hpp | 186 +++++++++++ asl/types/status_or_tests.cpp | 84 +++++ asl/types/status_tests.cpp | 82 +++++ asl/utility.hpp | 96 ------ 128 files changed, 8150 insertions(+), 7814 deletions(-) delete mode 100644 asl/BUILD.bazel delete mode 100644 asl/allocator.cpp delete mode 100644 asl/allocator.hpp delete mode 100644 asl/annotations.hpp delete mode 100644 asl/assert.cpp delete mode 100644 asl/assert.hpp delete mode 100644 asl/atomic.hpp 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 delete mode 100644 asl/box.hpp delete mode 100644 asl/buffer.hpp delete mode 100644 asl/config.hpp create mode 100644 asl/containers/BUILD.bazel create mode 100644 asl/containers/buffer.hpp create mode 100644 asl/containers/buffer_tests.cpp create mode 100644 asl/containers/hash_map.hpp create mode 100644 asl/containers/hash_map_tests.cpp create mode 100644 asl/containers/hash_set.hpp create mode 100644 asl/containers/hash_set_tests.cpp delete mode 100644 asl/float.hpp delete mode 100644 asl/format.cpp delete mode 100644 asl/format.hpp delete mode 100644 asl/format_float.cpp create mode 100644 asl/formatting/BUILD.bazel create mode 100644 asl/formatting/format.cpp create mode 100644 asl/formatting/format.hpp create mode 100644 asl/formatting/format_float.cpp create mode 100644 asl/formatting/format_tests.cpp delete mode 100644 asl/functional.hpp delete mode 100644 asl/hash.hpp delete mode 100644 asl/hash_cityhash.cpp delete mode 100644 asl/hash_map.hpp delete mode 100644 asl/hash_set.hpp create mode 100644 asl/hashing/BUILD.bazel create mode 100644 asl/hashing/hash.hpp create mode 100644 asl/hashing/hash_cityhash.cpp create mode 100644 asl/hashing/hash_tests.cpp delete mode 100644 asl/integers.hpp delete mode 100644 asl/io.hpp create mode 100644 asl/io/BUILD.bazel create mode 100644 asl/io/print.cpp create mode 100644 asl/io/print.hpp create mode 100644 asl/io/writer.hpp delete mode 100644 asl/layout.hpp delete mode 100644 asl/maybe_uninit.hpp delete mode 100644 asl/memory.hpp create mode 100644 asl/memory/BUILD.bazel create mode 100644 asl/memory/allocator.cpp create mode 100644 asl/memory/allocator.hpp create mode 100644 asl/memory/layout.hpp create mode 100644 asl/memory/memory.hpp delete mode 100644 asl/meta.hpp delete mode 100644 asl/option.hpp delete mode 100644 asl/print.cpp delete mode 100644 asl/print.hpp delete mode 100644 asl/span.hpp delete mode 100644 asl/status.cpp delete mode 100644 asl/status.hpp delete mode 100644 asl/status_or.hpp delete mode 100644 asl/string.hpp delete mode 100644 asl/string_builder.hpp delete mode 100644 asl/string_view.hpp create mode 100644 asl/strings/BUILD.bazel create mode 100644 asl/strings/string.hpp create mode 100644 asl/strings/string_builder.hpp create mode 100644 asl/strings/string_builder_tests.cpp create mode 100644 asl/strings/string_tests.cpp create mode 100644 asl/strings/string_view.hpp create mode 100644 asl/strings/string_view_tests.cpp create mode 100644 asl/synchronization/BUILD.bazel create mode 100644 asl/synchronization/atomic.hpp create mode 100644 asl/tests/BUILD.bazel delete mode 100644 asl/tests/box_tests.cpp delete mode 100644 asl/tests/buffer_tests.cpp delete mode 100644 asl/tests/float_tests.cpp delete mode 100644 asl/tests/format_tests.cpp delete mode 100644 asl/tests/functional_tests.cpp delete mode 100644 asl/tests/hash_map_tests.cpp delete mode 100644 asl/tests/hash_set_tests.cpp delete mode 100644 asl/tests/hash_tests.cpp delete mode 100644 asl/tests/integers_tests.cpp delete mode 100644 asl/tests/maybe_uninit_tests.cpp delete mode 100644 asl/tests/meta_tests.cpp delete mode 100644 asl/tests/option_tests.cpp delete mode 100644 asl/tests/span_tests.cpp delete mode 100644 asl/tests/status_or_tests.cpp delete mode 100644 asl/tests/status_tests.cpp delete mode 100644 asl/tests/string_builder_tests.cpp delete mode 100644 asl/tests/string_tests.cpp delete mode 100644 asl/tests/string_view_tests.cpp delete mode 100644 asl/tests/test_types.hpp create mode 100644 asl/tests/types.hpp delete mode 100644 asl/tests/utility_tests.cpp create mode 100644 asl/types/BUILD.bazel create mode 100644 asl/types/box.hpp create mode 100644 asl/types/box_tests.cpp create mode 100644 asl/types/maybe_uninit.hpp create mode 100644 asl/types/maybe_uninit_tests.cpp create mode 100644 asl/types/option.hpp create mode 100644 asl/types/option_tests.cpp create mode 100644 asl/types/span.hpp create mode 100644 asl/types/span_tests.cpp create mode 100644 asl/types/status.cpp create mode 100644 asl/types/status.hpp create mode 100644 asl/types/status_or.hpp create mode 100644 asl/types/status_or_tests.cpp create mode 100644 asl/types/status_tests.cpp delete mode 100644 asl/utility.hpp (limited to 'asl') diff --git a/asl/BUILD.bazel b/asl/BUILD.bazel deleted file mode 100644 index 2cc4af5..0000000 --- a/asl/BUILD.bazel +++ /dev/null @@ -1,78 +0,0 @@ -cc_library( - name = "asl", - hdrs = [ - "allocator.hpp", - "annotations.hpp", - "assert.hpp", - "atomic.hpp", - "box.hpp", - "buffer.hpp", - "config.hpp", - "float.hpp", - "format.hpp", - "functional.hpp", - "hash.hpp", - "hash_map.hpp", - "hash_set.hpp", - "integers.hpp", - "io.hpp", - "layout.hpp", - "maybe_uninit.hpp", - "memory.hpp", - "meta.hpp", - "option.hpp", - "print.hpp", - "span.hpp", - "status.hpp", - "status_or.hpp", - "string.hpp", - "string_builder.hpp", - "string_view.hpp", - "utility.hpp", - ], - srcs = [ - "allocator.cpp", - "assert.cpp", - "format.cpp", - "format_float.cpp", - "hash_cityhash.cpp", - "print.cpp", - "status.cpp", - ], - deps = [ - "//vendor/dragonbox", - ], - visibility = ["//visibility:public"], -) - -[cc_test( - name = "%s_tests" % name, - srcs = [ - "tests/%s_tests.cpp" % name, - "tests/test_types.hpp", - ], - deps = [ - ":asl", - "//asl/testing", - ], -) for name in [ - "box", - "buffer", - "float", - "format", - "functional", - "hash", - "hash_map", - "hash_set", - "integers", - "maybe_uninit", - "meta", - "option", - "span", - "status", - "status_or", - "string", - "string_builder", - "string_view", - "utility", -]] diff --git a/asl/allocator.cpp b/asl/allocator.cpp deleted file mode 100644 index 59bff76..0000000 --- a/asl/allocator.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "asl/allocator.hpp" -#include "asl/assert.hpp" -#include "asl/utility.hpp" -#include "asl/memory.hpp" -#include "asl/print.hpp" - -#include <cstdlib> - -// @Todo zalloc -// @Todo Cookies -// @Todo Debug values - -void* asl::GlobalHeap::alloc(const layout& layout) -{ -#if ASL_OS_WINDOWS - void* ptr = ::_aligned_malloc( - static_cast<size_t>(layout.size), - static_cast<size_t>(layout.align)); -#elif ASL_OS_LINUX - void* ptr = ::aligned_alloc( - static_cast<size_t>(layout.align), - static_cast<size_t>(layout.size)); -#endif - ASL_ASSERT(ptr != nullptr); // @Todo panic - return ptr; -} - -void* asl::GlobalHeap::realloc(void* old_ptr, [[maybe_unused]] const layout& old_layout, const layout& new_layout) -{ -#if ASL_OS_WINDOWS - return ::_aligned_realloc(old_ptr, - static_cast<size_t>(new_layout.size), - static_cast<size_t>(new_layout.align)); -#elif ASL_OS_LINUX - if (new_layout.align <= old_layout.align) - { - void* new_ptr = ::realloc(old_ptr, static_cast<size_t>(new_layout.size)); - ASL_ASSERT(new_ptr != nullptr); // @Todo panic - return new_ptr; - } - - void* new_ptr = alloc(new_layout); - asl::memcpy(new_ptr, old_ptr, asl::min(old_layout.size, new_layout.size)); - dealloc(old_ptr, old_layout); - return new_ptr; -#endif -} - -void asl::GlobalHeap::dealloc(void* ptr, const layout&) -{ -#if ASL_OS_WINDOWS - ::_aligned_free(ptr); -#elif ASL_OS_LINUX - ::free(ptr); -#endif -} diff --git a/asl/allocator.hpp b/asl/allocator.hpp deleted file mode 100644 index 90793dd..0000000 --- a/asl/allocator.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include "asl/layout.hpp" -#include "asl/meta.hpp" -#include "asl/memory.hpp" - -namespace asl -{ - -template<typename T> -concept allocator = moveable<T> && equality_comparable<T> && - requires(T& alloc, layout layout, void* ptr) - { - { alloc.alloc(layout) } -> same_as<void*>; - { alloc.realloc(ptr, layout, layout) } -> same_as<void*>; - alloc.dealloc(ptr, layout); - }; - -class GlobalHeap -{ -public: - static void* alloc(const layout&); - static void* realloc(void* ptr, const layout& old, const layout& new_layout); - static void dealloc(void* ptr, const layout&); - - constexpr bool operator==(const GlobalHeap&) const { return true; } -}; -static_assert(allocator<GlobalHeap>); - -using DefaultAllocator = GlobalHeap; - -template<typename T> -T* alloc_new(allocator auto& a, auto&&... args) -{ - void* ptr = a.alloc(layout::of<T>()); - return construct_at<T>(ptr, ASL_FWD(args)...); -} - -template<typename T> -void alloc_delete(allocator auto& a, T* ptr) -{ - destroy(ptr); - a.dealloc(ptr, layout::of<T>()); -} - -template<typename T> -constexpr T* alloc_new_default(auto&&... args) -{ - return alloc_new<T>(DefaultAllocator{}, ASL_FWD(args)...); -} - -template<typename T> -void alloc_delete_default(T* ptr) -{ - alloc_delete(DefaultAllocator{}, ptr); -} - -} // namespace asl diff --git a/asl/annotations.hpp b/asl/annotations.hpp deleted file mode 100644 index 6ea3a84..0000000 --- a/asl/annotations.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "asl/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/assert.cpp b/asl/assert.cpp deleted file mode 100644 index 353232e..0000000 --- a/asl/assert.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "asl/assert.hpp" -#include "asl/print.hpp" - - -void asl::report_assert_failure(const char* msg, const source_location& sl) -{ - eprint("------------------------------------------------------------\n"); - eprint("Assertion failure at {}, line {}:\n", sl.file, sl.line); - eprint("{}\n", msg); - eprint("------------------------------------------------------------\n"); -} diff --git a/asl/assert.hpp b/asl/assert.hpp deleted file mode 100644 index 608a44f..0000000 --- a/asl/assert.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include "asl/config.hpp" -#include "asl/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/atomic.hpp b/asl/atomic.hpp deleted file mode 100644 index 95c3715..0000000 --- a/asl/atomic.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include "asl/meta.hpp" - -namespace asl -{ - -enum class memory_order : int // NOLINT(*-enum-size) -{ - relaxed = __ATOMIC_RELAXED, - acquire = __ATOMIC_ACQUIRE, - release = __ATOMIC_RELEASE, - acq_rel = __ATOMIC_ACQ_REL, - seq_cst = __ATOMIC_SEQ_CST, -}; - -template<typename T> struct atomic { T m_value{}; }; - -inline void atomic_fence(memory_order order) -{ - __atomic_thread_fence(static_cast<int>(order)); -} - -template<is_integer T> -inline void atomic_store(atomic<T>* a, T value, memory_order order = memory_order::relaxed) -{ - __atomic_store(&a->m_value, &value, static_cast<int>(order)); -} - -template<is_integer T> -inline T atomic_load(atomic<T>* a, memory_order order = memory_order::relaxed) -{ - T value; - __atomic_load(&a->m_value, &value, static_cast<int>(order)); - return value; -} - -template<typename T> -inline T atomic_fetch_increment(atomic<T>* a, memory_order order = memory_order::relaxed) -{ - return __atomic_fetch_add(&a->m_value, 1, static_cast<int>(order)); -} - -template<typename T> -inline T atomic_fetch_decrement(atomic<T>* a, memory_order order = memory_order::relaxed) -{ - return __atomic_fetch_sub(&a->m_value, 1, static_cast<int>(order)); -} - -} // namespace asl - 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<is_floating_point T> constexpr T infinity() { return __builtin_inf(); } + +template<is_floating_point T> constexpr T nan() { return static_cast<T>(__builtin_nanf("")); } + +template<is_floating_point T> constexpr bool is_infinity(T f) { return __builtin_isinf(f); } + +template<is_floating_point T> 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<float>())); + ASL_TEST_EXPECT(asl::is_infinity(-asl::infinity<double>())); +} + +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<float>())); + ASL_TEST_EXPECT(asl::is_nan(asl::nan<double>())); +} + 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<typename... Args, typename C> +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<typename... Args, typename C> +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<typename... Args, typename C> +constexpr auto invoke(is_object auto C::* m, auto&& self, Args&&...) + requires ( + sizeof...(Args) == 0 && + requires { self.*m; } + ) +{ + return ASL_FWD(self).*m; +} + +template<typename... Args, typename C> +constexpr auto invoke(is_object auto C::* m, auto* self, Args&&...) + requires ( + sizeof...(Args) == 0 && + requires { self->*m; } + ) +{ + return self->*m; +} + +template<typename... Args> +constexpr auto invoke(auto&& f, Args&&... args) + requires requires { + f(ASL_FWD(args)...); + } +{ + return ASL_FWD(f)(ASL_FWD(args)...); +} + +template<typename F> struct _result_of_helper; + +template<typename R, typename... Args> +struct _result_of_helper<R(Args...)> +{ + using type = decltype(invoke(declval<R>(), declval<Args>()...)); +}; + +template<typename F> using result_of_t = _result_of_helper<F>::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<asl::result_of_t<Functor()>, int64_t>); +static_assert(asl::same_as<asl::result_of_t<Functor(int)>, int>); +static_assert(asl::same_as<asl::result_of_t<decltype(static_cast<float(*)(float)>(some_func1))(float)>, float>); +static_assert(asl::same_as<asl::result_of_t<decltype(&HasFunction::do_something)(HasFunction, int, float)>, void>); +static_assert(asl::same_as<asl::result_of_t<decltype(&HasMember::member)(HasMember)>, 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<int(*)(int)>(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<int(*)(int)>(&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<typename T> struct id { using type = T; }; + +template<typename... Args> static constexpr isize_t types_count = sizeof...(Args); + +template<typename T, T kValue> struct integral_constant { static constexpr T value = kValue; }; +template<bool B> using bool_constant = integral_constant<bool, B>; + +using true_type = bool_constant<true>; +using false_type = bool_constant<false>; + +template<bool kSelect, typename U, typename V> struct _select_helper { using type = V; }; +template<typename U, typename V> struct _select_helper<true, U, V> { using type = U; }; + +template<bool kSelect, typename U, typename V> using select_t = _select_helper<kSelect, U, V>::type; + +template<typename U, typename V> struct _same_as_helper : false_type {}; +template<typename T> struct _same_as_helper<T, T> : true_type {}; + +template<typename U, typename V> concept same_as = _same_as_helper<U, V>::value && _same_as_helper<V, U>::value; + +template<typename T> auto _as_lref_helper(int) -> id<T&>; +template<typename T> auto _as_lref_helper(...) -> id<T>; + +template<typename T> auto _as_rref_helper(int) -> id<T&&>; +template<typename T> auto _as_rref_helper(...) -> id<T>; + +template<typename T> using as_lref_t = decltype(_as_lref_helper<T>(0))::type; +template<typename T> using as_rref_t = decltype(_as_rref_helper<T>(0))::type; + +template<typename T> consteval as_rref_t<T> declval() {} + +template<typename T> struct _un_ref_t { using type = T; }; +template<typename T> struct _un_ref_t<T&> { using type = T; }; +template<typename T> struct _un_ref_t<T&&> { using type = T; }; + +template<typename T> using un_ref_t = _un_ref_t<T>::type; + +template<typename T, typename... Args> concept constructible_from = __is_constructible(T, Args...); + +template<typename T> concept default_constructible = constructible_from<T>; +template<typename T> concept copy_constructible = constructible_from<T, as_lref_t<const T>>; +template<typename T> concept move_constructible = constructible_from<T, as_rref_t<T>>; + +template<typename T, typename... Args> concept trivially_constructible_from = __is_trivially_constructible(T, Args...); + +template<typename T> concept trivially_default_constructible = trivially_constructible_from<T>; +template<typename T> concept trivially_copy_constructible = trivially_constructible_from<T, as_lref_t<const T>>; +template<typename T> concept trivially_move_constructible = trivially_constructible_from<T, as_rref_t<T>>; + +template<typename T, typename... Args> concept assignable_from = __is_assignable(T, Args...); + +template<typename T> concept copy_assignable = assignable_from<as_lref_t<T>, as_lref_t<const T>>; +template<typename T> concept move_assignable = assignable_from<as_lref_t<T>, as_rref_t<T>>; + +template<typename T, typename... Args> concept trivially_assignable_from = __is_trivially_assignable(T, Args...); + +template<typename T> concept trivially_copy_assignable = trivially_assignable_from<as_lref_t<T>, as_lref_t<const T>>; +template<typename T> concept trivially_move_assignable = trivially_assignable_from<as_lref_t<T>, as_rref_t<T>>; + +template<typename T> concept trivially_destructible = __is_trivially_destructible(T); + +template<typename T> concept copyable = copy_constructible<T> && copy_assignable<T>; +template<typename T> concept moveable = move_constructible<T> && move_assignable<T>; + +template<typename To, typename From> +concept convertible_from = __is_convertible(From, To); + +template<typename Derived, class Base> +concept derived_from = __is_class(Derived) && __is_class(Base) && convertible_from<const volatile Base*, const volatile Derived*>; + +using nullptr_t = decltype(nullptr); + +template<typename T> struct _un_const_helper { using type = T; }; +template<typename T> struct _un_const_helper<const T> { using type = T; }; + +template<typename T> using un_const_t = _un_const_helper<T>::type; + +template<typename T> struct _is_const_helper : false_type {}; +template<typename T> struct _is_const_helper<const T> : true_type {}; + +template<typename T> concept is_const = _is_const_helper<T>::value; + +template<typename T> struct _un_volatile_helper { using type = T; }; +template<typename T> struct _un_volatile_helper<volatile T> { using type = T; }; + +template<typename T> using un_volatile_t = _un_volatile_helper<T>::type; + +template<typename T> using un_cv_t = un_volatile_t<un_const_t<T>>; + +template<typename T> using un_cvref_t = un_ref_t<un_cv_t<T>>; + +template<typename T> concept is_void = same_as<void, un_cv_t<T>>; + +template<typename T> struct _is_ref_helper { static constexpr bool l = false; static constexpr bool r = false; }; +template<typename T> struct _is_ref_helper<T&> { static constexpr bool l = true; static constexpr bool r = false; }; +template<typename T> struct _is_ref_helper<T&&> { static constexpr bool l = false; static constexpr bool r = true; }; + +template<typename T> concept is_ref = _is_ref_helper<T>::l || _is_ref_helper<T>::r; +template<typename T> concept is_rref = _is_ref_helper<T>::r; +template<typename T> concept is_lref = _is_ref_helper<T>::l; + +template<typename T> struct _is_ptr_helper : false_type {}; +template<typename T> struct _is_ptr_helper<T*> : true_type {}; + +template<typename T> concept is_ptr = _is_ptr_helper<un_cv_t<T>>::value; + +template<typename T> struct _tame_helper { using type = T; }; + +#define TAME_HELPER_IMPL(TRAILING) \ + template<typename R, typename... Args> \ + struct _tame_helper<R(Args...) TRAILING> { 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<typename T> using tame_t = _tame_helper<T>::type; + +template<typename T> struct _is_func_helper : false_type {}; +template<typename R, typename... Args> struct _is_func_helper<R(Args...)> : true_type {}; + +template<typename T> concept is_func = _is_func_helper<tame_t<T>>::value; + +template<typename T> concept is_object = !is_void<T> && !is_ref<T> && !is_func<T>; + +template<typename T> struct _is_array_helper : false_type {}; +template<typename T> struct _is_array_helper<T[]> : true_type {}; +template<typename T, int N> struct _is_array_helper<T[N]> : true_type {}; + +template<typename T> concept is_array = _is_array_helper<T>::value; + +template<typename T> struct _is_floating_point_helper : false_type {}; +template<> struct _is_floating_point_helper<float> : true_type {}; +template<> struct _is_floating_point_helper<double> : true_type {}; + +template<typename T> concept is_floating_point = _is_floating_point_helper<un_cv_t<T>>::value; + +template<typename T> struct _is_integer_helper : false_type {}; +template<> struct _is_integer_helper<int8_t> : true_type {}; +template<> struct _is_integer_helper<int16_t> : true_type {}; +template<> struct _is_integer_helper<int32_t> : true_type {}; +template<> struct _is_integer_helper<int64_t> : true_type {}; +template<> struct _is_integer_helper<uint8_t> : true_type {}; +template<> struct _is_integer_helper<uint16_t> : true_type {}; +template<> struct _is_integer_helper<uint32_t> : true_type {}; +template<> struct _is_integer_helper<uint64_t> : true_type {}; + +template<typename T> concept is_integer = _is_integer_helper<un_cv_t<T>>::value; + +template<typename T> concept is_enum = __is_enum(T); + +template<typename T> struct is_uniquely_represented : false_type {}; +template<is_integer T> struct is_uniquely_represented<T> : true_type {}; +template<is_enum T> struct is_uniquely_represented<T> : true_type {}; +template<> struct is_uniquely_represented<uint128_t> : true_type {}; +template<> struct is_uniquely_represented<byte> : true_type {}; + +template<typename T> concept uniquely_represented = is_uniquely_represented<un_cv_t<T>>::value; + +template<typename T, typename U> +concept equality_comparable_with = requires (const un_cvref_t<T>& a, const un_cvref_t<U>& b) +{ + { a == b } -> same_as<bool>; + { b == a } -> same_as<bool>; + { a != b } -> same_as<bool>; + { b != a } -> same_as<bool>; +}; + +template<typename T> concept equality_comparable = equality_comparable_with<T, T>; + +struct niche_t {}; + +template<typename T> +concept has_niche = constructible_from<T, niche_t> && equality_comparable_with<T, niche_t>; + +template<typename T> +concept is_niche = same_as<un_cvref_t<T>, niche_t>; + +template<typename T, typename U> +concept _derefs_with_indirection_as = requires(T& t) +{ + *t; + requires convertible_from<U&, decltype(*t)>; +}; + +template<typename T, typename U> +concept _derefs_reference_as = is_ref<T> && convertible_from<U&, T>; + +template<typename T, typename U> +concept _derefs_value_as = !is_ref<T> && convertible_from<U&, T&>; + +template<typename U, _derefs_with_indirection_as<U> T> +constexpr U& deref(T&& t) { return static_cast<U&>(*t); } + +template<typename U, _derefs_reference_as<U> T> +constexpr U& deref(T&& t) { return static_cast<U&>(t); } + +template<typename U, _derefs_value_as<U> T> +constexpr U& deref(T&& t) { return static_cast<U&>(t); } + +template<typename T, typename U> +concept derefs_as = _derefs_with_indirection_as<T, U> || _derefs_reference_as<T, U> || _derefs_value_as<T, U>; + +} // 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<long, short>); +static_assert(asl::same_as<int, int>); + +static_assert(asl::same_as<asl::select_t<false, int, float>, float>); +static_assert(asl::same_as<asl::select_t<true, int, float>, int>); + +static_assert(asl::default_constructible<int>); +static_assert(asl::default_constructible<TrivialType>); +static_assert(asl::default_constructible<TrivialTypeDefaultValue>); + +static_assert(asl::trivially_default_constructible<int>); +static_assert(asl::trivially_default_constructible<TrivialType>); +static_assert(!asl::trivially_default_constructible<TrivialTypeDefaultValue>); + +static_assert(asl::copy_constructible<int>); +static_assert(asl::copy_constructible<TrivialType>); +static_assert(asl::copy_constructible<Copyable>); +static_assert(!asl::copy_constructible<MoveableOnly>); +static_assert(!asl::copy_constructible<Pinned>); + +static_assert(asl::trivially_copy_constructible<int>); +static_assert(asl::trivially_copy_constructible<TrivialType>); +static_assert(asl::trivially_copy_constructible<TrivialTypeDefaultValue>); +static_assert(!asl::trivially_copy_constructible<WithDestructor>); +static_assert(!asl::trivially_copy_constructible<Copyable>); +static_assert(!asl::trivially_copy_constructible<MoveableOnly>); +static_assert(!asl::trivially_copy_constructible<Pinned>); + +static_assert(asl::move_constructible<int>); +static_assert(asl::move_constructible<TrivialType>); +static_assert(asl::move_constructible<Copyable>); +static_assert(asl::move_constructible<MoveableOnly>); +static_assert(!asl::move_constructible<Pinned>); + +static_assert(asl::trivially_move_constructible<int>); +static_assert(asl::trivially_move_constructible<TrivialType>); +static_assert(asl::trivially_move_constructible<TrivialTypeDefaultValue>); +static_assert(!asl::trivially_move_constructible<WithDestructor>); +static_assert(!asl::trivially_move_constructible<Copyable>); +static_assert(!asl::trivially_move_constructible<MoveableOnly>); +static_assert(!asl::trivially_move_constructible<Pinned>); + +static_assert(asl::copy_assignable<int>); +static_assert(asl::copy_assignable<TrivialType>); +static_assert(asl::copy_assignable<Copyable>); +static_assert(!asl::copy_assignable<MoveableOnly>); +static_assert(!asl::copy_assignable<Pinned>); + +static_assert(asl::trivially_copy_assignable<int>); +static_assert(asl::trivially_copy_assignable<TrivialType>); +static_assert(asl::trivially_copy_assignable<TrivialTypeDefaultValue>); +static_assert(asl::trivially_copy_assignable<WithDestructor>); +static_assert(!asl::trivially_copy_assignable<Copyable>); +static_assert(!asl::trivially_copy_assignable<MoveableOnly>); +static_assert(!asl::trivially_copy_assignable<Pinned>); + +static_assert(asl::copyable<int>); +static_assert(asl::copyable<TrivialType>); +static_assert(asl::copyable<Copyable>); +static_assert(!asl::copyable<MoveableOnly>); +static_assert(!asl::copyable<Pinned>); + +static_assert(asl::moveable<int>); +static_assert(asl::moveable<TrivialType>); +static_assert(asl::moveable<Copyable>); +static_assert(asl::moveable<MoveableOnly>); +static_assert(!asl::moveable<Pinned>); + +static_assert(asl::move_assignable<int>); +static_assert(asl::move_assignable<TrivialType>); +static_assert(asl::move_assignable<Copyable>); +static_assert(asl::move_assignable<MoveableOnly>); +static_assert(!asl::move_assignable<Pinned>); + +static_assert(asl::trivially_move_assignable<int>); +static_assert(asl::trivially_move_assignable<TrivialType>); +static_assert(asl::trivially_move_assignable<TrivialTypeDefaultValue>); +static_assert(asl::trivially_move_assignable<WithDestructor>); +static_assert(!asl::trivially_move_assignable<Copyable>); +static_assert(!asl::trivially_move_assignable<MoveableOnly>); +static_assert(!asl::trivially_move_assignable<Pinned>); + +static_assert(asl::trivially_destructible<int>); +static_assert(asl::trivially_destructible<TrivialType>); +static_assert(asl::trivially_destructible<TrivialTypeDefaultValue>); +static_assert(!asl::trivially_destructible<WithDestructor>); +static_assert(asl::trivially_destructible<Copyable>); +static_assert(asl::trivially_destructible<MoveableOnly>); +static_assert(asl::trivially_destructible<Pinned>); + +static_assert(asl::same_as<int, asl::un_const_t<int>>); +static_assert(asl::same_as<int, asl::un_const_t<const int>>); +static_assert(asl::same_as<const int&, asl::un_const_t<const int&>>); + +static_assert(asl::same_as<int, asl::un_volatile_t<int>>); +static_assert(asl::same_as<int, asl::un_volatile_t<volatile int>>); +static_assert(asl::same_as<volatile int&, asl::un_volatile_t<volatile int&>>); + +static_assert(asl::same_as<int, asl::un_cv_t<int>>); +static_assert(asl::same_as<int, asl::un_cv_t<const int>>); +static_assert(asl::same_as<int, asl::un_cv_t<const volatile int>>); +static_assert(asl::same_as<int, asl::un_cv_t<volatile int>>); + +static_assert(asl::is_void<void>); +static_assert(asl::is_void<const void>); +static_assert(asl::is_void<const volatile void>); +static_assert(asl::is_void<volatile void>); +static_assert(!asl::is_void<int>); +static_assert(!asl::is_void<Struct>); +static_assert(!asl::is_void<int&>); +static_assert(!asl::is_void<int&&>); +static_assert(!asl::is_void<void()>); +static_assert(!asl::is_void<void() const &&>); + +static_assert(asl::is_ref<int&>); +static_assert(asl::is_ref<const int&>); +static_assert(asl::is_ref<const volatile int&>); +static_assert(asl::is_ref<int&&>); +static_assert(!asl::is_ref<int>); +static_assert(!asl::is_ref<void>); +static_assert(!asl::is_ref<void()>); +static_assert(!asl::is_ref<void() const &&>); + +static_assert(asl::is_ptr<int*>); +static_assert(asl::is_ptr<const int* const>); +static_assert(asl::is_ptr<const volatile int*>); +static_assert(!asl::is_ptr<int>); +static_assert(!asl::is_ptr<void>); +static_assert(!asl::is_ptr<void()>); +static_assert(!asl::is_ptr<void() const &&>); + +static_assert(asl::same_as<int, asl::tame_t<int>>); +static_assert(asl::same_as<int(), asl::tame_t<int()>>); +static_assert(asl::same_as<int(float), asl::tame_t<int(float)>>); +static_assert(asl::same_as<int(float), asl::tame_t<int(float) &>>); +static_assert(asl::same_as<int(float), asl::tame_t<int(float) const &&>>); +static_assert(asl::same_as<int(float), asl::tame_t<int(float) volatile noexcept>>); +static_assert(asl::same_as<int(float), asl::tame_t<int(float) && noexcept>>); +static_assert(asl::same_as<int(float), asl::tame_t<int(float) const>>); + +static_assert(asl::is_func<void()>); +static_assert(asl::is_func<void(int)>); +static_assert(asl::is_func<void(int, float)>); +static_assert(asl::is_func<void() &>); +static_assert(asl::is_func<void() const &&>); +static_assert(asl::is_func<void() volatile noexcept>); +static_assert(!asl::is_func<void(*)()>); +static_assert(!asl::is_func<int>); +static_assert(!asl::is_func<int&>); +static_assert(!asl::is_func<void>); + +static_assert(asl::is_object<Struct>); +static_assert(asl::is_object<int>); +static_assert(asl::is_object<int*>); +static_assert(asl::is_object<int Struct::*>); +static_assert(asl::is_object<int (Struct::*)(float)>); +static_assert(asl::is_object<int[]>); +static_assert(asl::is_object<int[45]>); +static_assert(asl::is_object<Enum>); +static_assert(!asl::is_object<int&>); +static_assert(!asl::is_object<void>); +static_assert(!asl::is_object<void(int)>); +static_assert(!asl::is_object<int(float) const && noexcept>); + +static_assert(!asl::is_array<Struct>); +static_assert(!asl::is_array<int>); +static_assert(!asl::is_array<int*>); +static_assert(!asl::is_array<int Struct::*>); +static_assert(!asl::is_array<int (Struct::*)(float)>); +static_assert(asl::is_array<int[]>); +static_assert(asl::is_array<int[45]>); +static_assert(!asl::is_array<Enum>); +static_assert(!asl::is_array<int&>); +static_assert(!asl::is_array<void>); +static_assert(!asl::is_array<void(int)>); +static_assert(!asl::is_array<int(float) const && noexcept>); + +static_assert(asl::same_as<int, asl::un_ref_t<int>>); +static_assert(asl::same_as<int, asl::un_ref_t<int&>>); +static_assert(asl::same_as<int, asl::un_ref_t<int&&>>); +static_assert(asl::same_as<int() &, asl::un_ref_t<int() &>>); + +static_assert(asl::types_count<int, float> == 2); +static_assert(asl::types_count<int, int> == 2); +static_assert(asl::types_count<int> == 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<class T> E(T&&) {} }; // NOLINT + +static_assert(asl::convertible_from<Base*, Derived*>); +static_assert(!asl::convertible_from<Derived*, Base*>); +static_assert(asl::convertible_from<C, D>); +static_assert(!asl::convertible_from<C*, Derived*>); +static_assert(asl::convertible_from<E, Base>); + +static_assert(!asl::convertible_from<int16_t(&)[], int32_t(&)[]>); +static_assert(asl::convertible_from<const int16_t(&)[], int16_t(&)[]>); +static_assert(asl::convertible_from<const int16_t(&)[], const int16_t(&)[]>); +static_assert(asl::convertible_from<int16_t(&)[], int16_t(&)[]>); +static_assert(!asl::convertible_from<int32_t(&)[], int16_t(&)[]>); +static_assert(!asl::convertible_from<int16_t(&)[], const int16_t(&)[]>); +static_assert(!asl::convertible_from<C(&)[], D(&)[]>); + +static_assert(asl::derived_from<Derived, Base>); +static_assert(!asl::derived_from<Base, Derived>); +static_assert(!asl::derived_from<D, C>); +static_assert(!asl::derived_from<C, D>); +static_assert(!asl::derived_from<uint8_t, uint16_t>); +static_assert(!asl::derived_from<uint16_t, uint8_t>); +static_assert(!asl::derived_from<int, int>); + +static_assert(!asl::is_const<int>); +static_assert(asl::is_const<const int>); +static_assert(!asl::is_const<const int*>); +static_assert(asl::is_const<int* const>); + +static_assert(asl::is_floating_point<float>); +static_assert(asl::is_floating_point<const float>); +static_assert(asl::is_floating_point<volatile double>); +static_assert(!asl::is_floating_point<const float&>); +static_assert(!asl::is_floating_point<int>); +static_assert(!asl::is_floating_point<C>); + +static_assert(asl::uniquely_represented<int>); +static_assert(asl::uniquely_represented<uint128_t>); +static_assert(!asl::uniquely_represented<bool>); + +enum Enum1 {}; +enum class Enum2 {}; + +static_assert(asl::uniquely_represented<Enum1>); +static_assert(asl::uniquely_represented<Enum2>); + +static_assert(!asl::is_enum<int>); +static_assert(asl::is_enum<Enum1>); +static_assert(asl::is_enum<Enum2>); + +static_assert(asl::derefs_as<int, int>); +static_assert(asl::derefs_as<int*, int>); +static_assert(asl::derefs_as<int&, int>); +static_assert(asl::derefs_as<asl::box<int>, int>); + +static_assert(asl::derefs_as<Derived, Base>); +static_assert(asl::derefs_as<Derived*, Base>); +static_assert(asl::derefs_as<Derived&, Base>); +static_assert(asl::derefs_as<asl::box<Derived>, 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<int>(5); + + wants_int(asl::deref<int>(5)); + wants_int(asl::deref<int>(a)); + wants_int(asl::deref<int>(&a)); + wants_int(asl::deref<int>(b)); + + Derived c{}; + auto d = asl::make_box<Derived>(); + + wants_base(asl::deref<Base>(Derived{})); + wants_base(asl::deref<Base>(c)); + wants_base(asl::deref<Base>(&c)); + wants_base(asl::deref<Base>(d)); + + wants_base_ptr(&asl::deref<Base>(Derived{})); + wants_base_ptr(&asl::deref<Base>(c)); + wants_base_ptr(&asl::deref<Base>(&c)); + wants_base_ptr(&asl::deref<Base>(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<decltype(__VA_ARGS__)>&&>(__VA_ARGS__)) + +#define ASL_FWD(expr_) (static_cast<decltype(expr_)&&>(expr_)) + +namespace asl +{ + +struct in_place_t {}; +static constexpr in_place_t in_place{}; + +template<moveable T> +constexpr void swap(T& a, T& b) +{ + T tmp{ASL_MOVE(a)}; + a = ASL_MOVE(b); + b = ASL_MOVE(tmp); +} + +template<typename T, typename U> +T exchange(T& obj, U&& new_value) +{ + T old_value = ASL_MOVE(obj); + obj = ASL_FWD(new_value); + return old_value; +} + +template<trivially_copy_constructible U, trivially_copy_constructible T> +constexpr U bit_cast(T value) requires (sizeof(T) == sizeof(U)) +{ + return __builtin_bit_cast(U, value); +} + +template<typename T> +constexpr T min(T a, T b) +{ + return (a <= b) ? a : b; +} + +template<typename T> +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" diff --git a/asl/box.hpp b/asl/box.hpp deleted file mode 100644 index 9d3c7f0..0000000 --- a/asl/box.hpp +++ /dev/null @@ -1,134 +0,0 @@ -#pragma once - -#include "asl/allocator.hpp" -#include "asl/assert.hpp" -#include "asl/annotations.hpp" -#include "asl/memory.hpp" -#include "asl/utility.hpp" -#include "asl/hash.hpp" - -namespace asl -{ - -template<is_object T, allocator Allocator = DefaultAllocator> -class box -{ - T* m_ptr; - ASL_NO_UNIQUE_ADDRESS Allocator m_alloc; - -public: - explicit constexpr box(niche_t) - requires default_constructible<Allocator> - : m_ptr{nullptr} - , m_alloc{} - {} - - constexpr box(T* ptr, Allocator alloc) - : m_ptr{ptr} - , m_alloc{ASL_MOVE(alloc)} - { - ASL_ASSERT(m_ptr != nullptr); - } - - constexpr box(box&& other) - : m_ptr{exchange(other.m_ptr, nullptr)} - , m_alloc{ASL_MOVE(other.m_alloc)} - {} - - template<is_object U> - requires convertible_from<T*, U*> - constexpr box(box<U, Allocator>&& other) // NOLINT(*-explicit-conversions) - : m_ptr{exchange(other.m_ptr, nullptr)} - , m_alloc{ASL_MOVE(other.m_alloc)} - {} - - constexpr box& operator=(box&& other) - { - if (this == &other) { return *this; } - - if (m_ptr != nullptr) { reset(); } - - m_ptr = exchange(other.m_ptr, nullptr); - m_alloc = ASL_MOVE(other.m_alloc); - - return *this; - } - - box(const box&) = delete; - box& operator=(const box&) = delete; - - constexpr ~box() - { - reset(); - } - - constexpr void reset() - { - if (m_ptr != nullptr) - { - destroy(m_ptr); - m_alloc.dealloc(m_ptr, layout::of<T>()); - m_ptr = nullptr; - } - } - - constexpr T* get() const { return m_ptr; } - - constexpr T& operator*() const - { - ASL_ASSERT(m_ptr != nullptr); - return *m_ptr; - } - - constexpr T* operator->() const - { - ASL_ASSERT(m_ptr != nullptr); - return m_ptr; - } - - constexpr bool operator==(niche_t) const - { - return m_ptr == nullptr; - } - - template<typename H> - requires hashable<T> - friend H AslHashValue(H h, const box& b) - { - return H::combine(ASL_MOVE(h), *b); - } - - template<is_object U, allocator A> - friend constexpr U* leak(box<U, A>&&); - - template<is_object U, allocator A> - friend class box; -}; - -template<is_object T, allocator Allocator = DefaultAllocator, typename... Args> -constexpr box<T, Allocator> make_box_in(Allocator allocator, Args&&... args) - requires constructible_from<T, Args&&...> -{ - void* raw_ptr = allocator.alloc(layout::of<T>()); - auto* ptr = construct_at<T>(raw_ptr, ASL_FWD(args)...); - return box(ptr, ASL_MOVE(allocator)); -} - -template<is_object T, allocator Allocator = DefaultAllocator, typename... Args> -constexpr box<T, Allocator> make_box(Args&&... args) - requires default_constructible<Allocator> && constructible_from<T, Args&&...> -{ - Allocator allocator{}; - void* raw_ptr = allocator.alloc(layout::of<T>()); - auto* ptr = construct_at<T>(raw_ptr, ASL_FWD(args)...); - return box<T>(ptr, ASL_MOVE(allocator)); -} - -template<is_object T, allocator A> -constexpr T* leak(box<T, A>&& b) -{ - return exchange(b.m_ptr, nullptr); -} - -} // namespace asl - diff --git a/asl/buffer.hpp b/asl/buffer.hpp deleted file mode 100644 index 5cf9964..0000000 --- a/asl/buffer.hpp +++ /dev/null @@ -1,459 +0,0 @@ -#pragma once - -#include "asl/meta.hpp" -#include "asl/allocator.hpp" -#include "asl/annotations.hpp" -#include "asl/memory.hpp" -#include "asl/assert.hpp" -#include "asl/span.hpp" -#include "asl/hash.hpp" - -namespace asl -{ - -template<is_object T, allocator Allocator = DefaultAllocator> -class buffer -{ - T* m_data{}; - isize_t m_capacity{}; - - static constexpr size_t kOnHeapMask = 0x8000'0000'0000'0000ULL; - - // bit 63 : 1 = on heap, 0 = inline - // bits [62:56] : size when inline - // bits [62:0] : size when on heap - size_t m_size_encoded_{}; - - ASL_NO_UNIQUE_ADDRESS Allocator m_allocator; - - static constexpr isize_t kInlineRegionSize = size_of<T*> + size_of<isize_t> + size_of<size_t>; - -public: - static constexpr isize_t kInlineCapacity = []() { - // 1 byte is used for size inline in m_size_encoded. - // This is enough because we have at most 24 bytes available, - // so 23 chars of capacity. - const isize_t available_size = kInlineRegionSize - 1; - return available_size / size_of<T>; - }(); - -private: - static_assert(align_of<T> <= align_of<T*>); - static_assert(align_of<T*> == align_of<isize_t>); - static_assert(align_of<T*> == align_of<size_t>); - - constexpr size_t load_size_encoded() const - { - size_t s{}; - asl::memcpy(&s, &m_size_encoded_, sizeof(size_t)); - return s; - } - - constexpr void store_size_encoded(size_t encoded) - { - asl::memcpy(&m_size_encoded_, &encoded, sizeof(size_t)); - } - - static constexpr bool is_on_heap(size_t size_encoded) - { - return (size_encoded & kOnHeapMask) != 0; - } - - static constexpr size_t encode_size_heap(isize_t size) - { - return static_cast<size_t>(size) | kOnHeapMask; - } - - static constexpr isize_t decode_size(size_t size_encoded) - { - if constexpr (kInlineCapacity == 0) - { - return is_on_heap(size_encoded) - ? static_cast<isize_t>(size_encoded & (~kOnHeapMask)) - : 0; - } - else - { - return is_on_heap(size_encoded) - ? static_cast<isize_t>(size_encoded & (~kOnHeapMask)) - : static_cast<isize_t>(size_encoded >> 56); - } - } - - constexpr bool is_on_heap() const - { - return is_on_heap(load_size_encoded()); - } - - constexpr T* push_uninit() - { - isize_t sz = size(); - resize_uninit_inner(sz + 1); - return data() + sz; - } - - constexpr void resize_uninit_inner(isize_t new_size) - { - isize_t old_size = size(); - if (!trivially_destructible<T> && new_size < old_size) - { - destroy_n(data() + new_size, old_size - new_size); - } - reserve_capacity(new_size); - set_size(new_size); - } - - constexpr void set_size_inline(isize_t new_size) - { - ASL_ASSERT(new_size >= 0 && new_size <= kInlineCapacity); - size_t size_encoded = (load_size_encoded() & size_t{0x00ff'ffff'ffff'ffff}) | (bit_cast<size_t>(new_size) << 56); - store_size_encoded(size_encoded); - } - - constexpr void set_size(isize_t new_size) - { - ASL_ASSERT(new_size >= 0 && new_size <= capacity()); - if (is_on_heap()) - { - store_size_encoded(encode_size_heap(new_size)); - } - else - { - set_size_inline(new_size); - } - } - - // NOLINTNEXTLINE(*-rvalue-reference-param-not-moved) - void move_from_other(buffer&& other, bool assign) - { - if (other.is_on_heap()) - { - destroy(); - m_data = other.m_data; - m_capacity = other.m_capacity; - store_size_encoded(other.load_size_encoded()); - } - else if (trivially_move_constructible<T>) - { - destroy(); - asl::memcpy(this, &other, kInlineRegionSize); - } - else if (!assign || m_allocator == other.m_allocator) - { - isize_t other_n = other.size(); - isize_t this_n = size(); - resize_uninit_inner(other_n); - if (other_n <= this_n) - { - relocate_assign_n(data(), other.data(), other_n); - } - else - { - relocate_assign_n(data(), other.data(), this_n); - relocate_uninit_n