Fix line endings
This commit is contained in:
88
.bazelrc
88
.bazelrc
@ -1,44 +1,44 @@
|
|||||||
startup --windows_enable_symlinks
|
startup --windows_enable_symlinks
|
||||||
build:windows --enable_runfiles=true
|
build:windows --enable_runfiles=true
|
||||||
|
|
||||||
build --build_python_zip=false
|
build --build_python_zip=false
|
||||||
|
|
||||||
build:windows --extra_execution_platforms=//:x64_windows-clang-cl
|
build:windows --extra_execution_platforms=//:x64_windows-clang-cl
|
||||||
# @Todo(bazel) We should be able to use @local_config_cc...
|
# @Todo(bazel) We should be able to use @local_config_cc...
|
||||||
build:windows --extra_toolchains=@@rules_cc++cc_configure_extension+local_config_cc//:cc-toolchain-x64_windows-clang-cl
|
build:windows --extra_toolchains=@@rules_cc++cc_configure_extension+local_config_cc//:cc-toolchain-x64_windows-clang-cl
|
||||||
|
|
||||||
build:linux --repo_env=CC=clang
|
build:linux --repo_env=CC=clang
|
||||||
|
|
||||||
build:windows --cxxopt=-Xclang=-std=c++20
|
build:windows --cxxopt=-Xclang=-std=c++20
|
||||||
build:linux --cxxopt=-std=c++20
|
build:linux --cxxopt=-std=c++20
|
||||||
|
|
||||||
build --cxxopt=-Wall
|
build --cxxopt=-Wall
|
||||||
build --cxxopt=-Wno-c++98-compat
|
build --cxxopt=-Wno-c++98-compat
|
||||||
build --cxxopt=-Wno-c++98-compat-pedantic
|
build --cxxopt=-Wno-c++98-compat-pedantic
|
||||||
build --cxxopt=-Wno-pre-c++17-compat
|
build --cxxopt=-Wno-pre-c++17-compat
|
||||||
build --cxxopt=-Wno-c++20-compat
|
build --cxxopt=-Wno-c++20-compat
|
||||||
build --cxxopt=-Wno-unused-macros
|
build --cxxopt=-Wno-unused-macros
|
||||||
build --cxxopt=-Wno-documentation-unknown-command
|
build --cxxopt=-Wno-documentation-unknown-command
|
||||||
build --cxxopt=-Wno-extra-semi-stmt
|
build --cxxopt=-Wno-extra-semi-stmt
|
||||||
build --cxxopt=-Wno-extra-semi
|
build --cxxopt=-Wno-extra-semi
|
||||||
build --cxxopt=-Wno-global-constructors
|
build --cxxopt=-Wno-global-constructors
|
||||||
build --cxxopt=-Wno-unsafe-buffer-usage
|
build --cxxopt=-Wno-unsafe-buffer-usage
|
||||||
build --cxxopt=-Wno-covered-switch-default
|
build --cxxopt=-Wno-covered-switch-default
|
||||||
|
|
||||||
build:windows_san --config=windows
|
build:windows_san --config=windows
|
||||||
build:windows_san --copt=-fno-sanitize-ignorelist
|
build:windows_san --copt=-fno-sanitize-ignorelist
|
||||||
build:windows_san --copt=-fsanitize=address
|
build:windows_san --copt=-fsanitize=address
|
||||||
build:windows_san --copt=-fsanitize=undefined
|
build:windows_san --copt=-fsanitize=undefined
|
||||||
build:windows_san --copt=-fno-sanitize-recover=all
|
build:windows_san --copt=-fno-sanitize-recover=all
|
||||||
build:windows_san --linkopt=clang_rt.asan-x86_64.lib
|
build:windows_san --linkopt=clang_rt.asan-x86_64.lib
|
||||||
build:windows_san --copt=/MT
|
build:windows_san --copt=/MT
|
||||||
|
|
||||||
build:linux_san --config=linux
|
build:linux_san --config=linux
|
||||||
build:linux_san --copt=-fsanitize=address
|
build:linux_san --copt=-fsanitize=address
|
||||||
build:linux_san --linkopt=-fsanitize=address
|
build:linux_san --linkopt=-fsanitize=address
|
||||||
build:linux_san --copt=-fsanitize=undefined
|
build:linux_san --copt=-fsanitize=undefined
|
||||||
build:linux_san --copt=-fno-sanitize-recover=all
|
build:linux_san --copt=-fno-sanitize-recover=all
|
||||||
build:linux_san --linkopt=-fsanitize=undefined
|
build:linux_san --linkopt=-fsanitize=undefined
|
||||||
build:linux_san --linkopt=-fsanitize-link-c++-runtime
|
build:linux_san --linkopt=-fsanitize-link-c++-runtime
|
||||||
|
|
||||||
test --test_output=errors
|
test --test_output=errors
|
||||||
|
68
.clang-tidy
68
.clang-tidy
@ -1,34 +1,34 @@
|
|||||||
Checks:
|
Checks:
|
||||||
- "hicpp-*"
|
- "hicpp-*"
|
||||||
- "cppcoreguidelines-*"
|
- "cppcoreguidelines-*"
|
||||||
- "misc-*"
|
- "misc-*"
|
||||||
- "clang-analyzer-*"
|
- "clang-analyzer-*"
|
||||||
- "-misc-include-cleaner"
|
- "-misc-include-cleaner"
|
||||||
- "performance-*"
|
- "performance-*"
|
||||||
- "readability-*"
|
- "readability-*"
|
||||||
- "-*-named-parameter"
|
- "-*-named-parameter"
|
||||||
- "-*-avoid-do-while"
|
- "-*-avoid-do-while"
|
||||||
- "-*-magic-numbers"
|
- "-*-magic-numbers"
|
||||||
- "-*-identifier-length"
|
- "-*-identifier-length"
|
||||||
- "-*-union-access"
|
- "-*-union-access"
|
||||||
- "-*-vararg"
|
- "-*-vararg"
|
||||||
- "-*-macro-usage"
|
- "-*-macro-usage"
|
||||||
- "-*-non-private-member-variables-in-classes"
|
- "-*-non-private-member-variables-in-classes"
|
||||||
- "-*-avoid-non-const-global-variables"
|
- "-*-avoid-non-const-global-variables"
|
||||||
- "-*-missing-std-forward"
|
- "-*-missing-std-forward"
|
||||||
- "-*-owning-memory"
|
- "-*-owning-memory"
|
||||||
- "-*-no-malloc"
|
- "-*-no-malloc"
|
||||||
- "-*-avoid-c-arrays"
|
- "-*-avoid-c-arrays"
|
||||||
- "-*-use-anonymous-namespace"
|
- "-*-use-anonymous-namespace"
|
||||||
- "-*-reinterpret-cast"
|
- "-*-reinterpret-cast"
|
||||||
- "-*-noexcept-swap"
|
- "-*-noexcept-swap"
|
||||||
- "-*-noexcept-move"
|
- "-*-noexcept-move"
|
||||||
- "-*-noexcept-move-constructor"
|
- "-*-noexcept-move-constructor"
|
||||||
- "-*-noexcept-move-operations"
|
- "-*-noexcept-move-operations"
|
||||||
- "-*-bounds-array-to-pointer-decay"
|
- "-*-bounds-array-to-pointer-decay"
|
||||||
- "-*-no-array-decay"
|
- "-*-no-array-decay"
|
||||||
- "-*-signed-bitwise"
|
- "-*-signed-bitwise"
|
||||||
- "-readability-use-anyofallof"
|
- "-readability-use-anyofallof"
|
||||||
- "-readability-function-cognitive-complexity"
|
- "-readability-function-cognitive-complexity"
|
||||||
- "-readability-math-missing-parentheses"
|
- "-readability-math-missing-parentheses"
|
||||||
- "-*-rvalue-reference-param-not-moved"
|
- "-*-rvalue-reference-param-not-moved"
|
||||||
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,2 +1,4 @@
|
|||||||
bazel-*/
|
bazel-*/
|
||||||
compile_commands.json
|
compile_commands.json
|
||||||
|
.cache/
|
||||||
|
external/
|
||||||
|
36
BUILD.bazel
36
BUILD.bazel
@ -1,18 +1,18 @@
|
|||||||
load("@hedron_compile_commands//:refresh_compile_commands.bzl", "refresh_compile_commands")
|
load("@hedron_compile_commands//:refresh_compile_commands.bzl", "refresh_compile_commands")
|
||||||
|
|
||||||
refresh_compile_commands(
|
refresh_compile_commands(
|
||||||
name = "refresh_clangd",
|
name = "refresh_clangd",
|
||||||
targets = "//...",
|
targets = "//...",
|
||||||
)
|
)
|
||||||
|
|
||||||
platform(
|
platform(
|
||||||
name = "x64_windows-clang-cl",
|
name = "x64_windows-clang-cl",
|
||||||
constraint_values = [
|
constraint_values = [
|
||||||
"@platforms//cpu:x86_64",
|
"@platforms//cpu:x86_64",
|
||||||
"@platforms//os:windows",
|
"@platforms//os:windows",
|
||||||
# @Todo(bazel) Bit weird to use a private thing.
|
# @Todo(bazel) Bit weird to use a private thing.
|
||||||
# We used to use @bazel_tools//tools/cpp:clang-cl but it's deprecated
|
# We used to use @bazel_tools//tools/cpp:clang-cl but it's deprecated
|
||||||
# in favor of... this?...
|
# in favor of... this?...
|
||||||
"@rules_cc//cc/private/toolchain:clang-cl",
|
"@rules_cc//cc/private/toolchain:clang-cl",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
30
MODULE.bazel
30
MODULE.bazel
@ -1,15 +1,15 @@
|
|||||||
module(name = "asl")
|
module(name = "asl")
|
||||||
|
|
||||||
bazel_dep(name = "platforms", version = "0.0.10")
|
bazel_dep(name = "platforms", version = "0.0.10")
|
||||||
bazel_dep(name = "rules_cc", version = "0.0.17")
|
bazel_dep(name = "rules_cc", version = "0.0.17")
|
||||||
|
|
||||||
bazel_dep(name = "hedron_compile_commands", dev_dependency = True)
|
bazel_dep(name = "hedron_compile_commands", dev_dependency = True)
|
||||||
git_override(
|
git_override(
|
||||||
module_name = "hedron_compile_commands",
|
module_name = "hedron_compile_commands",
|
||||||
remote = "https://github.com/hedronvision/bazel-compile-commands-extractor.git",
|
remote = "https://github.com/hedronvision/bazel-compile-commands-extractor.git",
|
||||||
commit = "4f28899228fb3ad0126897876f147ca15026151e",
|
commit = "4f28899228fb3ad0126897876f147ca15026151e",
|
||||||
)
|
)
|
||||||
|
|
||||||
bazel_dep(name = "rules_python", version = "1.1.0", dev_dependency = True)
|
bazel_dep(name = "rules_python", version = "1.1.0", dev_dependency = True)
|
||||||
python = use_extension("@rules_python//python/extensions:python.bzl", "python")
|
python = use_extension("@rules_python//python/extensions:python.bzl", "python")
|
||||||
python.toolchain(python_version = "3.13", is_default = True)
|
python.toolchain(python_version = "3.13", is_default = True)
|
||||||
|
156
asl/BUILD.bazel
156
asl/BUILD.bazel
@ -1,78 +1,78 @@
|
|||||||
cc_library(
|
cc_library(
|
||||||
name = "asl",
|
name = "asl",
|
||||||
hdrs = [
|
hdrs = [
|
||||||
"allocator.hpp",
|
"allocator.hpp",
|
||||||
"annotations.hpp",
|
"annotations.hpp",
|
||||||
"assert.hpp",
|
"assert.hpp",
|
||||||
"atomic.hpp",
|
"atomic.hpp",
|
||||||
"box.hpp",
|
"box.hpp",
|
||||||
"buffer.hpp",
|
"buffer.hpp",
|
||||||
"config.hpp",
|
"config.hpp",
|
||||||
"float.hpp",
|
"float.hpp",
|
||||||
"format.hpp",
|
"format.hpp",
|
||||||
"functional.hpp",
|
"functional.hpp",
|
||||||
"hash.hpp",
|
"hash.hpp",
|
||||||
"hash_map.hpp",
|
"hash_map.hpp",
|
||||||
"hash_set.hpp",
|
"hash_set.hpp",
|
||||||
"integers.hpp",
|
"integers.hpp",
|
||||||
"io.hpp",
|
"io.hpp",
|
||||||
"layout.hpp",
|
"layout.hpp",
|
||||||
"maybe_uninit.hpp",
|
"maybe_uninit.hpp",
|
||||||
"memory.hpp",
|
"memory.hpp",
|
||||||
"meta.hpp",
|
"meta.hpp",
|
||||||
"option.hpp",
|
"option.hpp",
|
||||||
"print.hpp",
|
"print.hpp",
|
||||||
"span.hpp",
|
"span.hpp",
|
||||||
"status.hpp",
|
"status.hpp",
|
||||||
"status_or.hpp",
|
"status_or.hpp",
|
||||||
"string.hpp",
|
"string.hpp",
|
||||||
"string_builder.hpp",
|
"string_builder.hpp",
|
||||||
"string_view.hpp",
|
"string_view.hpp",
|
||||||
"utility.hpp",
|
"utility.hpp",
|
||||||
],
|
],
|
||||||
srcs = [
|
srcs = [
|
||||||
"allocator.cpp",
|
"allocator.cpp",
|
||||||
"assert.cpp",
|
"assert.cpp",
|
||||||
"format.cpp",
|
"format.cpp",
|
||||||
"format_float.cpp",
|
"format_float.cpp",
|
||||||
"hash_cityhash.cpp",
|
"hash_cityhash.cpp",
|
||||||
"print.cpp",
|
"print.cpp",
|
||||||
"status.cpp",
|
"status.cpp",
|
||||||
],
|
],
|
||||||
deps = [
|
deps = [
|
||||||
"//vendor/dragonbox",
|
"//vendor/dragonbox",
|
||||||
],
|
],
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
|
|
||||||
[cc_test(
|
[cc_test(
|
||||||
name = "%s_tests" % name,
|
name = "%s_tests" % name,
|
||||||
srcs = [
|
srcs = [
|
||||||
"tests/%s_tests.cpp" % name,
|
"tests/%s_tests.cpp" % name,
|
||||||
"tests/test_types.hpp",
|
"tests/test_types.hpp",
|
||||||
],
|
],
|
||||||
deps = [
|
deps = [
|
||||||
":asl",
|
":asl",
|
||||||
"//asl/testing",
|
"//asl/testing",
|
||||||
],
|
],
|
||||||
) for name in [
|
) for name in [
|
||||||
"box",
|
"box",
|
||||||
"buffer",
|
"buffer",
|
||||||
"float",
|
"float",
|
||||||
"format",
|
"format",
|
||||||
"functional",
|
"functional",
|
||||||
"hash",
|
"hash",
|
||||||
"hash_map",
|
"hash_map",
|
||||||
"hash_set",
|
"hash_set",
|
||||||
"integers",
|
"integers",
|
||||||
"maybe_uninit",
|
"maybe_uninit",
|
||||||
"meta",
|
"meta",
|
||||||
"option",
|
"option",
|
||||||
"span",
|
"span",
|
||||||
"status",
|
"status",
|
||||||
"status_or",
|
"status_or",
|
||||||
"string",
|
"string",
|
||||||
"string_builder",
|
"string_builder",
|
||||||
"string_view",
|
"string_view",
|
||||||
"utility",
|
"utility",
|
||||||
]]
|
]]
|
||||||
|
@ -1,56 +1,56 @@
|
|||||||
#include "asl/allocator.hpp"
|
#include "asl/allocator.hpp"
|
||||||
#include "asl/assert.hpp"
|
#include "asl/assert.hpp"
|
||||||
#include "asl/utility.hpp"
|
#include "asl/utility.hpp"
|
||||||
#include "asl/memory.hpp"
|
#include "asl/memory.hpp"
|
||||||
#include "asl/print.hpp"
|
#include "asl/print.hpp"
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
// @Todo zalloc
|
// @Todo zalloc
|
||||||
// @Todo Cookies
|
// @Todo Cookies
|
||||||
// @Todo Debug values
|
// @Todo Debug values
|
||||||
|
|
||||||
void* asl::GlobalHeap::alloc(const layout& layout)
|
void* asl::GlobalHeap::alloc(const layout& layout)
|
||||||
{
|
{
|
||||||
#if ASL_OS_WINDOWS
|
#if ASL_OS_WINDOWS
|
||||||
void* ptr = ::_aligned_malloc(
|
void* ptr = ::_aligned_malloc(
|
||||||
static_cast<size_t>(layout.size),
|
static_cast<size_t>(layout.size),
|
||||||
static_cast<size_t>(layout.align));
|
static_cast<size_t>(layout.align));
|
||||||
#elif ASL_OS_LINUX
|
#elif ASL_OS_LINUX
|
||||||
void* ptr = ::aligned_alloc(
|
void* ptr = ::aligned_alloc(
|
||||||
static_cast<size_t>(layout.align),
|
static_cast<size_t>(layout.align),
|
||||||
static_cast<size_t>(layout.size));
|
static_cast<size_t>(layout.size));
|
||||||
#endif
|
#endif
|
||||||
ASL_ASSERT(ptr != nullptr); // @Todo panic
|
ASL_ASSERT(ptr != nullptr); // @Todo panic
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* asl::GlobalHeap::realloc(void* old_ptr, [[maybe_unused]] const layout& old_layout, const layout& new_layout)
|
void* asl::GlobalHeap::realloc(void* old_ptr, [[maybe_unused]] const layout& old_layout, const layout& new_layout)
|
||||||
{
|
{
|
||||||
#if ASL_OS_WINDOWS
|
#if ASL_OS_WINDOWS
|
||||||
return ::_aligned_realloc(old_ptr,
|
return ::_aligned_realloc(old_ptr,
|
||||||
static_cast<size_t>(new_layout.size),
|
static_cast<size_t>(new_layout.size),
|
||||||
static_cast<size_t>(new_layout.align));
|
static_cast<size_t>(new_layout.align));
|
||||||
#elif ASL_OS_LINUX
|
#elif ASL_OS_LINUX
|
||||||
if (new_layout.align <= old_layout.align)
|
if (new_layout.align <= old_layout.align)
|
||||||
{
|
{
|
||||||
void* new_ptr = ::realloc(old_ptr, static_cast<size_t>(new_layout.size));
|
void* new_ptr = ::realloc(old_ptr, static_cast<size_t>(new_layout.size));
|
||||||
ASL_ASSERT(new_ptr != nullptr); // @Todo panic
|
ASL_ASSERT(new_ptr != nullptr); // @Todo panic
|
||||||
return new_ptr;
|
return new_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* new_ptr = alloc(new_layout);
|
void* new_ptr = alloc(new_layout);
|
||||||
asl::memcpy(new_ptr, old_ptr, asl::min(old_layout.size, new_layout.size));
|
asl::memcpy(new_ptr, old_ptr, asl::min(old_layout.size, new_layout.size));
|
||||||
dealloc(old_ptr, old_layout);
|
dealloc(old_ptr, old_layout);
|
||||||
return new_ptr;
|
return new_ptr;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void asl::GlobalHeap::dealloc(void* ptr, const layout&)
|
void asl::GlobalHeap::dealloc(void* ptr, const layout&)
|
||||||
{
|
{
|
||||||
#if ASL_OS_WINDOWS
|
#if ASL_OS_WINDOWS
|
||||||
::_aligned_free(ptr);
|
::_aligned_free(ptr);
|
||||||
#elif ASL_OS_LINUX
|
#elif ASL_OS_LINUX
|
||||||
::free(ptr);
|
::free(ptr);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -1,58 +1,58 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "asl/layout.hpp"
|
#include "asl/layout.hpp"
|
||||||
#include "asl/meta.hpp"
|
#include "asl/meta.hpp"
|
||||||
#include "asl/memory.hpp"
|
#include "asl/memory.hpp"
|
||||||
|
|
||||||
namespace asl
|
namespace asl
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept allocator = moveable<T> && equality_comparable<T> &&
|
concept allocator = moveable<T> && equality_comparable<T> &&
|
||||||
requires(T& alloc, layout layout, void* ptr)
|
requires(T& alloc, layout layout, void* ptr)
|
||||||
{
|
{
|
||||||
{ alloc.alloc(layout) } -> same_as<void*>;
|
{ alloc.alloc(layout) } -> same_as<void*>;
|
||||||
{ alloc.realloc(ptr, layout, layout) } -> same_as<void*>;
|
{ alloc.realloc(ptr, layout, layout) } -> same_as<void*>;
|
||||||
alloc.dealloc(ptr, layout);
|
alloc.dealloc(ptr, layout);
|
||||||
};
|
};
|
||||||
|
|
||||||
class GlobalHeap
|
class GlobalHeap
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void* alloc(const layout&);
|
static void* alloc(const layout&);
|
||||||
static void* realloc(void* ptr, const layout& old, const layout& new_layout);
|
static void* realloc(void* ptr, const layout& old, const layout& new_layout);
|
||||||
static void dealloc(void* ptr, const layout&);
|
static void dealloc(void* ptr, const layout&);
|
||||||
|
|
||||||
constexpr bool operator==(const GlobalHeap&) const { return true; }
|
constexpr bool operator==(const GlobalHeap&) const { return true; }
|
||||||
};
|
};
|
||||||
static_assert(allocator<GlobalHeap>);
|
static_assert(allocator<GlobalHeap>);
|
||||||
|
|
||||||
using DefaultAllocator = GlobalHeap;
|
using DefaultAllocator = GlobalHeap;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T* alloc_new(allocator auto& a, auto&&... args)
|
T* alloc_new(allocator auto& a, auto&&... args)
|
||||||
{
|
{
|
||||||
void* ptr = a.alloc(layout::of<T>());
|
void* ptr = a.alloc(layout::of<T>());
|
||||||
return construct_at<T>(ptr, ASL_FWD(args)...);
|
return construct_at<T>(ptr, ASL_FWD(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void alloc_delete(allocator auto& a, T* ptr)
|
void alloc_delete(allocator auto& a, T* ptr)
|
||||||
{
|
{
|
||||||
destroy(ptr);
|
destroy(ptr);
|
||||||
a.dealloc(ptr, layout::of<T>());
|
a.dealloc(ptr, layout::of<T>());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr T* alloc_new_default(auto&&... args)
|
constexpr T* alloc_new_default(auto&&... args)
|
||||||
{
|
{
|
||||||
return alloc_new<T>(DefaultAllocator{}, ASL_FWD(args)...);
|
return alloc_new<T>(DefaultAllocator{}, ASL_FWD(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void alloc_delete_default(T* ptr)
|
void alloc_delete_default(T* ptr)
|
||||||
{
|
{
|
||||||
alloc_delete(DefaultAllocator{}, ptr);
|
alloc_delete(DefaultAllocator{}, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace asl
|
} // namespace asl
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "asl/config.hpp"
|
#include "asl/config.hpp"
|
||||||
|
|
||||||
#if ASL_COMPILER_CLANG_CL
|
#if ASL_COMPILER_CLANG_CL
|
||||||
#define ASL_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]]
|
#define ASL_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]]
|
||||||
#elif ASL_COMPILER_CLANG
|
#elif ASL_COMPILER_CLANG
|
||||||
#define ASL_NO_UNIQUE_ADDRESS [[no_unique_address]]
|
#define ASL_NO_UNIQUE_ADDRESS [[no_unique_address]]
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,33 +1,33 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "asl/config.hpp"
|
#include "asl/config.hpp"
|
||||||
#include "asl/meta.hpp"
|
#include "asl/meta.hpp"
|
||||||
|
|
||||||
namespace asl
|
namespace asl
|
||||||
{
|
{
|
||||||
|
|
||||||
void report_assert_failure( const char* msg, const source_location& sl = source_location{});
|
void report_assert_failure( const char* msg, const source_location& sl = source_location{});
|
||||||
|
|
||||||
} // namespace asl
|
} // namespace asl
|
||||||
|
|
||||||
#if ASL_COMPILER_CLANG_CL
|
#if ASL_COMPILER_CLANG_CL
|
||||||
#define ASL_DEBUG_BREAK() __debugbreak()
|
#define ASL_DEBUG_BREAK() __debugbreak()
|
||||||
#elif ASL_COMPILER_CLANG
|
#elif ASL_COMPILER_CLANG
|
||||||
#define ASL_DEBUG_BREAK() __builtin_debugtrap()
|
#define ASL_DEBUG_BREAK() __builtin_debugtrap()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ASL_ASSERT(...) \
|
#define ASL_ASSERT(...) \
|
||||||
if (__VA_ARGS__) {} \
|
if (__VA_ARGS__) {} \
|
||||||
else \
|
else \
|
||||||
{ \
|
{ \
|
||||||
::asl::report_assert_failure(#__VA_ARGS__); \
|
::asl::report_assert_failure(#__VA_ARGS__); \
|
||||||
ASL_DEBUG_BREAK(); \
|
ASL_DEBUG_BREAK(); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ASL_ASSERT_RELEASE(...) \
|
#define ASL_ASSERT_RELEASE(...) \
|
||||||
if (__VA_ARGS__) {} \
|
if (__VA_ARGS__) {} \
|
||||||
else \
|
else \
|
||||||
{ \
|
{ \
|
||||||
::asl::report_assert_failure(#__VA_ARGS__); \
|
::asl::report_assert_failure(#__VA_ARGS__); \
|
||||||
ASL_DEBUG_BREAK(); \
|
ASL_DEBUG_BREAK(); \
|
||||||
}
|
}
|
||||||
|
230
asl/box.hpp
230
asl/box.hpp
@ -1,115 +1,115 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "asl/allocator.hpp"
|
#include "asl/allocator.hpp"
|
||||||
#include "asl/assert.hpp"
|
#include "asl/assert.hpp"
|
||||||
#include "asl/annotations.hpp"
|
#include "asl/annotations.hpp"
|
||||||
#include "asl/memory.hpp"
|
#include "asl/memory.hpp"
|
||||||
#include "asl/utility.hpp"
|
#include "asl/utility.hpp"
|
||||||
#include "asl/hash.hpp"
|
#include "asl/hash.hpp"
|
||||||
|
|
||||||
namespace asl
|
namespace asl
|
||||||
{
|
{
|
||||||
|
|
||||||
template<is_object T, allocator Allocator = DefaultAllocator>
|
template<is_object T, allocator Allocator = DefaultAllocator>
|
||||||
class box
|
class box
|
||||||
{
|
{
|
||||||
T* m_ptr;
|
T* m_ptr;
|
||||||
ASL_NO_UNIQUE_ADDRESS Allocator m_alloc;
|
ASL_NO_UNIQUE_ADDRESS Allocator m_alloc;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit constexpr box(niche_t)
|
explicit constexpr box(niche_t)
|
||||||
requires default_constructible<Allocator>
|
requires default_constructible<Allocator>
|
||||||
: m_ptr{nullptr}
|
: m_ptr{nullptr}
|
||||||
, m_alloc{}
|
, m_alloc{}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
constexpr box(T* ptr, Allocator alloc)
|
constexpr box(T* ptr, Allocator alloc)
|
||||||
: m_ptr{ptr}
|
: m_ptr{ptr}
|
||||||
, m_alloc{ASL_MOVE(alloc)}
|
, m_alloc{ASL_MOVE(alloc)}
|
||||||
{
|
{
|
||||||
ASL_ASSERT(m_ptr != nullptr);
|
ASL_ASSERT(m_ptr != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr box(box&& other)
|
constexpr box(box&& other)
|
||||||
: m_ptr{exchange(other.m_ptr, nullptr)}
|
: m_ptr{exchange(other.m_ptr, nullptr)}
|
||||||
, m_alloc{ASL_MOVE(other.m_alloc)}
|
, m_alloc{ASL_MOVE(other.m_alloc)}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
constexpr box& operator=(box&& other)
|
constexpr box& operator=(box&& other)
|
||||||
{
|
{
|
||||||
if (this == &other) { return *this; }
|
if (this == &other) { return *this; }
|
||||||
|
|
||||||
if (m_ptr != nullptr) { reset(); }
|
if (m_ptr != nullptr) { reset(); }
|
||||||
|
|
||||||
m_ptr = exchange(other.m_ptr, nullptr);
|
m_ptr = exchange(other.m_ptr, nullptr);
|
||||||
m_alloc = ASL_MOVE(other.m_alloc);
|
m_alloc = ASL_MOVE(other.m_alloc);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
box(const box&) = delete;
|
box(const box&) = delete;
|
||||||
box& operator=(const box&) = delete;
|
box& operator=(const box&) = delete;
|
||||||
|
|
||||||
constexpr ~box()
|
constexpr ~box()
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void reset()
|
constexpr void reset()
|
||||||
{
|
{
|
||||||
if (m_ptr != nullptr)
|
if (m_ptr != nullptr)
|
||||||
{
|
{
|
||||||
destroy(m_ptr);
|
destroy(m_ptr);
|
||||||
m_alloc.dealloc(m_ptr, layout::of<T>());
|
m_alloc.dealloc(m_ptr, layout::of<T>());
|
||||||
m_ptr = nullptr;
|
m_ptr = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr T* get() const { return m_ptr; }
|
constexpr T* get() const { return m_ptr; }
|
||||||
|
|
||||||
constexpr T& operator*() const
|
constexpr T& operator*() const
|
||||||
{
|
{
|
||||||
ASL_ASSERT(m_ptr != nullptr);
|
ASL_ASSERT(m_ptr != nullptr);
|
||||||
return *m_ptr;
|
return *m_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr T* operator->() const
|
constexpr T* operator->() const
|
||||||
{
|
{
|
||||||
ASL_ASSERT(m_ptr != nullptr);
|
ASL_ASSERT(m_ptr != nullptr);
|
||||||
return m_ptr;
|
return m_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool operator==(niche_t) const
|
constexpr bool operator==(niche_t) const
|
||||||
{
|
{
|
||||||
return m_ptr == nullptr;
|
return m_ptr == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename H>
|
template<typename H>
|
||||||
requires hashable<T>
|
requires hashable<T>
|
||||||
friend H AslHashValue(H h, const box& b)
|
friend H AslHashValue(H h, const box& b)
|
||||||
{
|
{
|
||||||
return H::combine(ASL_MOVE(h), *b);
|
return H::combine(ASL_MOVE(h), *b);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<is_object T, allocator Allocator = DefaultAllocator, typename... Args>
|
template<is_object T, allocator Allocator = DefaultAllocator, typename... Args>
|
||||||
constexpr box<T, Allocator> make_box_in(Allocator allocator, Args&&... args)
|
constexpr box<T, Allocator> make_box_in(Allocator allocator, Args&&... args)
|
||||||
requires constructible_from<T, Args&&...>
|
requires constructible_from<T, Args&&...>
|
||||||
{
|
{
|
||||||
void* raw_ptr = allocator.alloc(layout::of<T>());
|
void* raw_ptr = allocator.alloc(layout::of<T>());
|
||||||
auto* ptr = construct_at<T>(raw_ptr, ASL_FWD(args)...);
|
auto* ptr = construct_at<T>(raw_ptr, ASL_FWD(args)...);
|
||||||
return box(ptr, ASL_MOVE(allocator));
|
return box(ptr, ASL_MOVE(allocator));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<is_object T, allocator Allocator = DefaultAllocator, typename... Args>
|
template<is_object T, allocator Allocator = DefaultAllocator, typename... Args>
|
||||||
constexpr box<T, Allocator> make_box(Args&&... args)
|
constexpr box<T, Allocator> make_box(Args&&... args)
|
||||||
requires default_constructible<Allocator> && constructible_from<T, Args&&...>
|
requires default_constructible<Allocator> && constructible_from<T, Args&&...>
|
||||||
{
|
{
|
||||||
Allocator allocator{};
|
Allocator allocator{};
|
||||||
void* raw_ptr = allocator.alloc(layout::of<T>());
|
void* raw_ptr = allocator.alloc(layout::of<T>());
|
||||||
auto* ptr = construct_at<T>(raw_ptr, ASL_FWD(args)...);
|
auto* ptr = construct_at<T>(raw_ptr, ASL_FWD(args)...);
|
||||||
return box<T>(ptr, ASL_MOVE(allocator));
|
return box<T>(ptr, ASL_MOVE(allocator));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace asl
|
} // namespace asl
|
||||||
|
|
||||||
|
918
asl/buffer.hpp
918
asl/buffer.hpp
@ -1,459 +1,459 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "asl/meta.hpp"
|
#include "asl/meta.hpp"
|
||||||
#include "asl/allocator.hpp"
|
#include "asl/allocator.hpp"
|
||||||
#include "asl/annotations.hpp"
|
#include "asl/annotations.hpp"
|
||||||
#include "asl/memory.hpp"
|
#include "asl/memory.hpp"
|
||||||
#include "asl/assert.hpp"
|
#include "asl/assert.hpp"
|
||||||
#include "asl/span.hpp"
|
#include "asl/span.hpp"
|
||||||
#include "asl/hash.hpp"
|
#include "asl/hash.hpp"
|
||||||
|
|
||||||
namespace asl
|
namespace asl
|
||||||
{
|
{
|
||||||
|
|
||||||
template<is_object T, allocator Allocator = DefaultAllocator>
|
template<is_object T, allocator Allocator = DefaultAllocator>
|
||||||
class buffer
|
class buffer
|
||||||
{
|
{
|
||||||
T* m_data{};
|
T* m_data{};
|
||||||
isize_t m_capacity{};
|
isize_t m_capacity{};
|
||||||
|
|
||||||
static constexpr size_t kOnHeapMask = 0x8000'0000'0000'0000ULL;
|
static constexpr size_t kOnHeapMask = 0x8000'0000'0000'0000ULL;
|
||||||
|
|
||||||
// bit 63 : 1 = on heap, 0 = inline
|
// bit 63 : 1 = on heap, 0 = inline
|
||||||
// bits [62:56] : size when inline
|
// bits [62:56] : size when inline
|
||||||
// bits [62:0] : size when on heap
|
// bits [62:0] : size when on heap
|
||||||
size_t m_size_encoded_{};
|
size_t m_size_encoded_{};
|
||||||
|
|
||||||
ASL_NO_UNIQUE_ADDRESS Allocator m_allocator;
|
ASL_NO_UNIQUE_ADDRESS Allocator m_allocator;
|
||||||
|
|
||||||
static constexpr isize_t kInlineRegionSize = size_of<T*> + size_of<isize_t> + size_of<size_t>;
|
static constexpr isize_t kInlineRegionSize = size_of<T*> + size_of<isize_t> + size_of<size_t>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static constexpr isize_t kInlineCapacity = []() {
|
static constexpr isize_t kInlineCapacity = []() {
|
||||||
// 1 byte is used for size inline in m_size_encoded.
|
// 1 byte is used for size inline in m_size_encoded.
|
||||||
// This is enough because we have at most 24 bytes available,
|
// This is enough because we have at most 24 bytes available,
|
||||||
// so 23 chars of capacity.
|
// so 23 chars of capacity.
|
||||||
const isize_t available_size = kInlineRegionSize - 1;
|
const isize_t available_size = kInlineRegionSize - 1;
|
||||||
return available_size / size_of<T>;
|
return available_size / size_of<T>;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static_assert(align_of<T> <= align_of<T*>);
|
static_assert(align_of<T> <= align_of<T*>);
|
||||||
static_assert(align_of<T*> == align_of<isize_t>);
|
static_assert(align_of<T*> == align_of<isize_t>);
|
||||||
static_assert(align_of<T*> == align_of<size_t>);
|
static_assert(align_of<T*> == align_of<size_t>);
|
||||||
|
|
||||||
constexpr size_t load_size_encoded() const
|
constexpr size_t load_size_encoded() const
|
||||||
{
|
{
|
||||||
size_t s{};
|
size_t s{};
|
||||||
asl::memcpy(&s, &m_size_encoded_, sizeof(size_t));
|
asl::memcpy(&s, &m_size_encoded_, sizeof(size_t));
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void store_size_encoded(size_t encoded)
|
constexpr void store_size_encoded(size_t encoded)
|
||||||
{
|
{
|
||||||
asl::memcpy(&m_size_encoded_, &encoded, sizeof(size_t));
|
asl::memcpy(&m_size_encoded_, &encoded, sizeof(size_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr bool is_on_heap(size_t size_encoded)
|
static constexpr bool is_on_heap(size_t size_encoded)
|
||||||
{
|
{
|
||||||
return (size_encoded & kOnHeapMask) != 0;
|
return (size_encoded & kOnHeapMask) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr size_t encode_size_heap(isize_t size)
|
static constexpr size_t encode_size_heap(isize_t size)
|
||||||
{
|
{
|
||||||
return static_cast<size_t>(size) | kOnHeapMask;
|
return static_cast<size_t>(size) | kOnHeapMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr isize_t decode_size(size_t size_encoded)
|
static constexpr isize_t decode_size(size_t size_encoded)
|
||||||
{
|
{
|
||||||
if constexpr (kInlineCapacity == 0)
|
if constexpr (kInlineCapacity == 0)
|
||||||
{
|
{
|
||||||
return is_on_heap(size_encoded)
|
return is_on_heap(size_encoded)
|
||||||
? static_cast<isize_t>(size_encoded & (~kOnHeapMask))
|
? static_cast<isize_t>(size_encoded & (~kOnHeapMask))
|
||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return is_on_heap(size_encoded)
|
return is_on_heap(size_encoded)
|
||||||
? static_cast<isize_t>(size_encoded & (~kOnHeapMask))
|
? static_cast<isize_t>(size_encoded & (~kOnHeapMask))
|
||||||
: static_cast<isize_t>(size_encoded >> 56);
|
: static_cast<isize_t>(size_encoded >> 56);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool is_on_heap() const
|
constexpr bool is_on_heap() const
|
||||||
{
|
{
|
||||||
return is_on_heap(load_size_encoded());
|
return is_on_heap(load_size_encoded());
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr T* push_uninit()
|
constexpr T* push_uninit()
|
||||||
{
|
{
|
||||||
isize_t sz = size();
|
isize_t sz = size();
|
||||||
resize_uninit_inner(sz + 1);
|
resize_uninit_inner(sz + 1);
|
||||||
return data() + sz;
|
return data() + sz;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void resize_uninit_inner(isize_t new_size)
|
constexpr void resize_uninit_inner(isize_t new_size)
|
||||||
{
|
{
|
||||||
isize_t old_size = size();
|
isize_t old_size = size();
|
||||||
if (!trivially_destructible<T> && new_size < old_size)
|
if (!trivially_destructible<T> && new_size < old_size)
|
||||||
{
|
{
|
||||||
destroy_n(data() + new_size, old_size - new_size);
|
destroy_n(data() + new_size, old_size - new_size);
|
||||||
}
|
}
|
||||||
reserve_capacity(new_size);
|
reserve_capacity(new_size);
|
||||||
set_size(new_size);
|
set_size(new_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void set_size_inline(isize_t new_size)
|
constexpr void set_size_inline(isize_t new_size)
|
||||||
{
|
{
|
||||||
ASL_ASSERT(new_size >= 0 && new_size <= kInlineCapacity);
|
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);
|
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);
|
store_size_encoded(size_encoded);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void set_size(isize_t new_size)
|
constexpr void set_size(isize_t new_size)
|
||||||
{
|
{
|
||||||
ASL_ASSERT(new_size >= 0 && new_size <= capacity());
|
ASL_ASSERT(new_size >= 0 && new_size <= capacity());
|
||||||
if (is_on_heap())
|
if (is_on_heap())
|
||||||
{
|
{
|
||||||
store_size_encoded(encode_size_heap(new_size));
|
store_size_encoded(encode_size_heap(new_size));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
set_size_inline(new_size);
|
set_size_inline(new_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOLINTNEXTLINE(*-rvalue-reference-param-not-moved)
|
// NOLINTNEXTLINE(*-rvalue-reference-param-not-moved)
|
||||||
void move_from_other(buffer&& other, bool assign)
|
void move_from_other(buffer&& other, bool assign)
|
||||||
{
|
{
|
||||||
if (other.is_on_heap())
|
if (other.is_on_heap())
|
||||||
{
|
{
|
||||||
destroy();
|
destroy();
|
||||||
m_data = other.m_data;
|
m_data = other.m_data;
|
||||||
m_capacity = other.m_capacity;
|
m_capacity = other.m_capacity;
|
||||||
store_size_encoded(other.load_size_encoded());
|
store_size_encoded(other.load_size_encoded());
|
||||||
}
|
}
|
||||||
else if (trivially_move_constructible<T>)
|
else if (trivially_move_constructible<T>)
|
||||||
{
|
{
|
||||||
destroy();
|
destroy();
|
||||||
asl::memcpy(this, &other, kInlineRegionSize);
|
asl::memcpy(this, &other, kInlineRegionSize);
|
||||||
}
|
}
|
||||||
else if (!assign || m_allocator == other.m_allocator)
|
else if (!assign || m_allocator == other.m_allocator)
|
||||||
{
|
{
|
||||||
isize_t other_n = other.size();
|
isize_t other_n = other.size();
|
||||||
isize_t this_n = size();
|
isize_t this_n = size();
|
||||||
resize_uninit_inner(other_n);
|
resize_uninit_inner(other_n);
|
||||||
if (other_n <= this_n)
|
if (other_n <= this_n)
|
||||||
{
|
{
|
||||||
relocate_assign_n(data(), other.data(), other_n);
|
relocate_assign_n(data(), other.data(), other_n);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
relocate_assign_n(data(), other.data(), this_n);
|
relocate_assign_n(data(), other.data(), this_n);
|
||||||
relocate_uninit_n(data() + this_n, other.data() + this_n, other_n - this_n);
|
relocate_uninit_n(data() + this_n, other.data() + this_n, other_n - this_n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
destroy();
|
destroy();
|
||||||
isize_t n = other.size();
|
isize_t n = other.size();
|
||||||
ASL_ASSERT(n <= kInlineCapacity);
|
ASL_ASSERT(n <= kInlineCapacity);
|
||||||
relocate_uninit_n(data(), other.data(), n);
|
relocate_uninit_n(data(), other.data(), n);
|
||||||
set_size_inline(n);
|
set_size_inline(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
other.set_size_inline(0);
|
other.set_size_inline(0);
|
||||||
|
|
||||||
if (assign)
|
if (assign)
|
||||||
{
|
{
|
||||||
m_allocator = ASL_MOVE(other.m_allocator);
|
m_allocator = ASL_MOVE(other.m_allocator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void copy_range(span<const T> to_copy)
|
void copy_range(span<const T> to_copy)
|
||||||
{
|
{
|
||||||
isize_t this_size = size();
|
isize_t this_size = size();
|
||||||
isize_t new_size = to_copy.size();
|
isize_t new_size = to_copy.size();
|
||||||
|
|
||||||
resize_uninit_inner(to_copy.size());
|
resize_uninit_inner(to_copy.size());
|
||||||
ASL_ASSERT(capacity() >= new_size);
|
ASL_ASSERT(capacity() >= new_size);
|
||||||
ASL_ASSERT(size() == to_copy.size());
|
ASL_ASSERT(size() == to_copy.size());
|
||||||
|
|
||||||
if (new_size <= this_size)
|
if (new_size <= this_size)
|
||||||
{
|
{
|
||||||
copy_assign_n(data(), to_copy.data(), new_size);
|
copy_assign_n(data(), to_copy.data(), new_size);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
copy_assign_n(data(), to_copy.data(), this_size);
|
copy_assign_n(data(), to_copy.data(), this_size);
|
||||||
copy_uninit_n(data() + this_size, to_copy.data() + this_size, new_size - this_size);
|
copy_uninit_n(data() + this_size, to_copy.data() + this_size, new_size - this_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
void resize_inner(isize_t new_size, Args&&... args)
|
void resize_inner(isize_t new_size, Args&&... args)
|
||||||
requires constructible_from<T, Args&&...>
|
requires constructible_from<T, Args&&...>
|
||||||
{
|
{
|
||||||
ASL_ASSERT(new_size >= 0);
|
ASL_ASSERT(new_size >= 0);
|
||||||
|
|
||||||
isize_t old_size = size();
|
isize_t old_size = size();
|
||||||
resize_uninit_inner(new_size);
|
resize_uninit_inner(new_size);
|
||||||
|
|
||||||
T* data_ptr = data();
|
T* data_ptr = data();
|
||||||
T* end = data_ptr + new_size;
|
T* end = data_ptr + new_size;
|
||||||
|
|
||||||
// NOLINTNEXTLINE(*-pointer-arithmetic)
|
// NOLINTNEXTLINE(*-pointer-arithmetic)
|
||||||
for (T* it = data_ptr + old_size; it < end; ++it)
|
for (T* it = data_ptr + old_size; it < end; ++it)
|
||||||
{
|
{
|
||||||
construct_at<T>(it, ASL_FWD(args)...);
|
construct_at<T>(it, ASL_FWD(args)...);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr buffer() requires default_constructible<Allocator> = default;
|
constexpr buffer() requires default_constructible<Allocator> = default;
|
||||||
|
|
||||||
explicit constexpr buffer(span<const T> s)
|
explicit constexpr buffer(span<const T> s)
|
||||||
requires default_constructible<Allocator>
|
requires default_constructible<Allocator>
|
||||||
: buffer{}
|
: buffer{}
|
||||||
{
|
{
|
||||||
copy_range(s);
|
copy_range(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit constexpr buffer(Allocator allocator)
|
explicit constexpr buffer(Allocator allocator)
|
||||||
: m_allocator{ASL_MOVE(allocator)}
|
: m_allocator{ASL_MOVE(allocator)}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
explicit constexpr buffer(span<const T> s, Allocator allocator)
|
explicit constexpr buffer(span<const T> s, Allocator allocator)
|
||||||
: m_allocator{ASL_MOVE(allocator)}
|
: m_allocator{ASL_MOVE(allocator)}
|
||||||
{
|
{
|
||||||
copy_range(s);
|
copy_range(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr buffer(const buffer& other)
|
constexpr buffer(const buffer& other)
|
||||||
requires copy_constructible<Allocator> && copyable<T>
|
requires copy_constructible<Allocator> && copyable<T>
|
||||||
: m_allocator{other.m_allocator}
|
: m_allocator{other.m_allocator}
|
||||||
{
|
{
|
||||||
copy_range(other);
|
copy_range(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr buffer(buffer&& other)
|
constexpr buffer(buffer&& other)
|
||||||
requires moveable<T>
|
requires moveable<T>
|
||||||
: buffer(ASL_MOVE(other.m_allocator))
|
: buffer(ASL_MOVE(other.m_allocator))
|
||||||
{
|
{
|
||||||
move_from_other(ASL_MOVE(other), false);
|
move_from_other(ASL_MOVE(other), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr buffer& operator=(const buffer& other)
|
constexpr buffer& operator=(const buffer& other)
|
||||||
requires copyable<T>
|
requires copyable<T>
|
||||||
{
|
{
|
||||||
if (&other == this) { return *this; }
|
if (&other == this) { return *this; }
|
||||||
copy_range(other);
|
copy_range(other);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr buffer& operator=(buffer&& other)
|
constexpr buffer& operator=(buffer&& other)
|
||||||
requires moveable<T>
|
requires moveable<T>
|
||||||
{
|
{
|
||||||
if (&other == this) { return *this; }
|
if (&other == this) { return *this; }
|
||||||
move_from_other(ASL_MOVE(other), true);
|
move_from_other(ASL_MOVE(other), true);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
~buffer()
|
~buffer()
|
||||||
{
|
{
|
||||||
destroy();
|
destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr isize_t size() const
|
constexpr isize_t size() const
|
||||||
{
|
{
|
||||||
return decode_size(load_size_encoded());
|
return decode_size(load_size_encoded());
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr isize_t capacity() const
|
constexpr isize_t capacity() const
|
||||||
{
|
{
|
||||||
if constexpr (kInlineCapacity == 0)
|
if constexpr (kInlineCapacity == 0)
|
||||||
{
|
{
|
||||||
return m_capacity;
|
return m_capacity;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return is_on_heap() ? m_capacity : kInlineCapacity;
|
return is_on_heap() ? m_capacity : kInlineCapacity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
isize_t current_size = size();
|
isize_t current_size = size();
|
||||||
if (current_size == 0) { return; }
|
if (current_size == 0) { return; }
|
||||||
|
|
||||||
destroy_n(data(), current_size);
|
destroy_n(data(), current_size);
|
||||||
set_size(0);
|
set_size(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroy()
|
void destroy()
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
if (is_on_heap())
|
if (is_on_heap())
|
||||||
{
|
{
|
||||||
if (m_data != nullptr)
|
if (m_data != nullptr)
|
||||||
{
|
{
|
||||||
auto current_layout = layout::array<T>(m_capacity);
|
auto current_layout = layout::array<T>(m_capacity);
|
||||||
m_allocator.dealloc(m_data, current_layout);
|
m_allocator.dealloc(m_data, current_layout);
|
||||||
}
|
}
|
||||||
set_size_inline(0);
|
set_size_inline(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void reserve_capacity(isize_t new_capacity)
|
void reserve_capacity(isize_t new_capacity)
|
||||||
{
|
{
|
||||||
ASL_ASSERT(new_capacity >= 0);
|
ASL_ASSERT(new_capacity >= 0);
|
||||||
ASL_ASSERT_RELEASE(new_capacity <= 0x4000'0000'0000'0000);
|
ASL_ASSERT_RELEASE(new_capacity <= 0x4000'0000'0000'0000);
|
||||||
|
|
||||||
if (new_capacity <= capacity()) { return; }
|
if (new_capacity <= capacity()) { return; }
|
||||||
ASL_ASSERT(new_capacity > kInlineCapacity);
|
ASL_ASSERT(new_capacity > kInlineCapacity);
|
||||||
|
|
||||||
new_capacity = static_cast<isize_t>(round_up_pow2(static_cast<uint64_t>(new_capacity)));
|
new_capacity = static_cast<isize_t>(round_up_pow2(static_cast<uint64_t>(new_capacity)));
|
||||||
|
|
||||||
T* old_data = data();
|
T* old_data = data();
|
||||||
const isize_t old_capacity = capacity();
|
const isize_t old_capacity = capacity();
|
||||||
const isize_t current_size = size();
|
const isize_t current_size = size();
|
||||||
const bool currently_on_heap = is_on_heap();
|
const bool currently_on_heap = is_on_heap();
|
||||||
|
|
||||||
auto old_layout = layout::array<T>(old_capacity);
|
auto old_layout = layout::array<T>(old_capacity);
|
||||||
auto new_layout = layout::array<T>(new_capacity);
|
auto new_layout = layout::array<T>(new_capacity);
|
||||||
|
|
||||||
if (currently_on_heap && trivially_move_constructible<T>)
|
if (currently_on_heap && trivially_move_constructible<T>)
|
||||||
{
|
{
|
||||||
m_data = reinterpret_cast<T*>(m_allocator.realloc(m_data, old_layout, new_layout));
|
m_data = reinterpret_cast<T*>(m_allocator.realloc(m_data, old_layout, new_layout));
|
||||||
m_capacity = new_capacity;
|
m_capacity = new_capacity;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
T* new_data = reinterpret_cast<T*>(m_allocator.alloc(new_layout));
|
T* new_data = reinterpret_cast<T*>(m_allocator.alloc(new_layout));
|
||||||
|
|
||||||
relocate_uninit_n(new_data, old_data, current_size);
|
relocate_uninit_n(new_data, old_data, current_size);
|
||||||
|
|
||||||
if (currently_on_heap)
|
if (currently_on_heap)
|
||||||
{
|
{
|
||||||
m_allocator.dealloc(old_data, old_layout);
|
m_allocator.dealloc(old_data, old_layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_data = new_data;
|
m_data = new_data;
|
||||||
m_capacity = new_capacity;
|
m_capacity = new_capacity;
|
||||||
store_size_encoded(encode_size_heap(current_size));
|
store_size_encoded(encode_size_heap(current_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void resize_uninit(isize_t new_size)
|
constexpr void resize_uninit(isize_t new_size)
|
||||||
requires trivially_default_constructible<T> && trivially_destructible<T>
|
requires trivially_default_constructible<T> && trivially_destructible<T>
|
||||||
{
|
{
|
||||||
reserve_capacity(new_size);
|
reserve_capacity(new_size);
|
||||||
set_size(new_size);
|
set_size(new_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void resize_zero(isize_t new_size)
|
constexpr void resize_zero(isize_t new_size)
|
||||||
requires trivially_default_constructible<T> && trivially_destructible<T>
|
requires trivially_default_constructible<T> && trivially_destructible<T>
|
||||||
{
|
{
|
||||||
isize_t old_size = size();
|
isize_t old_size = size();
|
||||||
resize_uninit(new_size);
|
resize_uninit(new_size);
|
||||||
|
|
||||||
if (new_size > old_size)
|
if (new_size > old_size)
|
||||||
{
|
{
|
||||||
memzero(data() + old_size, (new_size - old_size) * size_of<T>);
|
memzero(data() + old_size, (new_size - old_size) * size_of<T>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void resize(isize_t new_size)
|
void resize(isize_t new_size)
|
||||||
requires default_constructible<T>
|
requires default_constructible<T>
|
||||||
{
|
{
|
||||||
resize_inner(new_size);
|
resize_inner(new_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void resize(isize_t new_size, const T& value)
|
void resize(isize_t new_size, const T& value)
|
||||||
{
|
{
|
||||||
resize_inner(new_size, value);
|
resize_inner(new_size, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr T& push(auto&&... args)
|
constexpr T& push(auto&&... args)
|
||||||
requires constructible_from<T, decltype(args)&&...>
|
requires constructible_from<T, decltype(args)&&...>
|
||||||
{
|
{
|
||||||
T* uninit = push_uninit();
|
T* uninit = push_uninit();
|
||||||
T* init = construct_at<T>(uninit, ASL_FWD(args)...);
|
T* init = construct_at<T>(uninit, ASL_FWD(args)...);
|
||||||
return *init;
|
return *init;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Todo(C++23) Use deducing this
|
// @Todo(C++23) Use deducing this
|
||||||
const T* data() const
|
const T* data() const
|
||||||
{
|
{
|
||||||
if constexpr (kInlineCapacity == 0)
|
if constexpr (kInlineCapacity == 0)
|
||||||
{
|
{
|
||||||
return m_data;
|
return m_data;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return is_on_heap() ? m_data : reinterpret_cast<const T*>(this);
|
return is_on_heap() ? m_data : reinterpret_cast<const T*>(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
T* data()
|
T* data()
|
||||||
{
|
{
|
||||||
if constexpr (kInlineCapacity == 0)
|
if constexpr (kInlineCapacity == 0)
|
||||||
{
|
{
|
||||||
return m_data;
|
return m_data;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return is_on_heap() ? m_data : reinterpret_cast<T*>(this);
|
return is_on_heap() ? m_data : reinterpret_cast<T*>(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Todo(C++23) Use deducing this
|
// @Todo(C++23) Use deducing this
|
||||||
constexpr contiguous_iterator<const T> begin() const { return contiguous_iterator{data()}; }
|
constexpr contiguous_iterator<const T> begin() const { return contiguous_iterator{data()}; }
|
||||||
constexpr contiguous_iterator<const T> end() const { return contiguous_iterator{data() + size()}; }
|
constexpr contiguous_iterator<const T> end() const { return contiguous_iterator{data() + size()}; }
|
||||||
|
|
||||||
constexpr contiguous_iterator<T> begin() { return contiguous_iterator{data()}; }
|
constexpr contiguous_iterator<T> begin() { return contiguous_iterator{data()}; }
|
||||||
constexpr contiguous_iterator<T> end() { return contiguous_iterator{data() + size()}; }
|
constexpr contiguous_iterator<T> end() { return contiguous_iterator{data() + size()}; }
|
||||||
|
|
||||||
// @Todo(C++23) Deducing this
|
// @Todo(C++23) Deducing this
|
||||||
constexpr operator span<const T>() const // NOLINT(*-explicit-conversions)
|
constexpr operator span<const T>() const // NOLINT(*-explicit-conversions)
|
||||||
{
|
{
|
||||||
return as_span();
|
return as_span();
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr operator span<T>() // NOLINT(*-explicit-conversions)
|
constexpr operator span<T>() // NOLINT(*-explicit-conversions)
|
||||||
{
|
{
|
||||||
return as_span();
|
return as_span();
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr span<const T> as_span() const
|
constexpr span<const T> as_span() const
|
||||||
{
|
{
|
||||||
return span<const T>{data(), size()};
|
return span<const T>{data(), size()};
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr span<T> as_span()
|
constexpr span<T> as_span()
|
||||||
{
|
{
|
||||||
return span<T>{data(), size()};
|
return span<T>{data(), size()};
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Todo(C++23) Use deducing this
|
// @Todo(C++23) Use deducing this
|
||||||
constexpr T& operator[](isize_t i)
|
constexpr T& operator[](isize_t i)
|
||||||
{
|
{
|
||||||
ASL_ASSERT(i >= 0 && i <= size());
|
ASL_ASSERT(i >= 0 && i <= size());
|
||||||
return data()[i];
|
return data()[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr const T& operator[](isize_t i) const
|
constexpr const T& operator[](isize_t i) const
|
||||||
{
|
{
|
||||||
ASL_ASSERT(i >= 0 && i <= size());
|
ASL_ASSERT(i >= 0 && i <= size());
|
||||||
return data()[i];
|
return data()[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename H>
|
template<typename H>
|
||||||
requires hashable<T>
|
requires hashable<T>
|
||||||
friend H AslHashValue(H h, const buffer& b)
|
friend H AslHashValue(H h, const buffer& b)
|
||||||
{
|
{
|
||||||
return H::combine_contiguous(ASL_MOVE(h), b.as_span());
|
return H::combine_contiguous(ASL_MOVE(h), b.as_span());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace asl
|
} // namespace asl
|
||||||
|
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#define ASL_OS_WINDOWS 1
|
#define ASL_OS_WINDOWS 1
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
#define ASL_OS_LINUX 1
|
#define ASL_OS_LINUX 1
|
||||||
#else
|
#else
|
||||||
#error Unknown OS
|
#error Unknown OS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__clang__) && defined(_MSC_VER)
|
#if defined(__clang__) && defined(_MSC_VER)
|
||||||
#define ASL_COMPILER_CLANG_CL 1
|
#define ASL_COMPILER_CLANG_CL 1
|
||||||
#elif defined(__clang__)
|
#elif defined(__clang__)
|
||||||
#define ASL_COMPILER_CLANG 1
|
#define ASL_COMPILER_CLANG 1
|
||||||
#else
|
#else
|
||||||
#error Unknown compiler
|
#error Unknown compiler
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "asl/meta.hpp"
|
#include "asl/meta.hpp"
|
||||||
|
|
||||||
namespace asl
|
namespace asl
|
||||||
{
|
{
|
||||||
|
|
||||||
template<is_floating_point T> constexpr T infinity() { return __builtin_inf(); }
|
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 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_infinity(T f) { return __builtin_isinf(f); }
|
||||||
|
|
||||||
template<is_floating_point T> constexpr bool is_nan(T f) { return __builtin_isnan(f); }
|
template<is_floating_point T> constexpr bool is_nan(T f) { return __builtin_isnan(f); }
|
||||||
|
|
||||||
} // namespace asl
|
} // namespace asl
|
||||||
|
|
||||||
|
402
asl/format.cpp
402
asl/format.cpp
@ -1,201 +1,201 @@
|
|||||||
#include "asl/format.hpp"
|
#include "asl/format.hpp"
|
||||||
#include "asl/utility.hpp"
|
#include "asl/utility.hpp"
|
||||||
#include "asl/assert.hpp"
|
#include "asl/assert.hpp"
|
||||||
#include "asl/memory.hpp"
|
#include "asl/memory.hpp"
|
||||||
|
|
||||||
void asl::format_internals::format(
|
void asl::format_internals::format(
|
||||||
Writer* writer,
|
Writer* writer,
|
||||||
string_view fmt,
|
string_view fmt,
|
||||||
span<const type_erased_arg> args)
|
span<const type_erased_arg> args)
|
||||||
{
|
{
|
||||||
Formatter f(writer);
|
Formatter f(writer);
|
||||||
|
|
||||||
auto arg_it = args.begin();
|
auto arg_it = args.begin();
|
||||||
auto arg_end = args.end();
|
auto arg_end = args.end();
|
||||||
|
|
||||||
isize_t i = 0;
|
isize_t i = 0;
|
||||||
while (i < fmt.size())
|
while (i < fmt.size())
|
||||||
{
|
{
|
||||||
if (fmt[i] == '{')
|
if (fmt[i] == '{')
|
||||||
{
|
{
|
||||||
if (i + 1 < fmt.size())
|
if (i + 1 < fmt.size())
|
||||||
{
|
{
|
||||||
if (fmt[i + 1] == '}')
|
if (fmt[i + 1] == '}')
|
||||||
{
|
{
|
||||||
f.write(fmt.substr(0, i));
|
f.write(fmt.substr(0, i));
|
||||||
fmt = fmt.substr(i + 2);
|
fmt = fmt.substr(i + 2);
|
||||||
i = 0;
|
i = 0;
|
||||||
|
|
||||||
if (arg_it == arg_end)
|
if (arg_it == arg_end)
|
||||||
{
|
{
|
||||||
f.write("<ERROR>");
|
f.write("<ERROR>");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
arg_it->fn(f, arg_it->data);
|
arg_it->fn(f, arg_it->data);
|
||||||
arg_it++;
|
arg_it++;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fmt[i + 1] == '{')
|
if (fmt[i + 1] == '{')
|
||||||
{
|
{
|
||||||
f.write(fmt.substr(0, i + 1));
|
f.write(fmt.substr(0, i + 1));
|
||||||
fmt = fmt.substr(i + 2);
|
fmt = fmt.substr(i + 2);
|
||||||
i = 0;
|
i = 0;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
f.write(fmt.substr(0, i));
|
f.write(fmt.substr(0, i));
|
||||||
fmt = fmt.substr(i + 1);
|
fmt = fmt.substr(i + 1);
|
||||||
i = 0;
|
i = 0;
|
||||||
|
|
||||||
f.write("<ERROR>");
|
f.write("<ERROR>");
|
||||||
}
|
}
|
||||||
else if (i + 1 < fmt.size() && fmt[i] == '}' && fmt[i + 1] == '}')
|
else if (i + 1 < fmt.size() && fmt[i] == '}' && fmt[i + 1] == '}')
|
||||||
{
|
{
|
||||||
f.write(fmt.substr(0, i + 1));
|
f.write(fmt.substr(0, i + 1));
|
||||||
fmt = fmt.substr(i + 2);
|
fmt = fmt.substr(i + 2);
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
f.write(fmt);
|
f.write(fmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void asl::AslFormat(Formatter& f, const char* str)
|
void asl::AslFormat(Formatter& f, const char* str)
|
||||||
{
|
{
|
||||||
f.write({str, asl::strlen(str)});
|
f.write({str, asl::strlen(str)});
|
||||||
}
|
}
|
||||||
|
|
||||||
void asl::AslFormat(Formatter& f, bool v)
|
void asl::AslFormat(Formatter& f, bool v)
|
||||||
{
|
{
|
||||||
if (v)
|
if (v)
|
||||||
{
|
{
|
||||||
f.write("true");
|
f.write("true");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
f.write("false");
|
f.write("false");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void asl::AslFormat(Formatter& f, uint8_t v)
|
void asl::AslFormat(Formatter& f, uint8_t v)
|
||||||
{
|
{
|
||||||
AslFormat(f, static_cast<uint64_t>(v));
|
AslFormat(f, static_cast<uint64_t>(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
void asl::AslFormat(Formatter& f, uint16_t v)
|
void asl::AslFormat(Formatter& f, uint16_t v)
|
||||||
{
|
{
|
||||||
AslFormat(f, static_cast<uint64_t>(v));
|
AslFormat(f, static_cast<uint64_t>(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
void asl::AslFormat(Formatter& f, uint32_t v)
|
void asl::AslFormat(Formatter& f, uint32_t v)
|
||||||
{
|
{
|
||||||
AslFormat(f, static_cast<uint64_t>(v));
|
AslFormat(f, static_cast<uint64_t>(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr int32_t kMaxUint64Digits = 20;
|
static constexpr int32_t kMaxUint64Digits = 20;
|
||||||
|
|
||||||
asl::string_view asl::format_uint64(uint64_t v, asl::span<char, kMaxUint64Digits> buffer)
|
asl::string_view asl::format_uint64(uint64_t v, asl::span<char, kMaxUint64Digits> buffer)
|
||||||
{
|
{
|
||||||
static constexpr char s_pairs_storage[] = {
|
static constexpr char s_pairs_storage[] = {
|
||||||
'0', '0', '0', '1', '0', '2', '0', '3', '0', '4',
|
'0', '0', '0', '1', '0', '2', '0', '3', '0', '4',
|
||||||
'0', '5', '0', '6', '0', '7', '0', '8', '0', '9',
|
'0', '5', '0', '6', '0', '7', '0', '8', '0', '9',
|
||||||
'1', '0', '1', '1', '1', '2', '1', '3', '1', '4',
|
'1', '0', '1', '1', '1', '2', '1', '3', '1', '4',
|
||||||
'1', '5', '1', '6', '1', '7', '1', '8', '1', '9',
|
'1', '5', '1', '6', '1', '7', '1', '8', '1', '9',
|
||||||
'2', '0', '2', '1', '2', '2', '2', '3', '2', '4',
|
'2', '0', '2', '1', '2', '2', '2', '3', '2', '4',
|
||||||
'2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
|
'2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
|
||||||
'3', '0', '3', '1', '3', '2', '3', '3', '3', '4',
|
'3', '0', '3', '1', '3', '2', '3', '3', '3', '4',
|
||||||
'3', '5', '3', '6', '3', '7', '3', '8', '3', '9',
|
'3', '5', '3', '6', '3', '7', '3', '8', '3', '9',
|
||||||
'4', '0', '4', '1', '4', '2', '4', '3', '4', '4',
|
'4', '0', '4', '1', '4', '2', '4', '3', '4', '4',
|
||||||
'4', '5', '4', '6', '4', '7', '4', '8', '4', '9',
|
'4', '5', '4', '6', '4', '7', '4', '8', '4', '9',
|
||||||
'5', '0', '5', '1', '5', '2', '5', '3', '5', '4',
|
'5', '0', '5', '1', '5', '2', '5', '3', '5', '4',
|
||||||
'5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
|
'5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
|
||||||
'6', '0', '6', '1', '6', '2', '6', '3', '6', '4',
|
'6', '0', '6', '1', '6', '2', '6', '3', '6', '4',
|
||||||
'6', '5', '6', '6', '6', '7', '6', '8', '6', '9',
|
'6', '5', '6', '6', '6', '7', '6', '8', '6', '9',
|
||||||
'7', '0', '7', '1', '7', '2', '7', '3', '7', '4',
|
'7', '0', '7', '1', '7', '2', '7', '3', '7', '4',
|
||||||
'7', '5', '7', '6', '7', '7', '7', '8', '7', '9',
|
'7', '5', '7', '6', '7', '7', '7', '8', '7', '9',
|
||||||
'8', '0', '8', '1', '8', '2', '8', '3', '8', '4',
|
'8', '0', '8', '1', '8', '2', '8', '3', '8', '4',
|
||||||
'8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
|
'8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
|
||||||
'9', '0', '9', '1', '9', '2', '9', '3', '9', '4',
|
'9', '0', '9', '1', '9', '2', '9', '3', '9', '4',
|
||||||
'9', '5', '9', '6', '9', '7', '9', '8', '9', '9',
|
'9', '5', '9', '6', '9', '7', '9', '8', '9', '9',
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr span s_pairs = s_pairs_storage;
|
static constexpr span s_pairs = s_pairs_storage;
|
||||||
int32_t cursor = kMaxUint64Digits;
|
int32_t cursor = kMaxUint64Digits;
|
||||||
|
|
||||||
auto write_two = [&buffer, &cursor](span<const char, 2> str)
|
auto write_two = [&buffer, &cursor](span<const char, 2> str)
|
||||||
{
|
{
|
||||||
ASL_ASSERT(cursor >= 2);
|
ASL_ASSERT(cursor >= 2);
|
||||||
buffer[--cursor] = str[1];
|
buffer[--cursor] = str[1];
|
||||||
buffer[--cursor] = str[0];
|
buffer[--cursor] = str[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
auto write_one = [&buffer, &cursor](char c)
|
auto write_one = [&buffer, &cursor](char c)
|
||||||
{
|
{
|
||||||
ASL_ASSERT(cursor >= 1);
|
ASL_ASSERT(cursor >= 1);
|
||||||
buffer[--cursor] = c;
|
buffer[--cursor] = c;
|
||||||
};
|
};
|
||||||
|
|
||||||
while (v >= 100)
|
while (v >= 100)
|
||||||
{
|
{
|
||||||
uint64_t x = v % 100;
|
uint64_t x = v % 100;
|
||||||
v /= 100;
|
v /= 100;
|
||||||
write_two(s_pairs.subspan(static_cast<isize_t>(x * 2)).first<2>());
|
write_two(s_pairs.subspan(static_cast<isize_t>(x * 2)).first<2>());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v >= 10)
|
if (v >= 10)
|
||||||
{
|
{
|
||||||
write_two(s_pairs.subspan(static_cast<isize_t>(v * 2)).first<2>());
|
write_two(s_pairs.subspan(static_cast<isize_t>(v * 2)).first<2>());
|
||||||
}
|
}
|
||||||
else if (v > 0 || cursor == kMaxUint64Digits)
|
else if (v > 0 || cursor == kMaxUint64Digits)
|
||||||
{
|
{
|
||||||
ASL_ASSERT(v < 10);
|
ASL_ASSERT(v < 10);
|
||||||
write_one(static_cast<char>('0' + v));
|
write_one(static_cast<char>('0' + v));
|
||||||
}
|
}
|
||||||
|
|
||||||
return string_view(buffer.data(), kMaxUint64Digits).substr(cursor);
|
return string_view(buffer.data(), kMaxUint64Digits).substr(cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void asl::AslFormat(Formatter& f, uint64_t v)
|
void asl::AslFormat(Formatter& f, uint64_t v)
|
||||||
{
|
{
|
||||||
char buffer[kMaxUint64Digits];
|
char buffer[kMaxUint64Digits];
|
||||||
f.write(format_uint64(v, buffer));
|
f.write(format_uint64(v, buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
void asl::AslFormat(Formatter& f, int8_t v)
|
void asl::AslFormat(Formatter& f, int8_t v)
|
||||||
{
|
{
|
||||||
AslFormat(f, static_cast<int64_t>(v));
|
AslFormat(f, static_cast<int64_t>(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
void asl::AslFormat(Formatter& f, int16_t v)
|
void asl::AslFormat(Formatter& f, int16_t v)
|
||||||
{
|
{
|
||||||
AslFormat(f, static_cast<int64_t>(v));
|
AslFormat(f, static_cast<int64_t>(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
void asl::AslFormat(Formatter& f, int32_t v)
|
void asl::AslFormat(Formatter& f, int32_t v)
|
||||||
{
|
{
|
||||||
AslFormat(f, static_cast<int64_t>(v));
|
AslFormat(f, static_cast<int64_t>(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
void asl::AslFormat(Formatter& f, int64_t v)
|
void asl::AslFormat(Formatter& f, int64_t v)
|
||||||
{
|
{
|
||||||
if (v < 0)
|
if (v < 0)
|
||||||
{
|
{
|
||||||
f.write("-");
|
f.write("-");
|
||||||
uint64_t absolute_value = ~(bit_cast<uint64_t>(v) - 1);
|
uint64_t absolute_value = ~(bit_cast<uint64_t>(v) - 1);
|
||||||
AslFormat(f, absolute_value);
|
AslFormat(f, absolute_value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AslFormat(f, static_cast<uint64_t>(v));
|
AslFormat(f, static_cast<uint64_t>(v));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
216
asl/format.hpp
216
asl/format.hpp
@ -1,109 +1,109 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "asl/integers.hpp"
|
#include "asl/integers.hpp"
|
||||||
#include "asl/meta.hpp"
|
#include "asl/meta.hpp"
|
||||||
#include "asl/io.hpp"
|
#include "asl/io.hpp"
|
||||||
#include "asl/span.hpp"
|
#include "asl/span.hpp"
|
||||||
#include "asl/string_view.hpp"
|
#include "asl/string_view.hpp"
|
||||||
|
|
||||||
namespace asl
|
namespace asl
|
||||||
{
|
{
|
||||||
|
|
||||||
class Formatter;
|
class Formatter;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept formattable = requires (Formatter& f, const T& value)
|
concept formattable = requires (Formatter& f, const T& value)
|
||||||
{
|
{
|
||||||
AslFormat(f, value);
|
AslFormat(f, value);
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace format_internals
|
namespace format_internals
|
||||||
{
|
{
|
||||||
|
|
||||||
struct type_erased_arg
|
struct type_erased_arg
|
||||||
{
|
{
|
||||||
const void* data;
|
const void* data;
|
||||||
void (*fn)(Formatter&, const void*);
|
void (*fn)(Formatter&, const void*);
|
||||||
|
|
||||||
template<formattable T>
|
template<formattable T>
|
||||||
static constexpr void erased_fn(Formatter& f, const void* data)
|
static constexpr void erased_fn(Formatter& f, const void* data)
|
||||||
{
|
{
|
||||||
AslFormat(f, *reinterpret_cast<const T*>(data));
|
AslFormat(f, *reinterpret_cast<const T*>(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<formattable T>
|
template<formattable T>
|
||||||
explicit constexpr type_erased_arg(const T& arg)
|
explicit constexpr type_erased_arg(const T& arg)
|
||||||
: data{&arg}
|
: data{&arg}
|
||||||
, fn{erased_fn<T>}
|
, fn{erased_fn<T>}
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
void format(Writer*, string_view fmt, span<const type_erased_arg> args);
|
void format(Writer*, string_view fmt, span<const type_erased_arg> args);
|
||||||
|
|
||||||
} // namespace internals
|
} // namespace internals
|
||||||
|
|
||||||
class Formatter
|
class Formatter
|
||||||
{
|
{
|
||||||
Writer* m_writer;
|
Writer* m_writer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit constexpr Formatter(Writer* writer)
|
explicit constexpr Formatter(Writer* writer)
|
||||||
: m_writer{writer}
|
: m_writer{writer}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
constexpr void write(string_view s)
|
constexpr void write(string_view s)
|
||||||
{
|
{
|
||||||
m_writer->write(as_bytes(s.as_span()));
|
m_writer->write(as_bytes(s.as_span()));
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr Writer* writer() const { return m_writer; }
|
constexpr Writer* writer() const { return m_writer; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template<formattable... Args>
|
template<formattable... Args>
|
||||||
void format(Writer* w, string_view fmt, const Args&... args)
|
void format(Writer* w, string_view fmt, const Args&... args)
|
||||||
{
|
{
|
||||||
if constexpr (types_count<Args...> > 0)
|
if constexpr (types_count<Args...> > 0)
|
||||||
{
|
{
|
||||||
format_internals::type_erased_arg type_erased_args[] = {
|
format_internals::type_erased_arg type_erased_args[] = {
|
||||||
format_internals::type_erased_arg(args)...
|
format_internals::type_erased_arg(args)...
|
||||||
};
|
};
|
||||||
|
|
||||||
format_internals::format(w, fmt, type_erased_args);
|
format_internals::format(w, fmt, type_erased_args);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
format_internals::format(w, fmt, {});
|
format_internals::format(w, fmt, {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<isize_t N>
|
template<isize_t N>
|
||||||
void AslFormat(Formatter& f, const char (&str)[N])
|
void AslFormat(Formatter& f, const char (&str)[N])
|
||||||
{
|
{
|
||||||
f.write(string_view(str, N - 1));
|
f.write(string_view(str, N - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AslFormat(Formatter& f, const char* str);
|
void AslFormat(Formatter& f, const char* str);
|
||||||
|
|
||||||
inline void AslFormat(Formatter& f, string_view sv)
|
inline void AslFormat(Formatter& f, string_view sv)
|
||||||
{
|
{
|
||||||
f.write(sv);
|
f.write(sv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AslFormat(Formatter& f, float);
|
void AslFormat(Formatter& f, float);
|
||||||
void AslFormat(Formatter& f, double);
|
void AslFormat(Formatter& f, double);
|
||||||
|
|
||||||
void AslFormat(Formatter& f, bool);
|
void AslFormat(Formatter& f, bool);
|
||||||
|
|
||||||
void AslFormat(Formatter& f, uint8_t);
|
void AslFormat(Formatter& f, uint8_t);
|
||||||
void AslFormat(Formatter& f, uint16_t);
|
void AslFormat(Formatter& f, uint16_t);
|
||||||
void AslFormat(Formatter& f, uint32_t);
|
void AslFormat(Formatter& f, uint32_t);
|
||||||
void AslFormat(Formatter& f, uint64_t);
|
void AslFormat(Formatter& f, uint64_t);
|
||||||
|
|
||||||
void AslFormat(Formatter& f, int8_t);
|
void AslFormat(Formatter& f, int8_t);
|
||||||
void AslFormat(Formatter& f, int16_t);
|
void AslFormat(Formatter& f, int16_t);
|
||||||
void AslFormat(Formatter& f, int32_t);
|
void AslFormat(Formatter& f, int32_t);
|
||||||
void AslFormat(Formatter& f, int64_t);
|
void AslFormat(Formatter& f, int64_t);
|
||||||
|
|
||||||
string_view format_uint64(uint64_t value, span<char, 20> buffer);
|
string_view format_uint64(uint64_t value, span<char, 20> buffer);
|
||||||
|
|
||||||
} // namespace asl
|
} // namespace asl
|
||||||
|
@ -1,98 +1,98 @@
|
|||||||
#include "asl/format.hpp"
|
#include "asl/format.hpp"
|
||||||
#include "asl/float.hpp"
|
#include "asl/float.hpp"
|
||||||
|
|
||||||
#define JKJ_STD_REPLACEMENT_NAMESPACE_DEFINED 0
|
#define JKJ_STD_REPLACEMENT_NAMESPACE_DEFINED 0
|
||||||
#define JKJ_STATIC_DATA_SECTION_DEFINED 0
|
#define JKJ_STATIC_DATA_SECTION_DEFINED 0
|
||||||
#include <dragonbox.h>
|
#include <dragonbox.h>
|
||||||
|
|
||||||
static constexpr isize_t kZeroCount = 100;
|
static constexpr isize_t kZeroCount = 100;
|
||||||
static constexpr char kZeros[kZeroCount] = {
|
static constexpr char kZeros[kZeroCount] = {
|
||||||
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
|
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
|
||||||
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
|
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
|
||||||
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
|
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
|
||||||
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
|
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
|
||||||
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
|
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
|
||||||
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
|
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
|
||||||
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
|
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
|
||||||
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
|
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
|
||||||
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
|
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
|
||||||
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
|
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
|
||||||
};
|
};
|
||||||
|
|
||||||
template<asl::is_floating_point T>
|
template<asl::is_floating_point T>
|
||||||
static void format_float(asl::Formatter& f, T value)
|
static void format_float(asl::Formatter& f, T value)
|
||||||
{
|
{
|
||||||
if (asl::is_infinity(value))
|
if (asl::is_infinity(value))
|
||||||
{
|
{
|
||||||
if (value > 0)
|
if (value > 0)
|
||||||
{
|
{
|
||||||
f.write("Infinity"_sv);
|
f.write("Infinity"_sv);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
f.write("-Infinity"_sv);
|
f.write("-Infinity"_sv);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value == static_cast<T>(0))
|
if (value == static_cast<T>(0))
|
||||||
{
|
{
|
||||||
f.write("0"_sv);
|
f.write("0"_sv);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asl::is_nan(value))
|
if (asl::is_nan(value))
|
||||||
{
|
{
|
||||||
f.write("NaN"_sv);
|
f.write("NaN"_sv);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto decimal = jkj::dragonbox::to_decimal(value);
|
auto decimal = jkj::dragonbox::to_decimal(value);
|
||||||
|
|
||||||
if (decimal.is_negative) { f.write("-"); }
|
if (decimal.is_negative) { f.write("-"); }
|
||||||
|
|
||||||
char buffer[20];
|
char buffer[20];
|
||||||
asl::string_view digits = asl::format_uint64(decimal.significand, buffer);
|
asl::string_view digits = asl::format_uint64(decimal.significand, buffer);
|
||||||
|
|
||||||
if (decimal.exponent >= 0)
|
if (decimal.exponent >= 0)
|
||||||
{
|
{
|
||||||
f.write(digits);
|
f.write(digits);
|
||||||
while (decimal.exponent > 0)
|
while (decimal.exponent > 0)
|
||||||
{
|
{
|
||||||
isize_t to_write = asl::min(static_cast<isize_t>(decimal.exponent), kZeroCount);
|
isize_t to_write = asl::min(static_cast<isize_t>(decimal.exponent), kZeroCount);
|
||||||
f.write(asl::string_view(kZeros, to_write));
|
f.write(asl::string_view(kZeros, to_write));
|
||||||
decimal.exponent -= to_write;
|
decimal.exponent -= to_write;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (digits.size() <= -decimal.exponent)
|
if (digits.size() <= -decimal.exponent)
|
||||||
{
|
{
|
||||||
f.write("0.");
|
f.write("0.");
|
||||||
decimal.exponent = -decimal.exponent - static_cast<int>(digits.size());
|
decimal.exponent = -decimal.exponent - static_cast<int>(digits.size());
|
||||||
while (decimal.exponent > 0)
|
while (decimal.exponent > 0)
|
||||||
{
|
{
|
||||||
isize_t to_write = asl::min(static_cast<isize_t>(decimal.exponent), kZeroCount);
|
isize_t to_write = asl::min(static_cast<isize_t>(decimal.exponent), kZeroCount);
|
||||||
f.write(asl::string_view(kZeros, to_write));
|
f.write(asl::string_view(kZeros, to_write));
|
||||||
decimal.exponent -= to_write;
|
decimal.exponent -= to_write;
|
||||||
}
|
}
|
||||||
f.write(digits);
|
f.write(digits);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
f.write(digits.first(digits.size() + decimal.exponent));
|
f.write(digits.first(digits.size() + decimal.exponent));
|
||||||
f.write(".");
|
f.write(".");
|
||||||
f.write(digits.last(-decimal.exponent));
|
f.write(digits.last(-decimal.exponent));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void asl::AslFormat(Formatter& f, float value)
|
void asl::AslFormat(Formatter& f, float value)
|
||||||
{
|
{
|
||||||
format_float(f, value);
|
format_float(f, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void asl::AslFormat(Formatter& f, double value)
|
void asl::AslFormat(Formatter& f, double value)
|
||||||
{
|
{
|
||||||
format_float(f, value);
|
format_float(f, value);
|
||||||
}
|
}
|
||||||
|
@ -1,65 +1,65 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "asl/meta.hpp"
|
#include "asl/meta.hpp"
|
||||||
#include "asl/utility.hpp"
|
#include "asl/utility.hpp"
|
||||||
|
|
||||||
namespace asl {
|
namespace asl {
|
||||||
|
|
||||||
template<typename... Args, typename C>
|
template<typename... Args, typename C>
|
||||||
constexpr auto invoke(is_func auto C::* f, auto&& self, Args&&... args)
|
constexpr auto invoke(is_func auto C::* f, auto&& self, Args&&... args)
|
||||||
requires requires {
|
requires requires {
|
||||||
(self.*f)(ASL_FWD(args)...);
|
(self.*f)(ASL_FWD(args)...);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
return (ASL_FWD(self).*f)(ASL_FWD(args)...);
|
return (ASL_FWD(self).*f)(ASL_FWD(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args, typename C>
|
template<typename... Args, typename C>
|
||||||
constexpr auto invoke(is_func auto C::* f, auto* self, Args&&... args)
|
constexpr auto invoke(is_func auto C::* f, auto* self, Args&&... args)
|
||||||
requires requires {
|
requires requires {
|
||||||
(self->*f)(ASL_FWD(args)...);
|
(self->*f)(ASL_FWD(args)...);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
return (self->*f)(ASL_FWD(args)...);
|
return (self->*f)(ASL_FWD(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args, typename C>
|
template<typename... Args, typename C>
|
||||||
constexpr auto invoke(is_object auto C::* m, auto&& self, Args&&...)
|
constexpr auto invoke(is_object auto C::* m, auto&& self, Args&&...)
|
||||||
requires (
|
requires (
|
||||||
sizeof...(Args) == 0 &&
|
sizeof...(Args) == 0 &&
|
||||||
requires { self.*m; }
|
requires { self.*m; }
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return ASL_FWD(self).*m;
|
return ASL_FWD(self).*m;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args, typename C>
|
template<typename... Args, typename C>
|
||||||
constexpr auto invoke(is_object auto C::* m, auto* self, Args&&...)
|
constexpr auto invoke(is_object auto C::* m, auto* self, Args&&...)
|
||||||
requires (
|
requires (
|
||||||
sizeof...(Args) == 0 &&
|
sizeof...(Args) == 0 &&
|
||||||
requires { self->*m; }
|
requires { self->*m; }
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return self->*m;
|
return self->*m;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
constexpr auto invoke(auto&& f, Args&&... args)
|
constexpr auto invoke(auto&& f, Args&&... args)
|
||||||
requires requires {
|
requires requires {
|
||||||
f(ASL_FWD(args)...);
|
f(ASL_FWD(args)...);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
return ASL_FWD(f)(ASL_FWD(args)...);
|
return ASL_FWD(f)(ASL_FWD(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F> struct _result_of_helper;
|
template<typename F> struct _result_of_helper;
|
||||||
|
|
||||||
template<typename R, typename... Args>
|
template<typename R, typename... Args>
|
||||||
struct _result_of_helper<R(Args...)>
|
struct _result_of_helper<R(Args...)>
|
||||||
{
|
{
|
||||||
using type = decltype(invoke(declval<R>(), declval<Args>()...));
|
using type = decltype(invoke(declval<R>(), declval<Args>()...));
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename F> using result_of_t = _result_of_helper<F>::type;
|
template<typename F> using result_of_t = _result_of_helper<F>::type;
|
||||||
|
|
||||||
} // namespace asl
|
} // namespace asl
|
||||||
|
276
asl/hash.hpp
276
asl/hash.hpp
@ -1,138 +1,138 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "asl/integers.hpp"
|
#include "asl/integers.hpp"
|
||||||
#include "asl/meta.hpp"
|
#include "asl/meta.hpp"
|
||||||
#include "asl/span.hpp"
|
#include "asl/span.hpp"
|
||||||
#include "asl/utility.hpp"
|
#include "asl/utility.hpp"
|
||||||
|
|
||||||
namespace asl::city_hash
|
namespace asl::city_hash
|
||||||
{
|
{
|
||||||
|
|
||||||
// Hash function for a byte array.
|
// Hash function for a byte array.
|
||||||
uint64_t CityHash64(const char *s, size_t len);
|
uint64_t CityHash64(const char *s, size_t len);
|
||||||
|
|
||||||
// Hash function for a byte array. For convenience, a 64-bit seed is also
|
// Hash function for a byte array. For convenience, a 64-bit seed is also
|
||||||
// hashed into the result.
|
// hashed into the result.
|
||||||
uint64_t CityHash64WithSeed(const char *s, size_t len, uint64_t seed);
|
uint64_t CityHash64WithSeed(const char *s, size_t len, uint64_t seed);
|
||||||
|
|
||||||
// Hash function for a byte array. For convenience, two seeds are also
|
// Hash function for a byte array. For convenience, two seeds are also
|
||||||
// hashed into the result.
|
// hashed into the result.
|
||||||
uint64_t CityHash64WithSeeds(const char *s, size_t len,
|
uint64_t CityHash64WithSeeds(const char *s, size_t len,
|
||||||
uint64_t seed0, uint64_t seed1);
|
uint64_t seed0, uint64_t seed1);
|
||||||
|
|
||||||
// Hash function for a byte array.
|
// Hash function for a byte array.
|
||||||
uint128_t CityHash128(const char *s, size_t len);
|
uint128_t CityHash128(const char *s, size_t len);
|
||||||
|
|
||||||
// Hash function for a byte array. For convenience, a 128-bit seed is also
|
// Hash function for a byte array. For convenience, a 128-bit seed is also
|
||||||
// hashed into the result.
|
// hashed into the result.
|
||||||
uint128_t CityHash128WithSeed(const char *s, size_t len, uint128_t seed);
|
uint128_t CityHash128WithSeed(const char *s, size_t len, uint128_t seed);
|
||||||
|
|
||||||
// Hash function for a byte array. Most useful in 32-bit binaries.
|
// Hash function for a byte array. Most useful in 32-bit binaries.
|
||||||
uint32_t CityHash32(const char *s, size_t len);
|
uint32_t CityHash32(const char *s, size_t len);
|
||||||
|
|
||||||
// Hash 128 input bits down to 64 bits of output.
|
// Hash 128 input bits down to 64 bits of output.
|
||||||
// This is intended to be a reasonably good hash function.
|
// This is intended to be a reasonably good hash function.
|
||||||
constexpr uint64_t Hash128to64(uint64_t high, uint64_t low)
|
constexpr uint64_t Hash128to64(uint64_t high, uint64_t low)
|
||||||
{
|
{
|
||||||
// Murmur-inspired hashing.
|
// Murmur-inspired hashing.
|
||||||
const uint64_t kMul = 0x9ddfea08eb382d69ULL;
|
const uint64_t kMul = 0x9ddfea08eb382d69ULL;
|
||||||
uint64_t a = (low ^ high) * kMul;
|
uint64_t a = (low ^ high) * kMul;
|
||||||
a ^= (a >> 47);
|
a ^= (a >> 47);
|
||||||
uint64_t b = (high ^ a) * kMul;
|
uint64_t b = (high ^ a) * kMul;
|
||||||
b ^= (b >> 47);
|
b ^= (b >> 47);
|
||||||
b *= kMul;
|
b *= kMul;
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash 128 input bits down to 64 bits of output.
|
// Hash 128 input bits down to 64 bits of output.
|
||||||
// This is intended to be a reasonably good hash function.
|
// This is intended to be a reasonably good hash function.
|
||||||
constexpr uint64_t Hash128to64(const uint128_t& x)
|
constexpr uint64_t Hash128to64(const uint128_t& x)
|
||||||
{
|
{
|
||||||
return Hash128to64(x.high, x.low);
|
return Hash128to64(x.high, x.low);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace asl::city_hash
|
} // namespace asl::city_hash
|
||||||
|
|
||||||
namespace asl
|
namespace asl
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename T, typename H>
|
template<typename T, typename H>
|
||||||
concept hashable_generic = requires(const T& value, H h)
|
concept hashable_generic = requires(const T& value, H h)
|
||||||
{
|
{
|
||||||
{ AslHashValue(h, value) } -> same_as<H>;
|
{ AslHashValue(h, value) } -> same_as<H>;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct HashState
|
struct HashState
|
||||||
{
|
{
|
||||||
uint128_t state{};
|
uint128_t state{};
|
||||||
|
|
||||||
constexpr HashState() = default;
|
constexpr HashState() = default;
|
||||||
explicit constexpr HashState(uint128_t s) : state{s} {}
|
explicit constexpr HashState(uint128_t s) : state{s} {}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static HashState combine_contiguous(HashState h, span<const T> s)
|
static HashState combine_contiguous(HashState h, span<const T> s)
|
||||||
{
|
{
|
||||||
if constexpr (uniquely_represented<T>)
|
if constexpr (uniquely_represented<T>)
|
||||||
{
|
{
|
||||||
auto bytes = as_bytes(s);
|
auto bytes = as_bytes(s);
|
||||||
auto hashed = city_hash::CityHash128WithSeed(
|
auto hashed = city_hash::CityHash128WithSeed(
|
||||||
reinterpret_cast<const char*>(bytes.data()),
|
reinterpret_cast<const char*>(bytes.data()),
|
||||||
static_cast<size_t>(bytes.size()),
|
static_cast<size_t>(bytes.size()),
|
||||||
h.state);
|
h.state);
|
||||||
return HashState{hashed};
|
return HashState{hashed};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (const auto& value: s)
|
for (const auto& value: s)
|
||||||
{
|
{
|
||||||
h = AslHashValue(ASL_MOVE(h), value);
|
h = AslHashValue(ASL_MOVE(h), value);
|
||||||
}
|
}
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr HashState combine(HashState h)
|
static constexpr HashState combine(HashState h)
|
||||||
{
|
{
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<hashable_generic<HashState> Arg, hashable_generic<HashState>... Remaining>
|
template<hashable_generic<HashState> Arg, hashable_generic<HashState>... Remaining>
|
||||||
static constexpr HashState combine(HashState h, const Arg& arg, const Remaining&... remaining)
|
static constexpr HashState combine(HashState h, const Arg& arg, const Remaining&... remaining)
|
||||||
{
|
{
|
||||||
return combine(AslHashValue(ASL_MOVE(h), arg), remaining...);
|
return combine(AslHashValue(ASL_MOVE(h), arg), remaining...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept hashable = hashable_generic<T, HashState>;
|
concept hashable = hashable_generic<T, HashState>;
|
||||||
|
|
||||||
template<typename H, uniquely_represented T>
|
template<typename H, uniquely_represented T>
|
||||||
constexpr H AslHashValue(H h, const T& value)
|
constexpr H AslHashValue(H h, const T& value)
|
||||||
{
|
{
|
||||||
return H::combine_contiguous(ASL_MOVE(h), span<const T>{&value, 1});
|
return H::combine_contiguous(ASL_MOVE(h), span<const T>{&value, 1});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename H>
|
template<typename H>
|
||||||
constexpr H AslHashValue(H h, bool value)
|
constexpr H AslHashValue(H h, bool value)
|
||||||
{
|
{
|
||||||
return AslHashValue(ASL_MOVE(h), value ? 1 : 0);
|
return AslHashValue(ASL_MOVE(h), value ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename H, typename T>
|
template<typename H, typename T>
|
||||||
constexpr void AslHashValue(H h, T*); // Don't hash pointers
|
constexpr void AslHashValue(H h, T*); // Don't hash pointers
|
||||||
|
|
||||||
template<typename H, hashable T>
|
template<typename H, hashable T>
|
||||||
constexpr H AslHashValue(H h, const span<T>& s)
|
constexpr H AslHashValue(H h, const span<T>& s)
|
||||||
{
|
{
|
||||||
return H::combine_contiguous(ASL_MOVE(h), span<const T>{s.data(), s.size()});
|
return H::combine_contiguous(ASL_MOVE(h), span<const T>{s.data(), s.size()});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<hashable T>
|
template<hashable T>
|
||||||
constexpr uint64_t hash_value(const T& value)
|
constexpr uint64_t hash_value(const T& value)
|
||||||
{
|
{
|
||||||
auto result = AslHashValue(HashState{}, value).state;
|
auto result = AslHashValue(HashState{}, value).state;
|
||||||
return city_hash::Hash128to64(result);
|
return city_hash::Hash128to64(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace asl
|
} // namespace asl
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
356
asl/hash_map.hpp
356
asl/hash_map.hpp
@ -1,178 +1,178 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "asl/meta.hpp"
|
#include "asl/meta.hpp"
|
||||||
#include "asl/utility.hpp"
|
#include "asl/utility.hpp"
|
||||||
#include "asl/hash.hpp"
|
#include "asl/hash.hpp"
|
||||||
#include "asl/allocator.hpp"
|
#include "asl/allocator.hpp"
|
||||||
#include "asl/hash_set.hpp"
|
#include "asl/hash_set.hpp"
|
||||||
|
|
||||||
namespace asl
|
namespace asl
|
||||||
{
|
{
|
||||||
|
|
||||||
namespace hash_map_internal
|
namespace hash_map_internal
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename K, typename V>
|
template<typename K, typename V>
|
||||||
struct Slot
|
struct Slot
|
||||||
{
|
{
|
||||||
K key;
|
K key;
|
||||||
V value;
|
V value;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<hashable K, typename V, key_hasher<K> KeyHasher>
|
template<hashable K, typename V, key_hasher<K> KeyHasher>
|
||||||
struct SlotHasher : public KeyHasher
|
struct SlotHasher : public KeyHasher
|
||||||
{
|
{
|
||||||
using KeyHasher::hash;
|
using KeyHasher::hash;
|
||||||
|
|
||||||
constexpr static uint64_t hash(const Slot<K, V>& slot)
|
constexpr static uint64_t hash(const Slot<K, V>& slot)
|
||||||
{
|
{
|
||||||
return KeyHasher::hash(slot.key);
|
return KeyHasher::hash(slot.key);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<equality_comparable K, typename V, key_comparator<K> KeyComparator>
|
template<equality_comparable K, typename V, key_comparator<K> KeyComparator>
|
||||||
struct SlotComparator : public KeyComparator
|
struct SlotComparator : public KeyComparator
|
||||||
{
|
{
|
||||||
using KeyComparator::eq;
|
using KeyComparator::eq;
|
||||||
|
|
||||||
constexpr static bool eq(const Slot<K, V>& a, const Slot<K, V>& b)
|
constexpr static bool eq(const Slot<K, V>& a, const Slot<K, V>& b)
|
||||||
{
|
{
|
||||||
return KeyComparator::eq(a.key, b.key);
|
return KeyComparator::eq(a.key, b.key);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr static bool eq(const Slot<K, V>& a, const K& b)
|
constexpr static bool eq(const Slot<K, V>& a, const K& b)
|
||||||
{
|
{
|
||||||
return KeyComparator::eq(a.key, b);
|
return KeyComparator::eq(a.key, b);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace hash_map_internal
|
} // namespace hash_map_internal
|
||||||
|
|
||||||
template<
|
template<
|
||||||
is_object K,
|
is_object K,
|
||||||
is_object V,
|
is_object V,
|
||||||
allocator Allocator = DefaultAllocator,
|
allocator Allocator = DefaultAllocator,
|
||||||
key_hasher<K> KeyHasher = default_key_hasher<K>,
|
key_hasher<K> KeyHasher = default_key_hasher<K>,
|
||||||
key_comparator<K> KeyComparator = default_key_comparator<K>
|
key_comparator<K> KeyComparator = default_key_comparator<K>
|
||||||
>
|
>
|
||||||
requires moveable<K> && moveable<V>
|
requires moveable<K> && moveable<V>
|
||||||
class hash_map : protected hash_set<
|
class hash_map : protected hash_set<
|
||||||
hash_map_internal::Slot<K, V>,
|
hash_map_internal::Slot<K, V>,
|
||||||
Allocator,
|
Allocator,
|
||||||
hash_map_internal::SlotHasher<K, V, KeyHasher>,
|
hash_map_internal::SlotHasher<K, V, KeyHasher>,
|
||||||
hash_map_internal::SlotComparator<K, V, KeyComparator>>
|
hash_map_internal::SlotComparator<K, V, KeyComparator>>
|
||||||
{
|
{
|
||||||
using Base =
|
using Base =
|
||||||
hash_set<
|
hash_set<
|
||||||
hash_map_internal::Slot<K, V>,
|
hash_map_internal::Slot<K, V>,
|
||||||
Allocator,
|
Allocator,
|
||||||
hash_map_internal::SlotHasher<K, V, KeyHasher>,
|
hash_map_internal::SlotHasher<K, V, KeyHasher>,
|
||||||
hash_map_internal::SlotComparator<K, V, KeyComparator>>;
|
hash_map_internal::SlotComparator<K, V, KeyComparator>>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr hash_map() requires default_constructible<Allocator> = default;
|
constexpr hash_map() requires default_constructible<Allocator> = default;
|
||||||
|
|
||||||
explicit constexpr hash_map(Allocator allocator)
|
explicit constexpr hash_map(Allocator allocator)
|
||||||
: Base{ASL_MOVE(allocator)}
|
: Base{ASL_MOVE(allocator)}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
hash_map(const hash_map&) requires copyable<K> && copyable<V> = default;
|
hash_map(const hash_map&) requires copyable<K> && copyable<V> = default;
|
||||||
|
|
||||||
hash_map& operator=(const hash_map&) requires copyable<K> && copyable<V> = default;
|
hash_map& operator=(const hash_map&) requires copyable<K> && copyable<V> = default;
|
||||||
|
|
||||||
hash_map(hash_map&&) = default;
|
hash_map(hash_map&&) = default;
|
||||||
|
|
||||||
hash_map& operator=(hash_map&&) = default;
|
hash_map& operator=(hash_map&&) = default;
|
||||||
|
|
||||||
~hash_map() = default;
|
~hash_map() = default;
|
||||||
|
|
||||||
using Base::destroy;
|
using Base::destroy;
|
||||||
|
|
||||||
using Base::clear;
|
using Base::clear;
|
||||||
|
|
||||||
using Base::size;
|
using Base::size;
|
||||||
|
|
||||||
using Base::remove;
|
using Base::remove;
|
||||||
|
|
||||||
using Base::contains;
|
using Base::contains;
|
||||||
|
|
||||||
template<typename U, typename Arg0, typename... Args1>
|
template<typename U, typename Arg0, typename... Args1>
|
||||||
requires
|
requires
|
||||||
key_hasher<KeyHasher, U> &&
|
key_hasher<KeyHasher, U> &&
|
||||||
key_comparator<KeyComparator, K, U> &&
|
key_comparator<KeyComparator, K, U> &&
|
||||||
constructible_from<K, U&&> &&
|
constructible_from<K, U&&> &&
|
||||||
constructible_from<V, Arg0&&, Args1&&...>
|
constructible_from<V, Arg0&&, Args1&&...>
|
||||||
void insert(U&& key, Arg0&& arg0, Args1&&... args1)
|
void insert(U&& key, Arg0&& arg0, Args1&&... args1)
|
||||||
{
|
{
|
||||||
Base::maybe_grow_to_fit_one_more();
|
Base::maybe_grow_to_fit_one_more();
|
||||||
|
|
||||||
auto result = Base::find_slot_insert(key);
|
auto result = Base::find_slot_insert(key);
|
||||||
|
|
||||||
// NOLINTBEGIN(*-pointer-arithmetic)
|
// NOLINTBEGIN(*-pointer-arithmetic)
|
||||||
|
|
||||||
ASL_ASSERT(result.first_available_index >= 0);
|
ASL_ASSERT(result.first_available_index >= 0);
|
||||||
|
|
||||||
if (result.already_present_index >= 0)
|
if (result.already_present_index >= 0)
|
||||||
{
|
{
|
||||||
if (result.already_present_index != result.first_available_index)
|
if (result.already_present_index != result.first_available_index)
|
||||||
{
|
{
|
||||||
ASL_ASSERT((Base::m_tags[result.first_available_index] & Base::kHasValue) == 0);
|
ASL_ASSERT((Base::m_tags[result.first_available_index] & Base::kHasValue) == 0);
|
||||||
|
|
||||||
Base::m_values[result.first_available_index].construct_unsafe(ASL_MOVE(Base::m_values[result.already_present_index].as_init_unsafe()));
|
Base::m_values[result.first_available_index].construct_unsafe(ASL_MOVE(Base::m_values[result.already_present_index].as_init_unsafe()));
|
||||||
Base::m_values[result.already_present_index].destroy_unsafe();
|
Base::m_values[result.already_present_index].destroy_unsafe();
|
||||||
|
|
||||||
Base::m_tags[result.first_available_index] = result.tag;
|
Base::m_tags[result.first_available_index] = result.tag;
|
||||||
Base::m_tags[result.already_present_index] = Base::kTombstone;
|
Base::m_tags[result.already_present_index] = Base::kTombstone;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_ASSERT(Base::m_tags[result.first_available_index] == result.tag);
|
ASL_ASSERT(Base::m_tags[result.first_available_index] == result.tag);
|
||||||
|
|
||||||
if constexpr (sizeof...(Args1) == 0 && assignable_from<V&, Arg0&&>)
|
if constexpr (sizeof...(Args1) == 0 && assignable_from<V&, Arg0&&>)
|
||||||
{
|
{
|
||||||
Base::m_values[result.first_available_index].as_init_unsafe().value = ASL_FWD(arg0);
|
Base::m_values[result.first_available_index].as_init_unsafe().value = ASL_FWD(arg0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Base::m_values[result.first_available_index].as_init_unsafe().value = ASL_MOVE(V{ASL_FWD(arg0), ASL_FWD(args1)...});
|
Base::m_values[result.first_available_index].as_init_unsafe().value = ASL_MOVE(V{ASL_FWD(arg0), ASL_FWD(args1)...});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ASL_ASSERT((Base::m_tags[result.first_available_index] & Base::kHasValue) == 0);
|
ASL_ASSERT((Base::m_tags[result.first_available_index] & Base::kHasValue) == 0);
|
||||||
Base::m_values[result.first_available_index].construct_unsafe(ASL_FWD(key), V{ASL_FWD(arg0), ASL_FWD(args1)...});
|
Base::m_values[result.first_available_index].construct_unsafe(ASL_FWD(key), V{ASL_FWD(arg0), ASL_FWD(args1)...});
|
||||||
Base::m_tags[result.first_available_index] = result.tag;
|
Base::m_tags[result.first_available_index] = result.tag;
|
||||||
Base::m_size += 1;
|
Base::m_size += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOLINTEND(*-pointer-arithmetic)
|
// NOLINTEND(*-pointer-arithmetic)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Todo(C++23) Deducing this
|
// @Todo(C++23) Deducing this
|
||||||
template<typename U>
|
template<typename U>
|
||||||
requires key_hasher<KeyHasher, U> && key_comparator<KeyComparator, K, U>
|
requires key_hasher<KeyHasher, U> && key_comparator<KeyComparator, K, U>
|
||||||
const V* get(const U& value) const
|
const V* get(const U& value) const
|
||||||
{
|
{
|
||||||
isize_t index = Base::find_slot_lookup(value);
|
isize_t index = Base::find_slot_lookup(value);
|
||||||
if (index >= 0)
|
if (index >= 0)
|
||||||
{
|
{
|
||||||
// NOLINTNEXTLINE(*-pointer-arithmetic)
|
// NOLINTNEXTLINE(*-pointer-arithmetic)
|
||||||
return &Base::m_values[index].as_init_unsafe().value;
|
return &Base::m_values[index].as_init_unsafe().value;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
requires key_hasher<KeyHasher, U> && key_comparator<KeyComparator, K, U>
|
requires key_hasher<KeyHasher, U> && key_comparator<KeyComparator, K, U>
|
||||||
V* get(const U& value)
|
V* get(const U& value)
|
||||||
{
|
{
|
||||||
isize_t index = Base::find_slot_lookup(value);
|
isize_t index = Base::find_slot_lookup(value);
|
||||||
if (index >= 0)
|
if (index >= 0)
|
||||||
{
|
{
|
||||||
// NOLINTNEXTLINE(*-pointer-arithmetic)
|
// NOLINTNEXTLINE(*-pointer-arithmetic)
|
||||||
return &Base::m_values[index].as_init_unsafe().value;
|
return &Base::m_values[index].as_init_unsafe().value;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace asl
|
} // namespace asl
|
||||||
|
836
asl/hash_set.hpp
836
asl/hash_set.hpp
@ -1,418 +1,418 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "asl/annotations.hpp"
|
#include "asl/annotations.hpp"
|
||||||
#include "asl/meta.hpp"
|
#include "asl/meta.hpp"
|
||||||
#include "asl/utility.hpp"
|
#include "asl/utility.hpp"
|
||||||
#include "asl/maybe_uninit.hpp"
|
#include "asl/maybe_uninit.hpp"
|
||||||
#include "asl/hash.hpp"
|
#include "asl/hash.hpp"
|
||||||
#include "asl/allocator.hpp"
|
#include "asl/allocator.hpp"
|
||||||
#include "asl/memory.hpp"
|
#include "asl/memory.hpp"
|
||||||
|
|
||||||
namespace asl
|
namespace asl
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename H, typename T>
|
template<typename H, typename T>
|
||||||
concept key_hasher = requires (const T& value)
|
concept key_hasher = requires (const T& value)
|
||||||
{
|
{
|
||||||
{ H::hash(value) } -> same_as<uint64_t>;
|
{ H::hash(value) } -> same_as<uint64_t>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<hashable T>
|
template<hashable T>
|
||||||
struct default_key_hasher
|
struct default_key_hasher
|
||||||
{
|
{
|
||||||
constexpr static uint64_t hash(const T& value)
|
constexpr static uint64_t hash(const T& value)
|
||||||
{
|
{
|
||||||
return hash_value(value);
|
return hash_value(value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename C, typename U, typename V = U>
|
template<typename C, typename U, typename V = U>
|
||||||
concept key_comparator = requires(const U& a, const V& b)
|
concept key_comparator = requires(const U& a, const V& b)
|
||||||
{
|
{
|
||||||
{ C::eq(a, b) } -> same_as<bool>;
|
{ C::eq(a, b) } -> same_as<bool>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<equality_comparable T>
|
template<equality_comparable T>
|
||||||
struct default_key_comparator
|
struct default_key_comparator
|
||||||
{
|
{
|
||||||
constexpr static bool eq(const T& a, const T& b)
|
constexpr static bool eq(const T& a, const T& b)
|
||||||
{
|
{
|
||||||
return a == b;
|
return a == b;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<
|
template<
|
||||||
is_object T,
|
is_object T,
|
||||||
allocator Allocator = DefaultAllocator,
|
allocator Allocator = DefaultAllocator,
|
||||||
key_hasher<T> KeyHasher = default_key_hasher<T>,
|
key_hasher<T> KeyHasher = default_key_hasher<T>,
|
||||||
key_comparator<T> KeyComparator = default_key_comparator<T>
|
key_comparator<T> KeyComparator = default_key_comparator<T>
|
||||||
>
|
>
|
||||||
requires moveable<T>
|
requires moveable<T>
|
||||||
class hash_set
|
class hash_set
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
static constexpr uint8_t kHasValue = 0x80;
|
static constexpr uint8_t kHasValue = 0x80;
|
||||||
static constexpr uint8_t kHashMask = 0x7f;
|
static constexpr uint8_t kHashMask = 0x7f;
|
||||||
static constexpr uint8_t kEmpty = 0x00;
|
static constexpr uint8_t kEmpty = 0x00;
|
||||||
static constexpr uint8_t kTombstone = 0x01;
|
static constexpr uint8_t kTombstone = 0x01;
|
||||||
|
|
||||||
static constexpr isize_t kMinCapacity = 8;
|
static constexpr isize_t kMinCapacity = 8;
|
||||||
|
|
||||||
// Important so we can memzero the tags
|
// Important so we can memzero the tags
|
||||||
static_assert(kEmpty == 0);
|
static_assert(kEmpty == 0);
|
||||||
|
|
||||||
uint8_t* m_tags{};
|
uint8_t* m_tags{};
|
||||||
maybe_uninit<T>* m_values{};
|
maybe_uninit<T>* m_values{};
|
||||||
isize_t m_capacity{};
|
isize_t m_capacity{};
|
||||||
isize_t m_size{};
|
isize_t m_size{};
|
||||||
|
|
||||||
ASL_NO_UNIQUE_ADDRESS Allocator m_allocator;
|
ASL_NO_UNIQUE_ADDRESS Allocator m_allocator;
|
||||||
|
|
||||||
constexpr isize_t max_size() const
|
constexpr isize_t max_size() const
|
||||||
{
|
{
|
||||||
// Max load factor is 75%
|
// Max load factor is 75%
|
||||||
return (m_capacity >> 1) + (m_capacity >> 2);
|
return (m_capacity >> 1) + (m_capacity >> 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static isize_t size_to_capacity(isize_t size)
|
static isize_t size_to_capacity(isize_t size)
|
||||||
{
|
{
|
||||||
ASL_ASSERT(size > 0);
|
ASL_ASSERT(size > 0);
|
||||||
return max<isize_t>(
|
return max<isize_t>(
|
||||||
kMinCapacity,
|
kMinCapacity,
|
||||||
static_cast<isize_t>(round_up_pow2((static_cast<uint64_t>(size) * 4 + 2) / 3)));
|
static_cast<isize_t>(round_up_pow2((static_cast<uint64_t>(size) * 4 + 2) / 3)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void insert_inner(
|
static void insert_inner(
|
||||||
T&& value,
|
T&& value,
|
||||||
uint8_t* tags,
|
uint8_t* tags,
|
||||||
maybe_uninit<T>* values,
|
maybe_uninit<T>* values,
|
||||||
isize_t capacity,
|
isize_t capacity,
|
||||||
isize_t* size)
|
isize_t* size)
|
||||||
{
|
{
|
||||||
ASL_ASSERT(*size < capacity);
|
ASL_ASSERT(*size < capacity);
|
||||||
|
|
||||||
const auto result = find_slot_insert(value, tags, values, capacity);
|
const auto result = find_slot_insert(value, tags, values, capacity);
|
||||||
|
|
||||||
// NOLINTBEGIN(*-pointer-arithmetic)
|
// NOLINTBEGIN(*-pointer-arithmetic)
|
||||||
|
|
||||||
ASL_ASSERT(result.first_available_index >= 0);
|
ASL_ASSERT(result.first_available_index >= 0);
|
||||||
|
|
||||||
if (result.already_present_index != result.first_available_index)
|
if (result.already_present_index != result.first_available_index)
|
||||||
{
|
{
|
||||||
ASL_ASSERT((tags[result.first_available_index] & kHasValue) == 0);
|
ASL_ASSERT((tags[result.first_available_index] & kHasValue) == 0);
|
||||||
if (result.already_present_index >= 0)
|
if (result.already_present_index >= 0)
|
||||||
{
|
{
|
||||||
ASL_ASSERT((tags[result.already_present_index] & kHasValue) != 0);
|
ASL_ASSERT((tags[result.already_present_index] & kHasValue) != 0);
|
||||||
values[result.already_present_index].destroy_unsafe();
|
values[result.already_present_index].destroy_unsafe();
|
||||||
tags[result.already_present_index] = kTombstone;
|
tags[result.already_present_index] = kTombstone;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*size += 1;
|
*size += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
values[result.first_available_index].construct_unsafe(ASL_MOVE(value));
|
values[result.first_available_index].construct_unsafe(ASL_MOVE(value));
|
||||||
tags[result.first_available_index] = result.tag;
|
tags[result.first_available_index] = result.tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOLINTEND(*-pointer-arithmetic)
|
// NOLINTEND(*-pointer-arithmetic)
|
||||||
}
|
}
|
||||||
|
|
||||||
void grow_and_rehash()
|
void grow_and_rehash()
|
||||||
{
|
{
|
||||||
grow_and_rehash(max(kMinCapacity, m_capacity * 2));
|
grow_and_rehash(max(kMinCapacity, m_capacity * 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
void grow_and_rehash(isize_t new_capacity)
|
void grow_and_rehash(isize_t new_capacity)
|
||||||
{
|
{
|
||||||
ASL_ASSERT(new_capacity >= kMinCapacity && is_pow2(new_capacity) && new_capacity > m_capacity);
|
ASL_ASSERT(new_capacity >= kMinCapacity && is_pow2(new_capacity) && new_capacity > m_capacity);
|
||||||
|
|
||||||
auto* new_tags = reinterpret_cast<uint8_t*>(m_allocator.alloc(layout::array<uint8_t>(new_capacity)));
|
auto* new_tags = reinterpret_cast<uint8_t*>(m_allocator.alloc(layout::array<uint8_t>(new_capacity)));
|
||||||
auto* new_values = reinterpret_cast<maybe_uninit<T>*>(m_allocator.alloc(layout::array<maybe_uninit<T>>(new_capacity)));
|
auto* new_values = reinterpret_cast<maybe_uninit<T>*>(m_allocator.alloc(layout::array<maybe_uninit<T>>(new_capacity)));
|
||||||
asl::memzero(new_tags, new_capacity);
|
asl::memzero(new_tags, new_capacity);
|
||||||
|
|
||||||
isize_t new_size = 0;
|
isize_t new_size = 0;
|
||||||
|
|
||||||
if (m_size > 0)
|
if (m_size > 0)
|
||||||
{
|
{
|
||||||
// NOLINTBEGIN(*-pointer-arithmetic)
|
// NOLINTBEGIN(*-pointer-arithmetic)
|
||||||
for (isize_t i = 0; i < m_capacity; ++i)
|
for (isize_t i = 0; i < m_capacity; ++i)
|
||||||
{
|
{
|
||||||
if ((m_tags[i] & kHasValue) == 0) { continue; }
|
if ((m_tags[i] & kHasValue) == 0) { continue; }
|
||||||
|
|
||||||
insert_inner(ASL_MOVE(m_values[i].as_init_unsafe()), new_tags, new_values, new_capacity, &new_size);
|
insert_inner(ASL_MOVE(m_values[i].as_init_unsafe()), new_tags, new_values, new_capacity, &new_size);
|
||||||
|
|
||||||
// Destroy now so that destroy() has less things to do
|
// Destroy now so that destroy() has less things to do
|
||||||
m_values[i].destroy_unsafe();
|
m_values[i].destroy_unsafe();
|
||||||
m_tags[i] = kTombstone;
|
m_tags[i] = kTombstone;
|
||||||
}
|
}
|
||||||
// NOLINTEND(*-pointer-arithmetic)
|
// NOLINTEND(*-pointer-arithmetic)
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_ASSERT(new_size == m_size);
|
ASL_ASSERT(new_size == m_size);
|
||||||
|
|
||||||
m_size = 0;
|
m_size = 0;
|
||||||
destroy();
|
destroy();
|
||||||
|
|
||||||
m_tags = new_tags;
|
m_tags = new_tags;
|
||||||
m_values = new_values;
|
m_values = new_values;
|
||||||
m_capacity = new_capacity;
|
m_capacity = new_capacity;
|
||||||
m_size = new_size;
|
m_size = new_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear_values()
|
void clear_values()
|
||||||
{
|
{
|
||||||
if constexpr (!trivially_destructible<T>)
|
if constexpr (!trivially_destructible<T>)
|
||||||
{
|
{
|
||||||
if (m_size > 0)
|
if (m_size > 0)
|
||||||
{
|
{
|
||||||
for (isize_t i = 0; i < m_capacity; ++i)
|
for (isize_t i = 0; i < m_capacity; ++i)
|
||||||
{
|
{
|
||||||
if ((m_tags[i] & kHasValue) != 0) // NOLINT(*-pointer-arithmetic)
|
if ((m_tags[i] & kHasValue) != 0) // NOLINT(*-pointer-arithmetic)
|
||||||
{
|
{
|
||||||
m_values[i].destroy_unsafe(); // NOLINT(*-pointer-arithmetic)
|
m_values[i].destroy_unsafe(); // NOLINT(*-pointer-arithmetic)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void copy_from(const hash_set& other)
|
void copy_from(const hash_set& other)
|
||||||
{
|
{
|
||||||
if (other.size() > 0)
|
if (other.size() > 0)
|
||||||
{
|
{
|
||||||
isize_t min_capacity = size_to_capacity(other.size());
|
isize_t min_capacity = size_to_capacity(other.size());
|
||||||
if (m_capacity < min_capacity)
|
if (m_capacity < min_capacity)
|
||||||
{
|
{
|
||||||
grow_and_rehash(min_capacity);
|
grow_and_rehash(min_capacity);
|
||||||
}
|
}
|
||||||
ASL_ASSERT(m_capacity >= min_capacity);
|
ASL_ASSERT(m_capacity >= min_capacity);
|
||||||
|
|
||||||
for (isize_t i = 0; i < other.m_capacity; ++i)
|
for (isize_t i = 0; i < other.m_capacity; ++i)
|
||||||
{
|
{
|
||||||
if ((other.m_tags[i] & kHasValue) != 0) // NOLINT(*-pointer-arithmetic)
|
if ((other.m_tags[i] & kHasValue) != 0) // NOLINT(*-pointer-arithmetic)
|
||||||
{
|
{
|
||||||
insert(other.m_values[i].as_init_unsafe()); // NOLINT(*-pointer-arithmetic)
|
insert(other.m_values[i].as_init_unsafe()); // NOLINT(*-pointer-arithmetic)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FindSlotResult
|
struct FindSlotResult
|
||||||
{
|
{
|
||||||
uint8_t tag{};
|
uint8_t tag{};
|
||||||
isize_t first_available_index = -1;
|
isize_t first_available_index = -1;
|
||||||
isize_t already_present_index = -1;
|
isize_t already_present_index = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
requires key_hasher<KeyHasher, U> && key_comparator<KeyComparator, T, U>
|
requires key_hasher<KeyHasher, U> && key_comparator<KeyComparator, T, U>
|
||||||
static FindSlotResult find_slot_insert(
|
static FindSlotResult find_slot_insert(
|
||||||
const U& value,
|
const U& value,
|
||||||
const uint8_t* tags,
|
const uint8_t* tags,
|
||||||
const maybe_uninit<T>* values,
|
const maybe_uninit<T>* values,
|
||||||
isize_t capacity)
|
isize_t capacity)
|
||||||
{
|
{
|
||||||
ASL_ASSERT(is_pow2(capacity));
|
ASL_ASSERT(is_pow2(capacity));
|
||||||
|
|
||||||
FindSlotResult result{};
|
FindSlotResult result{};
|
||||||
|
|
||||||
const isize_t capacity_mask = capacity - 1;
|
const isize_t capacity_mask = capacity - 1;
|
||||||
const uint64_t hash = KeyHasher::hash(value);
|
const uint64_t hash = KeyHasher::hash(value);
|
||||||
const auto starting_index = static_cast<isize_t>(hash >> 7) & capacity_mask;
|
const auto starting_index = static_cast<isize_t>(hash >> 7) & capacity_mask;
|
||||||
|
|
||||||
result.tag = static_cast<uint8_t>(hash & kHashMask) | kHasValue;
|
result.tag = static_cast<uint8_t>(hash & kHashMask) | kHasValue;
|
||||||
|
|
||||||
// NOLINTBEGIN(*-pointer-arithmetic)
|
// NOLINTBEGIN(*-pointer-arithmetic)
|
||||||
|
|
||||||
for (
|
for (
|
||||||
isize_t i = starting_index;
|
isize_t i = starting_index;
|
||||||
i != starting_index || result.first_available_index < 0;
|
i != starting_index || result.first_available_index < 0;
|
||||||
i = (i + 1) & capacity_mask)
|
i = (i + 1) & capacity_mask)
|
||||||
{
|
{
|
||||||
uint8_t t = tags[i];
|
uint8_t t = tags[i];
|
||||||
|
|
||||||
if ((t & kHasValue) == 0 && result.first_available_index < 0)
|
if ((t & kHasValue) == 0 && result.first_available_index < 0)
|
||||||
{
|
{
|
||||||
result.first_available_index = i;
|
result.first_available_index = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t == result.tag && KeyComparator::eq(values[i].as_init_unsafe(), value))
|
if (t == result.tag && KeyComparator::eq(values[i].as_init_unsafe(), value))
|
||||||
{
|
{
|
||||||
ASL_ASSERT(result.already_present_index < 0);
|
ASL_ASSERT(result.already_present_index < 0);
|
||||||
result.already_present_index = i;
|
result.already_present_index = i;
|
||||||
if (result.first_available_index < 0)
|
if (result.first_available_index < 0)
|
||||||
{
|
{
|
||||||
result.first_available_index = i;
|
result.first_available_index = i;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t == kEmpty) { break; }
|
if (t == kEmpty) { break; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOLINTEND(*-pointer-arithmetic)
|
// NOLINTEND(*-pointer-arithmetic)
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
requires key_hasher<KeyHasher, U> && key_comparator<KeyComparator, T, U>
|
requires key_hasher<KeyHasher, U> && key_comparator<KeyComparator, T, U>
|
||||||
isize_t find_slot_lookup(const U& value) const
|
isize_t find_slot_lookup(const U& value) const
|
||||||
{
|
{
|
||||||
if (m_size <= 0) { return -1; };
|
if (m_size <= 0) { return -1; };
|
||||||
|
|
||||||
ASL_ASSERT(is_pow2(m_capacity));
|
ASL_ASSERT(is_pow2(m_capacity));
|
||||||
|
|
||||||
const isize_t capacity_mask = m_capacity - 1;
|
const isize_t capacity_mask = m_capacity - 1;
|
||||||
const uint64_t hash = KeyHasher::hash(value);
|
const uint64_t hash = KeyHasher::hash(value);
|
||||||
const uint8_t tag = static_cast<uint8_t>(hash & kHashMask) | kHasValue;
|
const uint8_t tag = static_cast<uint8_t>(hash & kHashMask) | kHasValue;
|
||||||
const auto starting_index = static_cast<isize_t>(hash >> 7) & capacity_mask;
|
const auto starting_index = static_cast<isize_t>(hash >> 7) & capacity_mask;
|
||||||
|
|
||||||
// NOLINTBEGIN(*-pointer-arithmetic)
|
// NOLINTBEGIN(*-pointer-arithmetic)
|
||||||
|
|
||||||
isize_t i = starting_index;
|
isize_t i = starting_index;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
const uint8_t t = m_tags[i];
|
const uint8_t t = m_tags[i];
|
||||||
|
|
||||||
if (t == tag && KeyComparator::eq(m_values[i].as_init_unsafe(), value)) { return i; }
|
if (t == tag && KeyComparator::eq(m_values[i].as_init_unsafe(), value)) { return i; }
|
||||||
if (t == kEmpty) { break; }
|
if (t == kEmpty) { break; }
|
||||||
|
|
||||||
i = (i + 1) & capacity_mask;
|
i = (i + 1) & capacity_mask;
|
||||||
} while (i != starting_index);
|
} while (i != starting_index);
|
||||||
|
|
||||||
// NOLINTEND(*-pointer-arithmetic)
|
// NOLINTEND(*-pointer-arithmetic)
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
requires key_hasher<KeyHasher, U> && key_comparator<KeyComparator, T, U>
|
requires key_hasher<KeyHasher, U> && key_comparator<KeyComparator, T, U>
|
||||||
FindSlotResult find_slot_insert(const U& value)
|
FindSlotResult find_slot_insert(const U& value)
|
||||||
{
|
{
|
||||||
return find_slot_insert(value, m_tags, m_values, m_capacity);
|
return find_slot_insert(value, m_tags, m_values, m_capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
void maybe_grow_to_fit_one_more()
|
void maybe_grow_to_fit_one_more()
|
||||||
{
|
{
|
||||||
if (m_size >= max_size())
|
if (m_size >= max_size())
|
||||||
{
|
{
|
||||||
grow_and_rehash();
|
grow_and_rehash();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr hash_set() requires default_constructible<Allocator>
|
constexpr hash_set() requires default_constructible<Allocator>
|
||||||
: m_allocator{}
|
: m_allocator{}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
explicit constexpr hash_set(Allocator allocator)
|
explicit constexpr hash_set(Allocator allocator)
|
||||||
: m_allocator{ASL_MOVE(allocator)}
|
: m_allocator{ASL_MOVE(allocator)}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
hash_set(const hash_set& other)
|
hash_set(const hash_set& other)
|
||||||
requires copy_constructible<Allocator> && copyable<T>
|
requires copy_constructible<Allocator> && copyable<T>
|
||||||
: hash_set{other.m_allocator}
|
: hash_set{other.m_allocator}
|
||||||
{
|
{
|
||||||
copy_from(other);
|
copy_from(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
hash_set& operator=(const hash_set& other)
|
hash_set& operator=(const hash_set& other)
|
||||||
requires copyable<T>
|
requires copyable<T>
|
||||||
{
|
{
|
||||||
if (&other != this)
|
if (&other != this)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
copy_from(other);
|
copy_from(other);
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
hash_set(hash_set&& other)
|
hash_set(hash_set&& other)
|
||||||
requires move_constructible<Allocator>
|
requires move_constructible<Allocator>
|
||||||
: m_tags{exchange(other.m_tags, nullptr)}
|
: m_tags{exchange(other.m_tags, nullptr)}
|
||||||
, m_values{exchange(other.m_values, nullptr)}
|
, m_values{exchange(other.m_values, nullptr)}
|
||||||
, m_capacity{exchange(other.m_capacity, 0)}
|
, m_capacity{exchange(other.m_capacity, 0)}
|
||||||
, m_size{exchange(other.m_size, 0)}
|
, m_size{exchange(other.m_size, 0)}
|
||||||
, m_allocator{ASL_MOVE(other.m_allocator)}
|
, m_allocator{ASL_MOVE(other.m_allocator)}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
hash_set& operator=(hash_set&& other)
|
hash_set& operator=(hash_set&& other)
|
||||||
{
|
{
|
||||||
if (&other != this)
|
if (&other != this)
|
||||||
{
|
{
|
||||||
destroy();
|
destroy();
|
||||||
m_tags = exchange(other.m_tags, nullptr);
|
m_tags = exchange(other.m_tags, nullptr);
|
||||||
m_values = exchange(other.m_values, nullptr);
|
m_values = exchange(other.m_values, nullptr);
|
||||||
m_capacity = exchange(other.m_capacity, 0);
|
m_capacity = exchange(other.m_capacity, 0);
|
||||||
m_size = exchange(other.m_size, 0);
|
m_size = exchange(other.m_size, 0);
|
||||||
m_allocator = ASL_MOVE(other.m_allocator);
|
m_allocator = ASL_MOVE(other.m_allocator);
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
~hash_set()
|
~hash_set()
|
||||||
{
|
{
|
||||||
destroy();
|
destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroy()
|
void destroy()
|
||||||
{
|
{
|
||||||
clear_values();
|
clear_values();
|
||||||
m_size = 0;
|
m_size = 0;
|
||||||
|
|
||||||
if (m_capacity > 0)
|
if (m_capacity > 0)
|
||||||
{
|
{
|
||||||
m_allocator.dealloc(m_tags, layout::array<uint8_t>(m_capacity));
|
m_allocator.dealloc(m_tags, layout::array<uint8_t>(m_capacity));
|
||||||
m_allocator.dealloc(m_values, layout::array<maybe_uninit<T>>(m_capacity));
|
m_allocator.dealloc(m_values, layout::array<maybe_uninit<T>>(m_capacity));
|
||||||
m_capacity = 0;
|
m_capacity = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
clear_values();
|
clear_values();
|
||||||
m_size = 0;
|
m_size = 0;
|
||||||
|
|
||||||
if (m_capacity > 0)
|
if (m_capacity > 0)
|
||||||
{
|
{
|
||||||
asl::memzero(m_tags, m_capacity);
|
asl::memzero(m_tags, m_capacity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr isize_t size() const { return m_size; }
|
constexpr isize_t size() const { return m_size; }
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
void insert(Args&&... args)
|
void insert(Args&&... args)
|
||||||
requires constructible_from<T, Args&&...>
|
requires constructible_from<T, Args&&...>
|
||||||
{
|
{
|
||||||
maybe_grow_to_fit_one_more();
|
maybe_grow_to_fit_one_more();
|
||||||
ASL_ASSERT(m_size < max_size());
|
ASL_ASSERT(m_size < max_size());
|
||||||
insert_inner(ASL_MOVE(T{ASL_FWD(args)...}), m_tags, m_values, m_capacity, &m_size);
|
insert_inner(ASL_MOVE(T{ASL_FWD(args)...}), m_tags, m_values, m_capacity, &m_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
requires key_hasher<KeyHasher, U> && key_comparator<KeyComparator, T, U>
|
requires key_hasher<KeyHasher, U> && key_comparator<KeyComparator, T, U>
|
||||||
bool contains(const U& value) const
|
bool contains(const U& value) const
|
||||||
{
|
{
|
||||||
return find_slot_lookup(value) >= 0;
|
return find_slot_lookup(value) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
requires key_hasher<KeyHasher, U> && key_comparator<KeyComparator, T, U>
|
requires key_hasher<KeyHasher, U> && key_comparator<KeyComparator, T, U>
|
||||||
bool remove(const U& value)
|
bool remove(const U& value)
|
||||||
{
|
{
|
||||||
isize_t slot = find_slot_lookup(value);
|
isize_t slot = find_slot_lookup(value);
|
||||||
if (slot < 0) { return false; }
|
if (slot < 0) { return false; }
|
||||||
|
|
||||||
m_values[slot].destroy_unsafe(); // NOLINT(*-pointer-arithmetic)
|
m_values[slot].destroy_unsafe(); // NOLINT(*-pointer-arithmetic)
|
||||||
m_tags[slot] = kTombstone; // NOLINT(*-pointer-arithmetic)
|
m_tags[slot] = kTombstone; // NOLINT(*-pointer-arithmetic)
|
||||||
m_size -= 1;
|
m_size -= 1;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace asl
|
} // namespace asl
|
||||||
|
|
||||||
|
@ -1,40 +1,40 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "asl/config.hpp"
|
#include "asl/config.hpp"
|
||||||
|
|
||||||
using int8_t = signed char;
|
using int8_t = signed char;
|
||||||
using int16_t = signed short;
|
using int16_t = signed short;
|
||||||
using int32_t = signed int;
|
using int32_t = signed int;
|
||||||
#if ASL_OS_WINDOWS
|
#if ASL_OS_WINDOWS
|
||||||
using int64_t = signed long long;
|
using int64_t = signed long long;
|
||||||
#elif ASL_OS_LINUX
|
#elif ASL_OS_LINUX
|
||||||
using int64_t = signed long;
|
using int64_t = signed long;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using uint8_t = unsigned char;
|
using uint8_t = unsigned char;
|
||||||
using uint16_t = unsigned short;
|
using uint16_t = unsigned short;
|
||||||
using uint32_t = unsigned int;
|
using uint32_t = unsigned int;
|
||||||
#if ASL_OS_WINDOWS
|
#if ASL_OS_WINDOWS
|
||||||
using uint64_t = unsigned long long;
|
using uint64_t = unsigned long long;
|
||||||
#elif ASL_OS_LINUX
|
#elif ASL_OS_LINUX
|
||||||
using uint64_t = unsigned long;
|
using uint64_t = unsigned long;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct uint128_t
|
struct uint128_t
|
||||||
{
|
{
|
||||||
uint64_t high;
|
uint64_t high;
|
||||||
uint64_t low;
|
uint64_t low;
|
||||||
};
|
};
|
||||||
|
|
||||||
using size_t = uint64_t;
|
using size_t = uint64_t;
|
||||||
using isize_t = int64_t;
|
using isize_t = int64_t;
|
||||||
|
|
||||||
using uintptr_t = size_t;
|
using uintptr_t = size_t;
|
||||||
|
|
||||||
namespace asl
|
namespace asl
|
||||||
{
|
{
|
||||||
|
|
||||||
enum class byte : uint8_t {};
|
enum class byte : uint8_t {};
|
||||||
|
|
||||||
} // namespace asl
|
} // namespace asl
|
||||||
|
|
||||||
|
38
asl/io.hpp
38
asl/io.hpp
@ -1,20 +1,20 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "asl/integers.hpp"
|
#include "asl/integers.hpp"
|
||||||
#include "asl/utility.hpp"
|
#include "asl/utility.hpp"
|
||||||
#include "asl/span.hpp"
|
#include "asl/span.hpp"
|
||||||
|
|
||||||
namespace asl
|
namespace asl
|
||||||
{
|
{
|
||||||
|
|
||||||
class Writer
|
class Writer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Writer() = default;
|
Writer() = default;
|
||||||
ASL_DELETE_COPY_MOVE(Writer);
|
ASL_DELETE_COPY_MOVE(Writer);
|
||||||
virtual ~Writer() = default;
|
virtual ~Writer() = default;
|
||||||
|
|
||||||
virtual void write(span<const byte>) = 0;
|
virtual void write(span<const byte>) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace asl
|
} // namespace asl
|
||||||
|
@ -1,37 +1,37 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "asl/integers.hpp"
|
#include "asl/integers.hpp"
|
||||||
#include "asl/meta.hpp"
|
#include "asl/meta.hpp"
|
||||||
|
|
||||||
namespace asl
|
namespace asl
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline constexpr isize_t size_of = static_cast<isize_t>(sizeof(T));
|
inline constexpr isize_t size_of = static_cast<isize_t>(sizeof(T));
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline constexpr isize_t align_of = static_cast<isize_t>(alignof(T));
|
inline constexpr isize_t align_of = static_cast<isize_t>(alignof(T));
|
||||||
|
|
||||||
struct layout
|
struct layout
|
||||||
{
|
{
|
||||||
isize_t size;
|
isize_t size;
|
||||||
isize_t align;
|
isize_t align;
|
||||||
|
|
||||||
constexpr bool operator==(const layout&) const = default;
|
constexpr bool operator==(const layout&) const = default;
|
||||||
|
|
||||||
template<is_object T>
|
template<is_object T>
|
||||||
static constexpr layout of()
|
static constexpr layout of()
|
||||||
{
|
{
|
||||||
return layout{ size_of<T>, align_of<T> };
|
return layout{ size_of<T>, align_of<T> };
|
||||||
}
|
}
|
||||||
|
|
||||||
template<is_object T>
|
template<is_object T>
|
||||||
static constexpr layout array(isize_t size)
|
static constexpr layout array(isize_t size)
|
||||||
{
|
{
|
||||||
return layout{ size_of<T> * size, align_of<T> };
|
return layout{ size_of<T> * size, align_of<T> };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace asl
|
} // namespace asl
|
||||||
|
|
||||||
#define AslOffsetOf(S, M) (static_cast<isize_t>(__builtin_offsetof(S, M)))
|
#define AslOffsetOf(S, M) (static_cast<isize_t>(__builtin_offsetof(S, M)))
|
||||||
|
@ -1,26 +1,26 @@
|
|||||||
cc_library(
|
cc_library(
|
||||||
name = "log",
|
name = "log",
|
||||||
srcs = [
|
srcs = [
|
||||||
"log.hpp",
|
"log.hpp",
|
||||||
],
|
],
|
||||||
hdrs = [
|
hdrs = [
|
||||||
"log.cpp",
|
"log.cpp",
|
||||||
],
|
],
|
||||||
deps = [
|
deps = [
|
||||||
"//asl",
|
"//asl",
|
||||||
],
|
],
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
|
|
||||||
cc_test(
|
cc_test(
|
||||||
name = "tests",
|
name = "tests",
|
||||||
srcs = [
|
srcs = [
|
||||||
"log_tests.cpp"
|
"log_tests.cpp"
|
||||||
],
|
],
|
||||||
deps = [
|
deps = [
|
||||||
":log",
|
":log",
|
||||||
"//asl/testing",
|
"//asl/testing",
|
||||||
],
|
],
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,72 +1,72 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "asl/meta.hpp"
|
#include "asl/meta.hpp"
|
||||||
#include "asl/utility.hpp"
|
#include "asl/utility.hpp"
|
||||||
#include "asl/memory.hpp"
|
#include "asl/memory.hpp"
|
||||||
|
|
||||||
namespace asl
|
namespace asl
|
||||||
{
|
{
|
||||||
|
|
||||||
template<is_object T>
|
template<is_object T>
|
||||||
union maybe_uninit
|
union maybe_uninit
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
T m_value;
|
T m_value;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr maybe_uninit() requires trivially_default_constructible<T> = default;
|
constexpr maybe_uninit() requires trivially_default_constructible<T> = default;
|
||||||
constexpr maybe_uninit() requires (!trivially_default_constructible<T>) {} // NOLINT
|
constexpr maybe_uninit() requires (!trivially_default_constructible<T>) {} // NOLINT
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
explicit constexpr maybe_uninit(in_place_t, Args&&... args)
|
explicit constexpr maybe_uninit(in_place_t, Args&&... args)
|
||||||
requires constructible_from<T, Args&&...>
|
requires constructible_from<T, Args&&...>
|
||||||
: m_value{ASL_FWD(args)...}
|
: m_value{ASL_FWD(args)...}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
constexpr maybe_uninit(const maybe_uninit&) requires trivially_copy_constructible<T> = default;
|
constexpr maybe_uninit(const maybe_uninit&) requires trivially_copy_constructible<T> = default;
|
||||||
constexpr maybe_uninit(const maybe_uninit&) requires (!trivially_copy_constructible<T>) {} // NOLINT
|
constexpr maybe_uninit(const maybe_uninit&) requires (!trivially_copy_constructible<T>) {} // NOLINT
|
||||||
|
|
||||||
constexpr maybe_uninit(maybe_uninit&&) requires trivially_move_constructible<T> = default;
|
constexpr maybe_uninit(maybe_uninit&&) requires trivially_move_constructible<T> = default;
|
||||||
constexpr maybe_uninit(maybe_uninit&&) requires (!trivially_move_constructible<T>) {} // NOLINT
|
constexpr maybe_uninit(maybe_uninit&&) requires (!trivially_move_constructible<T>) {} // NOLINT
|
||||||
|
|
||||||
constexpr maybe_uninit& operator=(const maybe_uninit&) requires trivially_copy_assignable<T> = default;
|
constexpr maybe_uninit& operator=(const maybe_uninit&) requires trivially_copy_assignable<T> = default;
|
||||||
constexpr maybe_uninit& operator=(const maybe_uninit&) requires (!trivially_copy_assignable<T>) {}
|
constexpr maybe_uninit& operator=(const maybe_uninit&) requires (!trivially_copy_assignable<T>) {}
|
||||||
|
|
||||||
constexpr maybe_uninit& operator=(maybe_uninit&&) requires trivially_move_assignable<T> = default;
|
constexpr maybe_uninit& operator=(maybe_uninit&&) requires trivially_move_assignable<T> = default;
|
||||||
constexpr maybe_uninit& operator=(maybe_uninit&&) requires (!trivially_move_assignable<T>) {}
|
constexpr maybe_uninit& operator=(maybe_uninit&&) requires (!trivially_move_assignable<T>) {}
|
||||||
|
|
||||||
constexpr ~maybe_uninit() requires trivially_destructible<T> = default;
|
constexpr ~maybe_uninit() requires trivially_destructible<T> = default;
|
||||||
constexpr ~maybe_uninit() requires (!trivially_destructible<T>) {} // NOLINT
|
constexpr ~maybe_uninit() requires (!trivially_destructible<T>) {} // NOLINT
|
||||||
|
|
||||||
// @Safety Value must not have been initialized yet
|
// @Safety Value must not have been initialized yet
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
constexpr void construct_unsafe(Args&&... args)
|
constexpr void construct_unsafe(Args&&... args)
|
||||||
requires constructible_from<T, Args&&...>
|
requires constructible_from<T, Args&&...>
|
||||||
{
|
{
|
||||||
construct_at<T>(&m_value, ASL_FWD(args)...);
|
construct_at<T>(&m_value, ASL_FWD(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Safety Value must have been initialized
|
// @Safety Value must have been initialized
|
||||||
template<typename U>
|
template<typename U>
|
||||||
constexpr void assign_unsafe(U&& value)
|
constexpr void assign_unsafe(U&& value)
|
||||||
requires assignable_from<T&, U&&>
|
requires assignable_from<T&, U&&>
|
||||||
{
|
{
|
||||||
m_value = ASL_FWD(value);
|
m_value = ASL_FWD(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Safety Value must have been initialized
|
// @Safety Value must have been initialized
|
||||||
constexpr void destroy_unsafe()
|
constexpr void destroy_unsafe()
|
||||||
{
|
{
|
||||||
if constexpr (!trivially_destructible<T>)
|
if constexpr (!trivially_destructible<T>)
|
||||||
{
|
{
|
||||||
destroy(&m_value);
|
destroy(&m_value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Safety Value must have been initialized
|
// @Safety Value must have been initialized
|
||||||
constexpr const T& as_init_unsafe() const& { return m_value; }
|
constexpr const T& as_init_unsafe() const& { return m_value; }
|
||||||
constexpr T& as_init_unsafe() & { return m_value; }
|
constexpr T& as_init_unsafe() & { return m_value; }
|
||||||
constexpr T&& as_init_unsafe() && { return ASL_MOVE(m_value); }
|
constexpr T&& as_init_unsafe() && { return ASL_MOVE(m_value); }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace asl
|
} // namespace asl
|
||||||
|
274
asl/memory.hpp
274
asl/memory.hpp
@ -1,137 +1,137 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "asl/integers.hpp"
|
#include "asl/integers.hpp"
|
||||||
#include "asl/meta.hpp"
|
#include "asl/meta.hpp"
|
||||||
#include "asl/layout.hpp"
|
#include "asl/layout.hpp"
|
||||||
#include "asl/utility.hpp"
|
#include "asl/utility.hpp"
|
||||||
|
|
||||||
constexpr void* operator new(size_t, void* ptr)
|
constexpr void* operator new(size_t, void* ptr)
|
||||||
{
|
{
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace asl
|
namespace asl
|
||||||
{
|
{
|
||||||
|
|
||||||
constexpr isize_t memcmp(const void* a, const void* b, isize_t size)
|
constexpr isize_t memcmp(const void* a, const void* b, isize_t size)
|
||||||
{
|
{
|
||||||
return __builtin_memcmp(a, b, static_cast<size_t>(size));
|
return __builtin_memcmp(a, b, static_cast<size_t>(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void memcpy(void* dst, const void* src, isize_t size)
|
constexpr void memcpy(void* dst, const void* src, isize_t size)
|
||||||
{
|
{
|
||||||
__builtin_memcpy(dst, src, static_cast<size_t>(size));
|
__builtin_memcpy(dst, src, static_cast<size_t>(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void memzero(void* dst, isize_t size)
|
inline void memzero(void* dst, isize_t size)
|
||||||
{
|
{
|
||||||
__builtin_memset(dst, 0, static_cast<size_t>(size));
|
__builtin_memset(dst, 0, static_cast<size_t>(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr isize_t strlen(const char* s)
|
constexpr isize_t strlen(const char* s)
|
||||||
{
|
{
|
||||||
return static_cast<isize_t>(__builtin_strlen(s));
|
return static_cast<isize_t>(__builtin_strlen(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename... Args>
|
template<typename T, typename... Args>
|
||||||
constexpr T* construct_at(void* ptr, Args&&... args)
|
constexpr T* construct_at(void* ptr, Args&&... args)
|
||||||
requires constructible_from<T, Args&&...>
|
requires constructible_from<T, Args&&...>
|
||||||
{
|
{
|
||||||
return new (ptr) T{ ASL_FWD(args)... };
|
return new (ptr) T{ ASL_FWD(args)... };
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr void destroy(T* data)
|
constexpr void destroy(T* data)
|
||||||
{
|
{
|
||||||
if constexpr (!trivially_destructible<T>)
|
if constexpr (!trivially_destructible<T>)
|
||||||
{
|
{
|
||||||
data->~T();
|
data->~T();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr void destroy_n(T* data, isize_t n)
|
constexpr void destroy_n(T* data, isize_t n)
|
||||||
{
|
{
|
||||||
if constexpr (!trivially_destructible<T>)
|
if constexpr (!trivially_destructible<T>)
|
||||||
{
|
{
|
||||||
for (isize_t i = 0; i < n; ++i)
|
for (isize_t i = 0; i < n; ++i)
|
||||||
{
|
{
|
||||||
destroy(data + i);
|
destroy(data + i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<copy_constructible T>
|
template<copy_constructible T>
|
||||||
constexpr void copy_uninit_n(T* to, const T* from, isize_t n)
|
constexpr void copy_uninit_n(T* to, const T* from, isize_t n)
|
||||||
{
|
{
|
||||||
if constexpr (trivially_copy_constructible<T>)
|
if constexpr (trivially_copy_constructible<T>)
|
||||||
{
|
{
|
||||||
memcpy(to, from, size_of<T> * n);
|
memcpy(to, from, size_of<T> * n);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (isize_t i = 0; i < n; ++i)
|
for (isize_t i = 0; i < n; ++i)
|
||||||
{
|
{
|
||||||
// NOLINTNEXTLINE(*-pointer-arithmetic)
|
// NOLINTNEXTLINE(*-pointer-arithmetic)
|
||||||
construct_at<T>(to + i, from[i]);
|
construct_at<T>(to + i, from[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<copy_assignable T>
|
template<copy_assignable T>
|
||||||
constexpr void copy_assign_n(T* to, const T* from, isize_t n)
|
constexpr void copy_assign_n(T* to, const T* from, isize_t n)
|
||||||
{
|
{
|
||||||
if constexpr (trivially_copy_constructible<T>)
|
if constexpr (trivially_copy_constructible<T>)
|
||||||
{
|
{
|
||||||
memcpy(to, from, size_of<T> * n);
|
memcpy(to, from, size_of<T> * n);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (isize_t i = 0; i < n; ++i)
|
for (isize_t i = 0; i < n; ++i)
|
||||||
{
|
{
|
||||||
// NOLINTNEXTLINE(*-pointer-arithmetic)
|
// NOLINTNEXTLINE(*-pointer-arithmetic)
|
||||||
to[i] = from[i];
|
to[i] = from[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<move_constructible T>
|
template<move_constructible T>
|
||||||
constexpr void relocate_uninit_n(T* to, T* from, isize_t n)
|
constexpr void relocate_uninit_n(T* to, T* from, isize_t n)
|
||||||
{
|
{
|
||||||
if constexpr (trivially_move_constructible<T>)
|
if constexpr (trivially_move_constructible<T>)
|
||||||
{
|
{
|
||||||
static_assert(trivially_destructible<T>);
|
static_assert(trivially_destructible<T>);
|
||||||
memcpy(to, from, size_of<T> * n);
|
memcpy(to, from, size_of<T> * n);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (isize_t i = 0; i < n; ++i)
|
for (isize_t i = 0; i < n; ++i)
|
||||||
{
|
{
|
||||||
// NOLINTNEXTLINE(*-pointer-arithmetic)
|
// NOLINTNEXTLINE(*-pointer-arithmetic)
|
||||||
construct_at<T>(to + i, ASL_MOVE(from[i]));
|
construct_at<T>(to + i, ASL_MOVE(from[i]));
|
||||||
}
|
}
|
||||||
destroy_n(from, n);
|
destroy_n(from, n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<move_assignable T>
|
template<move_assignable T>
|
||||||
constexpr void relocate_assign_n(T* to, T* from, isize_t n)
|
constexpr void relocate_assign_n(T* to, T* from, isize_t n)
|
||||||
{
|
{
|
||||||
if constexpr (trivially_move_assignable<T>)
|
if constexpr (trivially_move_assignable<T>)
|
||||||
{
|
{
|
||||||
static_assert(trivially_destructible<T>);
|
static_assert(trivially_destructible<T>);
|
||||||
memcpy(to, from, size_of<T> * n);
|
memcpy(to, from, size_of<T> * n);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (isize_t i = 0; i < n; ++i)
|
for (isize_t i = 0; i < n; ++i)
|
||||||
{
|
{
|
||||||
// NOLINTNEXTLINE(*-pointer-arithmetic)
|
// NOLINTNEXTLINE(*-pointer-arithmetic)
|
||||||
to[i] = ASL_MOVE(from[i]);
|
to[i] = ASL_MOVE(from[i]);
|
||||||
}
|
}
|
||||||
destroy_n(from, n);
|
destroy_n(from, n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace asl
|
} // namespace asl
|
||||||
|
|
||||||
|
442
asl/meta.hpp
442
asl/meta.hpp
@ -1,221 +1,221 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "asl/integers.hpp"
|
#include "asl/integers.hpp"
|
||||||
|
|
||||||
namespace asl {
|
namespace asl {
|
||||||
|
|
||||||
struct source_location
|
struct source_location
|
||||||
{
|
{
|
||||||
const char* file;
|
const char* file;
|
||||||
int line;
|
int line;
|
||||||
|
|
||||||
explicit source_location(
|
explicit source_location(
|
||||||
const char* file_ = __builtin_FILE(),
|
const char* file_ = __builtin_FILE(),
|
||||||
int line_ = __builtin_LINE())
|
int line_ = __builtin_LINE())
|
||||||
: file{file_}
|
: file{file_}
|
||||||
, line{line_}
|
, line{line_}
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct empty {};
|
struct empty {};
|
||||||
|
|
||||||
template<typename T> struct id { using type = T; };
|
template<typename T> struct id { using type = T; };
|
||||||
|
|
||||||
template<typename... Args> static constexpr isize_t types_count = sizeof...(Args);
|
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<typename T, T kValue> struct integral_constant { static constexpr T value = kValue; };
|
||||||
template<bool B> using bool_constant = integral_constant<bool, B>;
|
template<bool B> using bool_constant = integral_constant<bool, B>;
|
||||||
|
|
||||||
using true_type = bool_constant<true>;
|
using true_type = bool_constant<true>;
|
||||||
using false_type = bool_constant<false>;
|
using false_type = bool_constant<false>;
|
||||||
|
|
||||||
template<bool kSelect, typename U, typename V> struct _select_helper { using type = V; };
|
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<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<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 U, typename V> struct _same_as_helper : false_type {};
|
||||||
template<typename T> struct _same_as_helper<T, T> : true_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 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(int) -> id<T&>;
|
||||||
template<typename T> auto _as_lref_helper(...) -> 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(int) -> id<T&&>;
|
||||||
template<typename T> auto _as_rref_helper(...) -> 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_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> using as_rref_t = decltype(_as_rref_helper<T>(0))::type;
|
||||||
|
|
||||||
template<typename T> consteval as_rref_t<T> declval() {}
|
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 { 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> 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> using un_ref_t = _un_ref_t<T>::type;
|
||||||
|
|
||||||
template<typename T, typename... Args> concept constructible_from = __is_constructible(T, Args...);
|
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 default_constructible = constructible_from<T>;
|
||||||
template<typename T> concept copy_constructible = constructible_from<T, as_lref_t<const 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> 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, 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_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_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> 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, 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 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> 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, 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_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_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 trivially_destructible = __is_trivially_destructible(T);
|
||||||
|
|
||||||
template<typename T> concept copyable = copy_constructible<T> && copy_assignable<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 T> concept moveable = move_constructible<T> && move_assignable<T>;
|
||||||
|
|
||||||
template<typename To, typename From>
|
template<typename To, typename From>
|
||||||
concept convertible_from = __is_convertible(From, To);
|
concept convertible_from = __is_convertible(From, To);
|
||||||
|
|
||||||
template<typename Derived, class Base>
|
template<typename Derived, class Base>
|
||||||
concept derived_from = __is_class(Derived) && __is_class(Base) && convertible_from<const volatile Base*, const volatile Derived*>;
|
concept derived_from = __is_class(Derived) && __is_class(Base) && convertible_from<const volatile Base*, const volatile Derived*>;
|
||||||
|
|
||||||
using nullptr_t = decltype(nullptr);
|
using nullptr_t = decltype(nullptr);
|
||||||
|
|
||||||
template<typename T> struct _un_const_helper { using type = T; };
|
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> struct _un_const_helper<const T> { using type = T; };
|
||||||
|
|
||||||
template<typename T> using un_const_t = _un_const_helper<T>::type;
|
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 : false_type {};
|
||||||
template<typename T> struct _is_const_helper<const T> : true_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> 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 { using type = T; };
|
||||||
template<typename T> struct _un_volatile_helper<volatile T> { 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_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_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> 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> 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 { 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 = 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> 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_ref = _is_ref_helper<T>::l || _is_ref_helper<T>::r;
|
||||||
|
|
||||||
template<typename T> struct _is_ptr_helper : false_type {};
|
template<typename T> struct _is_ptr_helper : false_type {};
|
||||||
template<typename T> struct _is_ptr_helper<T*> : true_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> concept is_ptr = _is_ptr_helper<un_cv_t<T>>::value;
|
||||||
|
|
||||||
template<typename T> struct _tame_helper { using type = T; };
|
template<typename T> struct _tame_helper { using type = T; };
|
||||||
|
|
||||||
#define TAME_HELPER_IMPL(TRAILING) \
|
#define TAME_HELPER_IMPL(TRAILING) \
|
||||||
template<typename R, typename... Args> \
|
template<typename R, typename... Args> \
|
||||||
struct _tame_helper<R(Args...) TRAILING> { using type = R(Args...); }
|
struct _tame_helper<R(Args...) TRAILING> { using type = R(Args...); }
|
||||||
|
|
||||||
TAME_HELPER_IMPL();
|
TAME_HELPER_IMPL();
|
||||||
TAME_HELPER_IMPL(&);
|
TAME_HELPER_IMPL(&);
|
||||||
TAME_HELPER_IMPL(&&);
|
TAME_HELPER_IMPL(&&);
|
||||||
TAME_HELPER_IMPL(const);
|
TAME_HELPER_IMPL(const);
|
||||||
TAME_HELPER_IMPL(const &);
|
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(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(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(& 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(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(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);
|
TAME_HELPER_IMPL(const volatile & noexcept);
|
||||||
TAME_HELPER_IMPL(const volatile && noexcept);
|
TAME_HELPER_IMPL(const volatile && noexcept);
|
||||||
|
|
||||||
#undef TAME_HELPER_IMPL
|
#undef TAME_HELPER_IMPL
|
||||||
|
|
||||||
template<typename T> using tame_t = _tame_helper<T>::type;
|
template<typename T> using tame_t = _tame_helper<T>::type;
|
||||||
|
|
||||||
template<typename T> struct _is_func_helper : false_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 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_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> 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 : false_type {};
|
||||||
template<typename T> struct _is_array_helper<T[]> : true_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, int N> struct _is_array_helper<T[N]> : true_type {};
|
||||||
|
|
||||||
template<typename T> concept is_array = _is_array_helper<T>::value;
|
template<typename T> concept is_array = _is_array_helper<T>::value;
|
||||||
|
|
||||||
template<typename T> struct _is_floating_point_helper : false_type {};
|
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<float> : true_type {};
|
||||||
template<> struct _is_floating_point_helper<double> : 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> concept is_floating_point = _is_floating_point_helper<un_cv_t<T>>::value;
|
||||||
|
|
||||||
template<typename T> struct _is_integer_helper : false_type {};
|
template<typename T> struct _is_integer_helper : false_type {};
|
||||||
template<> struct _is_integer_helper<int8_t> : true_type {};
|
template<> struct _is_integer_helper<int8_t> : true_type {};
|
||||||
template<> struct _is_integer_helper<int16_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<int32_t> : true_type {};
|
||||||
template<> struct _is_integer_helper<int64_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<uint8_t> : true_type {};
|
||||||
template<> struct _is_integer_helper<uint16_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<uint32_t> : true_type {};
|
||||||
template<> struct _is_integer_helper<uint64_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_integer = _is_integer_helper<un_cv_t<T>>::value;
|
||||||
|
|
||||||
template<typename T> concept is_enum = __is_enum(T);
|
template<typename T> concept is_enum = __is_enum(T);
|
||||||
|
|
||||||
template<typename T> struct is_uniquely_represented : false_type {};
|
template<typename T> struct is_uniquely_represented : false_type {};
|
||||||
template<is_integer T> struct is_uniquely_represented<T> : true_type {};
|
template<is_integer T> struct is_uniquely_represented<T> : true_type {};
|
||||||
template<is_enum 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<uint128_t> : true_type {};
|
||||||
template<> struct is_uniquely_represented<byte> : 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> concept uniquely_represented = is_uniquely_represented<un_cv_t<T>>::value;
|
||||||
|
|
||||||
template<typename T, typename U>
|
template<typename T, typename U>
|
||||||
concept equality_comparable_with = requires (const un_cvref_t<T>& a, const un_cvref_t<U>& b)
|
concept equality_comparable_with = requires (const un_cvref_t<T>& a, const un_cvref_t<U>& b)
|
||||||
{
|
{
|
||||||
{ a == b } -> same_as<bool>;
|
{ a == b } -> same_as<bool>;
|
||||||
{ b == a } -> same_as<bool>;
|
{ b == a } -> same_as<bool>;
|
||||||
{ a != b } -> same_as<bool>;
|
{ a != b } -> same_as<bool>;
|
||||||
{ b != a } -> same_as<bool>;
|
{ b != a } -> same_as<bool>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T> concept equality_comparable = equality_comparable_with<T, T>;
|
template<typename T> concept equality_comparable = equality_comparable_with<T, T>;
|
||||||
|
|
||||||
struct niche_t {};
|
struct niche_t {};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept has_niche = constructible_from<T, niche_t> && equality_comparable_with<T, niche_t>;
|
concept has_niche = constructible_from<T, niche_t> && equality_comparable_with<T, niche_t>;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept is_niche = same_as<un_cvref_t<T>, niche_t>;
|
concept is_niche = same_as<un_cvref_t<T>, niche_t>;
|
||||||
|
|
||||||
} // namespace asl
|
} // namespace asl
|
||||||
|
1016
asl/option.hpp
1016
asl/option.hpp
File diff suppressed because it is too large
Load Diff
@ -1,31 +1,31 @@
|
|||||||
#include "asl/print.hpp"
|
#include "asl/print.hpp"
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
// @Todo Optimize this, maybe make buffered
|
// @Todo Optimize this, maybe make buffered
|
||||||
class ConsoleWriter : public asl::Writer
|
class ConsoleWriter : public asl::Writer
|
||||||
{
|
{
|
||||||
FILE* m_handle;
|
FILE* m_handle;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ConsoleWriter(FILE* handle)
|
explicit ConsoleWriter(FILE* handle)
|
||||||
: m_handle{handle}
|
: m_handle{handle}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void write(asl::span<const asl::byte> s) override
|
void write(asl::span<const asl::byte> s) override
|
||||||
{
|
{
|
||||||
fwrite(s.data(), 1, static_cast<size_t>(s.size()), m_handle);
|
fwrite(s.data(), 1, static_cast<size_t>(s.size()), m_handle);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
asl::Writer* asl::print_internals::get_stdout_writer()
|
asl::Writer* asl::print_internals::get_stdout_writer()
|
||||||
{
|
{
|
||||||
static ConsoleWriter s_writer{stdout};
|
static ConsoleWriter s_writer{stdout};
|
||||||
return &s_writer;
|
return &s_writer;
|
||||||
}
|
}
|
||||||
|
|
||||||
asl::Writer* asl::print_internals::get_stderr_writer()
|
asl::Writer* asl::print_internals::get_stderr_writer()
|
||||||
{
|
{
|
||||||
static ConsoleWriter s_writer{stderr};
|
static ConsoleWriter s_writer{stderr};
|
||||||
return &s_writer;
|
return &s_writer;
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,29 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "asl/format.hpp"
|
#include "asl/format.hpp"
|
||||||
|
|
||||||
namespace asl
|
namespace asl
|
||||||
{
|
{
|
||||||
|
|
||||||
namespace print_internals
|
namespace print_internals
|
||||||
{
|
{
|
||||||
|
|
||||||
// @Todo Make print writers thread safe
|
// @Todo Make print writers thread safe
|
||||||
Writer* get_stdout_writer();
|
Writer* get_stdout_writer();
|
||||||
Writer* get_stderr_writer();
|
Writer* get_stderr_writer();
|
||||||
|
|
||||||
} // namespace print_internals
|
} // namespace print_internals
|
||||||
|
|
||||||
template<formattable... Args>
|
template<formattable... Args>
|
||||||
void print(string_view fmt, const Args&... args)
|
void print(string_view fmt, const Args&... args)
|
||||||
{
|
{
|
||||||
format(print_internals::get_stdout_writer(), fmt, args...);
|
format(print_internals::get_stdout_writer(), fmt, args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<formattable... Args>
|
template<formattable... Args>
|
||||||
void eprint(string_view fmt, const Args&... args)
|
void eprint(string_view fmt, const Args&... args)
|
||||||
{
|
{
|
||||||
format(print_internals::get_stderr_writer(), fmt, args...);
|
format(print_internals::get_stderr_writer(), fmt, args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace asl
|
} // namespace asl
|
||||||
|
@ -49,7 +49,7 @@ class span
|
|||||||
{
|
{
|
||||||
return size < 0;
|
return size < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr bool kIsDynamic = is_dynamic(kSize);
|
static constexpr bool kIsDynamic = is_dynamic(kSize);
|
||||||
|
|
||||||
using SizeType = select_t<kIsDynamic, isize_t, empty>;
|
using SizeType = select_t<kIsDynamic, isize_t, empty>;
|
||||||
@ -102,7 +102,7 @@ public:
|
|||||||
|
|
||||||
constexpr span(const span&) = default;
|
constexpr span(const span&) = default;
|
||||||
constexpr span(span&&) = default;
|
constexpr span(span&&) = default;
|
||||||
|
|
||||||
constexpr span& operator=(const span&) = default;
|
constexpr span& operator=(const span&) = default;
|
||||||
constexpr span& operator=(span&&) = default;
|
constexpr span& operator=(span&&) = default;
|
||||||
|
|
||||||
@ -124,7 +124,7 @@ public:
|
|||||||
{
|
{
|
||||||
return contiguous_iterator{m_data};
|
return contiguous_iterator{m_data};
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr contiguous_iterator<T> end() const
|
constexpr contiguous_iterator<T> end() const
|
||||||
{
|
{
|
||||||
return contiguous_iterator{m_data + size()};
|
return contiguous_iterator{m_data + size()};
|
||||||
|
@ -73,7 +73,7 @@ void asl::status::unref()
|
|||||||
void asl::AslFormat(asl::Formatter& f, const asl::status& s)
|
void asl::AslFormat(asl::Formatter& f, const asl::status& s)
|
||||||
{
|
{
|
||||||
string_view status_str{};
|
string_view status_str{};
|
||||||
|
|
||||||
switch (s.code())
|
switch (s.code())
|
||||||
{
|
{
|
||||||
case status_code::ok: status_str = "ok"_sv; break;
|
case status_code::ok: status_str = "ok"_sv; break;
|
||||||
|
@ -54,13 +54,13 @@ class status
|
|||||||
|
|
||||||
void ref();
|
void ref();
|
||||||
void unref();
|
void unref();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr ~status()
|
constexpr ~status()
|
||||||
{
|
{
|
||||||
if (!is_inline()) { unref(); }
|
if (!is_inline()) { unref(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit constexpr status(status_code code)
|
explicit constexpr status(status_code code)
|
||||||
: m_payload{status_to_payload(code)}
|
: m_payload{status_to_payload(code)}
|
||||||
{}
|
{}
|
||||||
|
@ -1,179 +1,179 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "asl/status.hpp"
|
#include "asl/status.hpp"
|
||||||
#include "asl/maybe_uninit.hpp"
|
#include "asl/maybe_uninit.hpp"
|
||||||
#include "asl/hash.hpp"
|
#include "asl/hash.hpp"
|
||||||
|
|
||||||
namespace asl
|
namespace asl
|
||||||
{
|
{
|
||||||
|
|
||||||
template<is_object T>
|
template<is_object T>
|
||||||
class status_or
|
class status_or
|
||||||
{
|
{
|
||||||
status m_status;
|
status m_status;
|
||||||
maybe_uninit<T> m_value{};
|
maybe_uninit<T> m_value{};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// @Todo Convert copy
|
// @Todo Convert copy
|
||||||
// @Todo Convert move
|
// @Todo Convert move
|
||||||
|
|
||||||
constexpr status_or(const status_or& other)
|
constexpr status_or(const status_or& other)
|
||||||
requires copy_constructible<T>
|
requires copy_constructible<T>
|
||||||
: m_status{other.m_status}
|
: m_status{other.m_status}
|
||||||
{
|
{
|
||||||
if (other.ok())
|
if (other.ok())
|
||||||
{
|
{
|
||||||
m_value.construct_unsafe(other.m_value.as_init_unsafe());
|
m_value.construct_unsafe(other.m_value.as_init_unsafe());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr status_or(status_or&& other)
|
constexpr status_or(status_or&& other)
|
||||||
requires move_constructible<T>
|
requires move_constructible<T>
|
||||||
: m_status{ASL_MOVE(other.m_status)}
|
: m_status{ASL_MOVE(other.m_status)}
|
||||||
{
|
{
|
||||||
if (other.ok())
|
if (other.ok())
|
||||||
{
|
{
|
||||||
m_value.construct_unsafe(ASL_MOVE(other.m_value.as_init_unsafe()));
|
m_value.construct_unsafe(ASL_MOVE(other.m_value.as_init_unsafe()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr status_or& operator=(const status_or& other)
|
constexpr status_or& operator=(const status_or& other)
|
||||||
requires copyable<T>
|
requires copyable<T>
|
||||||
{
|
{
|
||||||
if (&other != this)
|
if (&other != this)
|
||||||
{
|
{
|
||||||
if (ok())
|
if (ok())
|
||||||
{
|
{
|
||||||
if (other.ok())
|
if (other.ok())
|
||||||
{
|
{
|
||||||
m_value.assign_unsafe(other.m_value.as_init_unsafe());
|
m_value.assign_unsafe(other.m_value.as_init_unsafe());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_value.destroy_unsafe();
|
m_value.destroy_unsafe();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (other.ok())
|
else if (other.ok())
|
||||||
{
|
{
|
||||||
m_value.construct_unsafe(other.m_value.as_init_unsafe());
|
m_value.construct_unsafe(other.m_value.as_init_unsafe());
|
||||||
}
|
}
|
||||||
m_status = other.m_status;
|
m_status = other.m_status;
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr status_or& operator=(status_or&& other)
|
constexpr status_or& operator=(status_or&& other)
|
||||||
requires moveable<T>
|
requires moveable<T>
|
||||||
{
|
{
|
||||||
if (&other != this)
|
if (&other != this)
|
||||||
{
|
{
|
||||||
if (ok())
|
if (ok())
|
||||||
{
|
{
|
||||||
if (other.ok())
|
if (other.ok())
|
||||||
{
|
{
|
||||||
m_value.assign_unsafe(ASL_MOVE(other.m_value.as_init_unsafe()));
|
m_value.assign_unsafe(ASL_MOVE(other.m_value.as_init_unsafe()));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_value.destroy_unsafe();
|
m_value.destroy_unsafe();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (other.ok())
|
else if (other.ok())
|
||||||
{
|
{
|
||||||
m_value.construct_unsafe(ASL_MOVE(other.m_value.as_init_unsafe()));
|
m_value.construct_unsafe(ASL_MOVE(other.m_value.as_init_unsafe()));
|
||||||
}
|
}
|
||||||
m_status = ASL_MOVE(other.m_status);
|
m_status = ASL_MOVE(other.m_status);
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr ~status_or()
|
constexpr ~status_or()
|
||||||
{
|
{
|
||||||
if (m_status.ok())
|
if (m_status.ok())
|
||||||
{
|
{
|
||||||
m_value.destroy_unsafe();
|
m_value.destroy_unsafe();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOLINTNEXTLINE(*-explicit-conversions)
|
// NOLINTNEXTLINE(*-explicit-conversions)
|
||||||
constexpr status_or(const status& status) : m_status{status}
|
constexpr status_or(const status& status) : m_status{status}
|
||||||
{
|
{
|
||||||
ASL_ASSERT_RELEASE(!m_status.ok());
|
ASL_ASSERT_RELEASE(!m_status.ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOLINTNEXTLINE(*-explicit-conversions)
|
// NOLINTNEXTLINE(*-explicit-conversions)
|
||||||
constexpr status_or(status&& status) : m_status{ASL_MOVE(status)}
|
constexpr status_or(status&& status) : m_status{ASL_MOVE(status)}
|
||||||
{
|
{
|
||||||
ASL_ASSERT_RELEASE(!m_status.ok());
|
ASL_ASSERT_RELEASE(!m_status.ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
status_or& operator=(status status) = delete;
|
status_or& operator=(status status) = delete;
|
||||||
|
|
||||||
template<typename U = T>
|
template<typename U = T>
|
||||||
constexpr explicit (!convertible_from<T, U&&>)
|
constexpr explicit (!convertible_from<T, U&&>)
|
||||||
status_or(U&& value)
|
status_or(U&& value)
|
||||||
requires (
|
requires (
|
||||||
constructible_from<T, U&&> &&
|
constructible_from<T, U&&> &&
|
||||||
!same_as<un_cvref_t<U>, status_or> &&
|
!same_as<un_cvref_t<U>, status_or> &&
|
||||||
!same_as<un_cvref_t<U>, status>
|
!same_as<un_cvref_t<U>, status>
|
||||||
)
|
)
|
||||||
: m_status{status_code::ok}
|
: m_status{status_code::ok}
|
||||||
, m_value{in_place, ASL_FWD(value)}
|
, m_value{in_place, ASL_FWD(value)}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
constexpr bool ok() const { return m_status.ok(); }
|
constexpr bool ok() const { return m_status.ok(); }
|
||||||
|
|
||||||
constexpr status_code code() const { return m_status.code(); }
|
constexpr status_code code() const { return m_status.code(); }
|
||||||
|
|
||||||
constexpr string_view message() const { return m_status.message(); }
|
constexpr string_view message() const { return m_status.message(); }
|
||||||
|
|
||||||
// @Todo(C++23) Deducing this
|
// @Todo(C++23) Deducing this
|
||||||
constexpr const T& value() const&
|
constexpr const T& value() const&
|
||||||
{
|
{
|
||||||
ASL_ASSERT_RELEASE(ok());
|
ASL_ASSERT_RELEASE(ok());
|
||||||
return m_value.as_init_unsafe();
|
return m_value.as_init_unsafe();
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr T& value() &
|
constexpr T& value() &
|
||||||
{
|
{
|
||||||
ASL_ASSERT_RELEASE(ok());
|
ASL_ASSERT_RELEASE(ok());
|
||||||
return m_value.as_init_unsafe();
|
return m_value.as_init_unsafe();
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr T&& value() &&
|
constexpr T&& value() &&
|
||||||
{
|
{
|
||||||
ASL_ASSERT_RELEASE(ok());
|
ASL_ASSERT_RELEASE(ok());
|
||||||
return ASL_MOVE(m_value.as_init_unsafe());
|
return ASL_MOVE(m_value.as_init_unsafe());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
constexpr T value_or(U&& other_value) const&
|
constexpr T value_or(U&& other_value) const&
|
||||||
requires copy_constructible<T> && convertible_from<T, U&&>
|
requires copy_constructible<T> && convertible_from<T, U&&>
|
||||||
{
|
{
|
||||||
return ok() ? value() : static_cast<T>(ASL_FWD(other_value));
|
return ok() ? value() : static_cast<T>(ASL_FWD(other_value));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
constexpr T value_or(U&& other_value) &&
|
constexpr T value_or(U&& other_value) &&
|
||||||
requires move_constructible<T> && convertible_from<T, U&&>
|
requires move_constructible<T> && convertible_from<T, U&&>
|
||||||
{
|
{
|
||||||
return ok() ? ASL_MOVE(value()) : static_cast<T>(ASL_FWD(other_value));
|
return ok() ? ASL_MOVE(value()) : static_cast<T>(ASL_FWD(other_value));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename H>
|
template<typename H>
|
||||||
requires hashable<T>
|
requires hashable<T>
|
||||||
friend H AslHashValue(H h, const status_or& s)
|
friend H AslHashValue(H h, const status_or& s)
|
||||||
{
|
{
|
||||||
if (s.ok())
|
if (s.ok())
|
||||||
{
|
{
|
||||||
return H::combine(ASL_MOVE(h), s.m_status, s.value());
|
return H::combine(ASL_MOVE(h), s.m_status, s.value());
|
||||||
}
|
}
|
||||||
return H::combine(ASL_MOVE(h), s.m_status);
|
return H::combine(ASL_MOVE(h), s.m_status);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
status_or(T) -> status_or<T>;
|
status_or(T) -> status_or<T>;
|
||||||
|
|
||||||
} // namespace asl
|
} // namespace asl
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ public:
|
|||||||
{
|
{
|
||||||
return as_string_view() == other.as_string_view();
|
return as_string_view() == other.as_string_view();
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool operator==(string_view other) const
|
constexpr bool operator==(string_view other) const
|
||||||
{
|
{
|
||||||
return as_string_view() == other;
|
return as_string_view() == other;
|
||||||
|
@ -104,7 +104,7 @@ public:
|
|||||||
|
|
||||||
constexpr StringWriter& operator=(const StringWriter&) requires copy_assignable<Allocator> = default;
|
constexpr StringWriter& operator=(const StringWriter&) requires copy_assignable<Allocator> = default;
|
||||||
constexpr StringWriter& operator=(StringWriter&&) = default;
|
constexpr StringWriter& operator=(StringWriter&&) = default;
|
||||||
|
|
||||||
void write(span<const byte> str) override
|
void write(span<const byte> str) override
|
||||||
{
|
{
|
||||||
m_builder.push(string_view{reinterpret_cast<const char*>(str.data()), str.size()});
|
m_builder.push(string_view{reinterpret_cast<const char*>(str.data()), str.size()});
|
||||||
|
@ -41,7 +41,7 @@ public:
|
|||||||
~string_view() = default;
|
~string_view() = default;
|
||||||
|
|
||||||
constexpr isize_t size() const { return m_size; }
|
constexpr isize_t size() const { return m_size; }
|
||||||
|
|
||||||
constexpr bool is_empty() const { return m_size == 0; }
|
constexpr bool is_empty() const { return m_size == 0; }
|
||||||
|
|
||||||
constexpr const char* data() const { return m_data; }
|
constexpr const char* data() const { return m_data; }
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
cc_library(
|
cc_library(
|
||||||
name = "testing",
|
name = "testing",
|
||||||
hdrs = [
|
hdrs = [
|
||||||
"testing.hpp",
|
"testing.hpp",
|
||||||
],
|
],
|
||||||
srcs = [
|
srcs = [
|
||||||
"testing.cpp",
|
"testing.cpp",
|
||||||
],
|
],
|
||||||
deps = [
|
deps = [
|
||||||
"//asl",
|
"//asl",
|
||||||
],
|
],
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
|
@ -1,81 +1,81 @@
|
|||||||
#include "asl/testing/testing.hpp"
|
#include "asl/testing/testing.hpp"
|
||||||
|
|
||||||
#include "asl/print.hpp"
|
#include "asl/print.hpp"
|
||||||
|
|
||||||
static asl::testing::Test* g_head = nullptr;
|
static asl::testing::Test* g_head = nullptr;
|
||||||
static asl::testing::Test* g_tail = nullptr;
|
static asl::testing::Test* g_tail = nullptr;
|
||||||
|
|
||||||
void asl::testing::register_test(Test* test)
|
void asl::testing::register_test(Test* test)
|
||||||
{
|
{
|
||||||
if (g_head == nullptr && g_tail == nullptr)
|
if (g_head == nullptr && g_tail == nullptr)
|
||||||
{
|
{
|
||||||
g_head = test;
|
g_head = test;
|
||||||
g_tail = test;
|
g_tail = test;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_tail->m_next = test;
|
g_tail->m_next = test;
|
||||||
test->m_prev = asl::exchange(g_tail, test);
|
test->m_prev = asl::exchange(g_tail, test);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool g_current_test_fail = false;
|
static bool g_current_test_fail = false;
|
||||||
|
|
||||||
void asl::testing::report_failure(const char* msg, const char* file, int line)
|
void asl::testing::report_failure(const char* msg, const char* file, int line)
|
||||||
{
|
{
|
||||||
asl::eprint("--------------------------------------------------------------\n");
|
asl::eprint("--------------------------------------------------------------\n");
|
||||||
asl::eprint("Test assertion failed at {}, line {}:\n", file, line);
|
asl::eprint("Test assertion failed at {}, line {}:\n", file, line);
|
||||||
asl::eprint(" {}\n", msg);
|
asl::eprint(" {}\n", msg);
|
||||||
asl::eprint("--------------------------------------------------------------\n");
|
asl::eprint("--------------------------------------------------------------\n");
|
||||||
g_current_test_fail = true;
|
g_current_test_fail = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RESET "\x1b[0m"
|
#define RESET "\x1b[0m"
|
||||||
#define RED(S) "\x1b[0;31m" S RESET
|
#define RED(S) "\x1b[0;31m" S RESET
|
||||||
#define GREEN(S) "\x1b[0;32m" S RESET
|
#define GREEN(S) "\x1b[0;32m" S RESET
|
||||||
|
|
||||||
int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[])
|
int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[])
|
||||||
{
|
{
|
||||||
int fail = 0;
|
int fail = 0;
|
||||||
int pass = 0;
|
int pass = 0;
|
||||||
|
|
||||||
asl::testing::Test* failed_head = nullptr;
|
asl::testing::Test* failed_head = nullptr;
|
||||||
|
|
||||||
for (auto* it = g_head; it != nullptr; it = it->m_next)
|
for (auto* it = g_head; it != nullptr; it = it->m_next)
|
||||||
{
|
{
|
||||||
asl::eprint(GREEN("[ RUN ]") " {}\n", it->m_case_name);
|
asl::eprint(GREEN("[ RUN ]") " {}\n", it->m_case_name);
|
||||||
|
|
||||||
g_current_test_fail = false;
|
g_current_test_fail = false;
|
||||||
it->m_fn();
|
it->m_fn();
|
||||||
|
|
||||||
if (!g_current_test_fail)
|
if (!g_current_test_fail)
|
||||||
{
|
{
|
||||||
asl::eprint(GREEN("[ OK ]") " {}\n", it->m_case_name);
|
asl::eprint(GREEN("[ OK ]") " {}\n", it->m_case_name);
|
||||||
pass += 1;
|
pass += 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
asl::eprint(RED("[ FAILED ]") " {}\n", it->m_case_name);
|
asl::eprint(RED("[ FAILED ]") " {}\n", it->m_case_name);
|
||||||
fail += 1;
|
fail += 1;
|
||||||
|
|
||||||
it->m_next = asl::exchange(failed_head, it);
|
it->m_next = asl::exchange(failed_head, it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
asl::eprint(GREEN("[----------]") " {} test(s) run\n", fail + pass);
|
asl::eprint(GREEN("[----------]") " {} test(s) run\n", fail + pass);
|
||||||
|
|
||||||
if (fail == 0)
|
if (fail == 0)
|
||||||
{
|
{
|
||||||
asl::eprint(GREEN("[ PASSED ]") " Good job!\n");
|
asl::eprint(GREEN("[ PASSED ]") " Good job!\n");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
asl::eprint(RED("[ FAILED ]") " {} test(s) failed\n", fail);
|
asl::eprint(RED("[ FAILED ]") " {} test(s) failed\n", fail);
|
||||||
for (auto* it = failed_head; it != nullptr; it = it->m_next)
|
for (auto* it = failed_head; it != nullptr; it = it->m_next)
|
||||||
{
|
{
|
||||||
asl::eprint(RED("[ FAILED ]") " {}\n", it->m_case_name);
|
asl::eprint(RED("[ FAILED ]") " {}\n", it->m_case_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fail;
|
return fail;
|
||||||
}
|
}
|
||||||
|
@ -1,46 +1,46 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "asl/utility.hpp"
|
#include "asl/utility.hpp"
|
||||||
|
|
||||||
namespace asl::testing
|
namespace asl::testing
|
||||||
{
|
{
|
||||||
|
|
||||||
struct Test;
|
struct Test;
|
||||||
|
|
||||||
void register_test(Test*);
|
void register_test(Test*);
|
||||||
|
|
||||||
void report_failure(const char* msg, const char* file, int line);
|
void report_failure(const char* msg, const char* file, int line);
|
||||||
|
|
||||||
using TestFunction = void();
|
using TestFunction = void();
|
||||||
|
|
||||||
struct Test
|
struct Test
|
||||||
{
|
{
|
||||||
const char* m_case_name;
|
const char* m_case_name;
|
||||||
TestFunction* m_fn;
|
TestFunction* m_fn;
|
||||||
Test* m_next{};
|
Test* m_next{};
|
||||||
Test* m_prev{};
|
Test* m_prev{};
|
||||||
|
|
||||||
constexpr explicit Test(const char* case_name, TestFunction* fn)
|
constexpr explicit Test(const char* case_name, TestFunction* fn)
|
||||||
: m_case_name{case_name}
|
: m_case_name{case_name}
|
||||||
, m_fn{fn}
|
, m_fn{fn}
|
||||||
{
|
{
|
||||||
register_test(this);
|
register_test(this);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace asl::testing
|
} // namespace asl::testing
|
||||||
|
|
||||||
#define ASL_TEST(CASE) \
|
#define ASL_TEST(CASE) \
|
||||||
static void asl_test_fn_##CASE(); \
|
static void asl_test_fn_##CASE(); \
|
||||||
static ::asl::testing::Test asl_test_##CASE( \
|
static ::asl::testing::Test asl_test_##CASE( \
|
||||||
#CASE, \
|
#CASE, \
|
||||||
asl_test_fn_##CASE); \
|
asl_test_fn_##CASE); \
|
||||||
void asl_test_fn_##CASE()
|
void asl_test_fn_##CASE()
|
||||||
|
|
||||||
#define ASL_TEST_ASSERT(EXPR) \
|
#define ASL_TEST_ASSERT(EXPR) \
|
||||||
if (EXPR) {} \
|
if (EXPR) {} \
|
||||||
else { ::asl::testing::report_failure(#EXPR, __FILE__, __LINE__); return; }
|
else { ::asl::testing::report_failure(#EXPR, __FILE__, __LINE__); return; }
|
||||||
|
|
||||||
#define ASL_TEST_EXPECT(EXPR) \
|
#define ASL_TEST_EXPECT(EXPR) \
|
||||||
if (EXPR) {} \
|
if (EXPR) {} \
|
||||||
else { ::asl::testing::report_failure(#EXPR, __FILE__, __LINE__); }
|
else { ::asl::testing::report_failure(#EXPR, __FILE__, __LINE__); }
|
||||||
|
@ -1,78 +1,78 @@
|
|||||||
#include "asl/box.hpp"
|
#include "asl/box.hpp"
|
||||||
#include "asl/option.hpp"
|
#include "asl/option.hpp"
|
||||||
|
|
||||||
#include "asl/testing/testing.hpp"
|
#include "asl/testing/testing.hpp"
|
||||||
#include "asl/tests/test_types.hpp"
|
#include "asl/tests/test_types.hpp"
|
||||||
|
|
||||||
static_assert(sizeof(asl::box<int>) == sizeof(int*));
|
static_assert(sizeof(asl::box<int>) == sizeof(int*));
|
||||||
static_assert(!asl::copyable<asl::box<int>>);
|
static_assert(!asl::copyable<asl::box<int>>);
|
||||||
static_assert(asl::moveable<asl::box<int>>);
|
static_assert(asl::moveable<asl::box<int>>);
|
||||||
static_assert(asl::has_niche<asl::box<int>>);
|
static_assert(asl::has_niche<asl::box<int>>);
|
||||||
static_assert(sizeof(asl::option<asl::box<int>>) == sizeof(int*));
|
static_assert(sizeof(asl::option<asl::box<int>>) == sizeof(int*));
|
||||||
|
|
||||||
ASL_TEST(destructor)
|
ASL_TEST(destructor)
|
||||||
{
|
{
|
||||||
bool d = false;
|
bool d = false;
|
||||||
|
|
||||||
{
|
{
|
||||||
auto box = asl::make_box<DestructorObserver>(&d);
|
auto box = asl::make_box<DestructorObserver>(&d);
|
||||||
ASL_TEST_ASSERT(!d);
|
ASL_TEST_ASSERT(!d);
|
||||||
|
|
||||||
|
|
||||||
auto box3 = ASL_MOVE(box);
|
auto box3 = ASL_MOVE(box);
|
||||||
ASL_TEST_ASSERT(!d);
|
ASL_TEST_ASSERT(!d);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST_ASSERT(d);
|
ASL_TEST_ASSERT(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(value)
|
ASL_TEST(value)
|
||||||
{
|
{
|
||||||
auto b = asl::make_box<int>(24);
|
auto b = asl::make_box<int>(24);
|
||||||
ASL_TEST_EXPECT(*b == 24);
|
ASL_TEST_EXPECT(*b == 24);
|
||||||
|
|
||||||
auto b2 = ASL_MOVE(b);
|
auto b2 = ASL_MOVE(b);
|
||||||
ASL_TEST_EXPECT(*b2 == 24);
|
ASL_TEST_EXPECT(*b2 == 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(ptr)
|
ASL_TEST(ptr)
|
||||||
{
|
{
|
||||||
auto b = asl::make_box<int>(24);
|
auto b = asl::make_box<int>(24);
|
||||||
auto* ptr1 = b.get();
|
auto* ptr1 = b.get();
|
||||||
|
|
||||||
auto b2 = ASL_MOVE(b);
|
auto b2 = ASL_MOVE(b);
|
||||||
auto* ptr2 = b2.get();
|
auto* ptr2 = b2.get();
|
||||||
ASL_TEST_EXPECT(ptr1 == ptr2);
|
ASL_TEST_EXPECT(ptr1 == ptr2);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Struct { int a; };
|
struct Struct { int a; };
|
||||||
|
|
||||||
ASL_TEST(arrow)
|
ASL_TEST(arrow)
|
||||||
{
|
{
|
||||||
auto b = asl::make_box<Struct>(45);
|
auto b = asl::make_box<Struct>(45);
|
||||||
ASL_TEST_EXPECT(b->a == 45);
|
ASL_TEST_EXPECT(b->a == 45);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(niche)
|
ASL_TEST(niche)
|
||||||
{
|
{
|
||||||
static_assert(sizeof(asl::box<int>) == sizeof(asl::option<asl::box<int>>));
|
static_assert(sizeof(asl::box<int>) == sizeof(asl::option<asl::box<int>>));
|
||||||
|
|
||||||
asl::option<asl::box<int>> opt;
|
asl::option<asl::box<int>> opt;
|
||||||
ASL_TEST_EXPECT(!opt.has_value());
|
ASL_TEST_EXPECT(!opt.has_value());
|
||||||
|
|
||||||
opt = asl::make_box<int>(66);
|
opt = asl::make_box<int>(66);
|
||||||
ASL_TEST_EXPECT(opt.has_value());
|
ASL_TEST_EXPECT(opt.has_value());
|
||||||
ASL_TEST_EXPECT(*opt.value() == 66);
|
ASL_TEST_EXPECT(*opt.value() == 66);
|
||||||
|
|
||||||
opt = asl::nullopt;
|
opt = asl::nullopt;
|
||||||
ASL_TEST_EXPECT(!opt.has_value());
|
ASL_TEST_EXPECT(!opt.has_value());
|
||||||
|
|
||||||
bool destroyed = false;
|
bool destroyed = false;
|
||||||
asl::option opt2 = asl::make_box<DestructorObserver>(&destroyed);
|
asl::option opt2 = asl::make_box<DestructorObserver>(&destroyed);
|
||||||
ASL_TEST_EXPECT(opt2.has_value());
|
ASL_TEST_EXPECT(opt2.has_value());
|
||||||
ASL_TEST_EXPECT(!destroyed);
|
ASL_TEST_EXPECT(!destroyed);
|
||||||
|
|
||||||
opt2.reset();
|
opt2.reset();
|
||||||
ASL_TEST_EXPECT(!opt2.has_value());
|
ASL_TEST_EXPECT(!opt2.has_value());
|
||||||
ASL_TEST_EXPECT(destroyed);
|
ASL_TEST_EXPECT(destroyed);
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,23 +1,23 @@
|
|||||||
#include "asl/float.hpp"
|
#include "asl/float.hpp"
|
||||||
|
|
||||||
#include "asl/testing/testing.hpp"
|
#include "asl/testing/testing.hpp"
|
||||||
|
|
||||||
ASL_TEST(is_infinity)
|
ASL_TEST(is_infinity)
|
||||||
{
|
{
|
||||||
ASL_TEST_EXPECT(!asl::is_infinity(0.0F));
|
ASL_TEST_EXPECT(!asl::is_infinity(0.0F));
|
||||||
ASL_TEST_EXPECT(!asl::is_infinity(-25.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(-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<float>()));
|
||||||
ASL_TEST_EXPECT(asl::is_infinity(-asl::infinity<double>()));
|
ASL_TEST_EXPECT(asl::is_infinity(-asl::infinity<double>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(is_nan)
|
ASL_TEST(is_nan)
|
||||||
{
|
{
|
||||||
ASL_TEST_EXPECT(!asl::is_nan(0.0F));
|
ASL_TEST_EXPECT(!asl::is_nan(0.0F));
|
||||||
ASL_TEST_EXPECT(!asl::is_nan(-25.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(45.0F / 0.0F));
|
||||||
ASL_TEST_EXPECT(asl::is_nan(asl::nan<float>()));
|
ASL_TEST_EXPECT(asl::is_nan(asl::nan<float>()));
|
||||||
ASL_TEST_EXPECT(asl::is_nan(asl::nan<double>()));
|
ASL_TEST_EXPECT(asl::is_nan(asl::nan<double>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,110 +1,110 @@
|
|||||||
#include "asl/format.hpp"
|
#include "asl/format.hpp"
|
||||||
#include "asl/testing/testing.hpp"
|
#include "asl/testing/testing.hpp"
|
||||||
#include "asl/float.hpp"
|
#include "asl/float.hpp"
|
||||||
#include "asl/string_builder.hpp"
|
#include "asl/string_builder.hpp"
|
||||||
|
|
||||||
static_assert(asl::formattable<decltype("Hello")>);
|
static_assert(asl::formattable<decltype("Hello")>);
|
||||||
|
|
||||||
ASL_TEST(format_args)
|
ASL_TEST(format_args)
|
||||||
{
|
{
|
||||||
// @Todo Introduce ASL_TEST_EXPECT_EQ, or ASL_TEST_EXPECT_STREQ
|
// @Todo Introduce ASL_TEST_EXPECT_EQ, or ASL_TEST_EXPECT_STREQ
|
||||||
|
|
||||||
auto s = asl::format_to_string("Hello, world!");
|
auto s = asl::format_to_string("Hello, world!");
|
||||||
ASL_TEST_EXPECT(s == "Hello, world!"_sv);
|
ASL_TEST_EXPECT(s == "Hello, world!"_sv);
|
||||||
|
|
||||||
s = asl::format_to_string("");
|
s = asl::format_to_string("");
|
||||||
ASL_TEST_EXPECT(s == ""_sv);
|
ASL_TEST_EXPECT(s == ""_sv);
|
||||||
|
|
||||||
s = asl::format_to_string("Hello, {}!", "world");
|
s = asl::format_to_string("Hello, {}!", "world");
|
||||||
ASL_TEST_EXPECT(s == "Hello, world!"_sv);
|
ASL_TEST_EXPECT(s == "Hello, world!"_sv);
|
||||||
|
|
||||||
s = asl::format_to_string("Hello, {}! {}", "world");
|
s = asl::format_to_string("Hello, {}! {}", "world");
|
||||||
ASL_TEST_EXPECT(s == "Hello, world! <ERROR>"_sv);
|
ASL_TEST_EXPECT(s == "Hello, world! <ERROR>"_sv);
|
||||||
|
|
||||||
s = asl::format_to_string("Hello, pup!", "world");
|
s = asl::format_to_string("Hello, pup!", "world");
|
||||||
ASL_TEST_EXPECT(s == "Hello, pup!"_sv);
|
ASL_TEST_EXPECT(s == "Hello, pup!"_sv);
|
||||||
|
|
||||||
s = asl::format_to_string("{}", "CHEESE");
|
s = asl::format_to_string("{}", "CHEESE");
|
||||||
ASL_TEST_EXPECT(s == "CHEESE"_sv);
|
ASL_TEST_EXPECT(s == "CHEESE"_sv);
|
||||||
|
|
||||||
s = asl::format_to_string("{ ", "CHEESE");
|
s = asl::format_to_string("{ ", "CHEESE");
|
||||||
ASL_TEST_EXPECT(s == "<ERROR> "_sv);
|
ASL_TEST_EXPECT(s == "<ERROR> "_sv);
|
||||||
|
|
||||||
s = asl::format_to_string("{", "CHEESE");
|
s = asl::format_to_string("{", "CHEESE");
|
||||||
ASL_TEST_EXPECT(s == "<ERROR>"_sv);
|
ASL_TEST_EXPECT(s == "<ERROR>"_sv);
|
||||||
|
|
||||||
s = asl::format_to_string("a{{b");
|
s = asl::format_to_string("a{{b");
|
||||||
ASL_TEST_EXPECT(s == "a{b"_sv);
|
ASL_TEST_EXPECT(s == "a{b"_sv);
|
||||||
|
|
||||||
s = asl::format_to_string("{{{}}} }", "CHEESE");
|
s = asl::format_to_string("{{{}}} }", "CHEESE");
|
||||||
ASL_TEST_EXPECT(s == "{CHEESE} }"_sv);
|
ASL_TEST_EXPECT(s == "{CHEESE} }"_sv);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(format_integers)
|
ASL_TEST(format_integers)
|
||||||
{
|
{
|
||||||
auto s = asl::format_to_string("{} {} {}", 0, 1, 2);
|
auto s = asl::format_to_string("{} {} {}", 0, 1, 2);
|
||||||
ASL_TEST_EXPECT(s == "0 1 2"_sv);
|
ASL_TEST_EXPECT(s == "0 1 2"_sv);
|
||||||
|
|
||||||
s = asl::format_to_string("{} {} {}", 10, 11, 12);
|
s = asl::format_to_string("{} {} {}", 10, 11, 12);
|
||||||
ASL_TEST_EXPECT(s == "10 11 12"_sv);
|
ASL_TEST_EXPECT(s == "10 11 12"_sv);
|
||||||
|
|
||||||
s = asl::format_to_string("{} {} {}", 100, 101, 102);
|
s = asl::format_to_string("{} {} {}", 100, 101, 102);
|
||||||
ASL_TEST_EXPECT(s == "100 101 102"_sv);
|
ASL_TEST_EXPECT(s == "100 101 102"_sv);
|
||||||
|
|
||||||
s = asl::format_to_string("{} {} {}", 1000, 1001, 1002);
|
s = asl::format_to_string("{} {} {}", 1000, 1001, 1002);
|
||||||
ASL_TEST_EXPECT(s == "1000 1001 1002"_sv);
|
ASL_TEST_EXPECT(s == "1000 1001 1002"_sv);
|
||||||
|
|
||||||
s = asl::format_to_string("{} {} {} {}", -1, -23, -456, -7890);
|
s = asl::format_to_string("{} {} {} {}", -1, -23, -456, -7890);
|
||||||
ASL_TEST_EXPECT(s == "-1 -23 -456 -7890"_sv);
|
ASL_TEST_EXPECT(s == "-1 -23 -456 -7890"_sv);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(format_floats)
|
ASL_TEST(format_floats)
|
||||||
{
|
{
|
||||||
auto s = asl::format_to_string("{} {} {}", 0.0F, 1.0, 2.0F);
|
auto s = asl::format_to_string("{} {} {}", 0.0F, 1.0, 2.0F);
|
||||||
ASL_TEST_EXPECT(s == "0 1 2"_sv);
|
ASL_TEST_EXPECT(s == "0 1 2"_sv);
|
||||||
|
|
||||||
s = asl::format_to_string("{} {} {}", 0.1F, 0.001F, 0.123F);
|
s = asl::format_to_string("{} {} {}", 0.1F, 0.001F, 0.123F);
|
||||||
ASL_TEST_EXPECT(s == "0.1 0.001 0.123"_sv);
|
ASL_TEST_EXPECT(s == "0.1 0.001 0.123"_sv);
|
||||||
|
|
||||||
s = asl::format_to_string("{} {}", 1.25F, -22.3);
|
s = asl::format_to_string("{} {}", 1.25F, -22.3);
|
||||||
ASL_TEST_EXPECT(s == "1.25 -22.3"_sv);
|
ASL_TEST_EXPECT(s == "1.25 -22.3"_sv);
|
||||||
|
|
||||||
s = asl::format_to_string("{}", 1e32);
|
s = asl::format_to_string("{}", 1e32);
|
||||||
ASL_TEST_EXPECT(s == "100000000000000000000000000000000"_sv);
|
ASL_TEST_EXPECT(s == "100000000000000000000000000000000"_sv);
|
||||||
|
|
||||||
s = asl::format_to_string("{}", 123e-8);
|
s = asl::format_to_string("{}", 123e-8);
|
||||||
ASL_TEST_EXPECT(s == "0.00000123"_sv);
|
ASL_TEST_EXPECT(s == "0.00000123"_sv);
|
||||||
|
|
||||||
s = asl::format_to_string("{} {}", asl::infinity<float>(), -asl::infinity<double>());
|
s = asl::format_to_string("{} {}", asl::infinity<float>(), -asl::infinity<double>());
|
||||||
ASL_TEST_EXPECT(s == "Infinity -Infinity"_sv);
|
ASL_TEST_EXPECT(s == "Infinity -Infinity"_sv);
|
||||||
|
|
||||||
s = asl::format_to_string("{}", asl::nan<float>());
|
s = asl::format_to_string("{}", asl::nan<float>());
|
||||||
ASL_TEST_EXPECT(s == "NaN"_sv);
|
ASL_TEST_EXPECT(s == "NaN"_sv);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(format_boolean)
|
ASL_TEST(format_boolean)
|
||||||
{
|
{
|
||||||
auto s = asl::format_to_string("{} {}", true, false);
|
auto s = asl::format_to_string("{} {}", true, false);
|
||||||
ASL_TEST_EXPECT(s == "true false"_sv);
|
ASL_TEST_EXPECT(s == "true false"_sv);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CustomFormat
|
struct CustomFormat
|
||||||
{
|
{
|
||||||
int x;
|
int x;
|
||||||
friend void AslFormat(asl::Formatter&, const CustomFormat&);
|
friend void AslFormat(asl::Formatter&, const CustomFormat&);
|
||||||
};
|
};
|
||||||
|
|
||||||
void AslFormat(asl::Formatter& f, const CustomFormat& c)
|
void AslFormat(asl::Formatter& f, const CustomFormat& c)
|
||||||
{
|
{
|
||||||
f.write("("_sv);
|
f.write("("_sv);
|
||||||
AslFormat(f, c.x);
|
AslFormat(f, c.x);
|
||||||
f.write(")"_sv);
|
f.write(")"_sv);
|
||||||
}
|
}
|
||||||
|
|
||||||
static_assert(asl::formattable<CustomFormat>);
|
static_assert(asl::formattable<CustomFormat>);
|
||||||
|
|
||||||
ASL_TEST(format_custom)
|
ASL_TEST(format_custom)
|
||||||
{
|
{
|
||||||
auto s = asl::format_to_string("{}", CustomFormat{37});
|
auto s = asl::format_to_string("{}", CustomFormat{37});
|
||||||
ASL_TEST_EXPECT(s == "(37)"_sv);
|
ASL_TEST_EXPECT(s == "(37)"_sv);
|
||||||
}
|
}
|
||||||
|
@ -1,73 +1,73 @@
|
|||||||
#include "asl/functional.hpp"
|
#include "asl/functional.hpp"
|
||||||
#include "asl/testing/testing.hpp"
|
#include "asl/testing/testing.hpp"
|
||||||
|
|
||||||
struct HasFunction
|
struct HasFunction
|
||||||
{
|
{
|
||||||
void do_something(int, float) {}
|
void do_something(int, float) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct HasMember
|
struct HasMember
|
||||||
{
|
{
|
||||||
int member{};
|
int member{};
|
||||||
int member_array[4]{};
|
int member_array[4]{};
|
||||||
void (*member_fn)(){};
|
void (*member_fn)(){};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Functor
|
struct Functor
|
||||||
{
|
{
|
||||||
int64_t operator()() { return 35; }
|
int64_t operator()() { return 35; }
|
||||||
int operator()(int x) { return x; }
|
int operator()(int x) { return x; }
|
||||||
};
|
};
|
||||||
|
|
||||||
static int some_func0() { return 1; }
|
static int some_func0() { return 1; }
|
||||||
static int some_func1(int x) { return x + 1; }
|
static int some_func1(int x) { return x + 1; }
|
||||||
[[maybe_unused]] static float some_func1(float 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 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()>, int64_t>);
|
||||||
static_assert(asl::same_as<asl::result_of_t<Functor(int)>, int>);
|
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(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(&HasFunction::do_something)(HasFunction, int, float)>, void>);
|
||||||
static_assert(asl::same_as<asl::result_of_t<decltype(&HasMember::member)(HasMember)>, int>);
|
static_assert(asl::same_as<asl::result_of_t<decltype(&HasMember::member)(HasMember)>, int>);
|
||||||
|
|
||||||
ASL_TEST(invoke_member_function)
|
ASL_TEST(invoke_member_function)
|
||||||
{
|
{
|
||||||
HasFunction c;
|
HasFunction c;
|
||||||
asl::invoke(&HasFunction::do_something, c, 5, 5.0F);
|
asl::invoke(&HasFunction::do_something, c, 5, 5.0F);
|
||||||
asl::invoke(&HasFunction::do_something, &c, 5, 5.0F);
|
asl::invoke(&HasFunction::do_something, &c, 5, 5.0F);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(invoke_member_data)
|
ASL_TEST(invoke_member_data)
|
||||||
{
|
{
|
||||||
HasMember c;
|
HasMember c;
|
||||||
|
|
||||||
asl::invoke(&HasMember::member, c);
|
asl::invoke(&HasMember::member, c);
|
||||||
asl::invoke(&HasMember::member_array, c);
|
asl::invoke(&HasMember::member_array, c);
|
||||||
asl::invoke(&HasMember::member_fn, c);
|
asl::invoke(&HasMember::member_fn, c);
|
||||||
asl::invoke(&HasMember::member, &c);
|
asl::invoke(&HasMember::member, &c);
|
||||||
asl::invoke(&HasMember::member_array, &c);
|
asl::invoke(&HasMember::member_array, &c);
|
||||||
asl::invoke(&HasMember::member_fn, &c);
|
asl::invoke(&HasMember::member_fn, &c);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(invoke_fn)
|
ASL_TEST(invoke_fn)
|
||||||
{
|
{
|
||||||
ASL_TEST_EXPECT(asl::invoke(some_func0) == 1);
|
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(static_cast<int(*)(int)>(some_func1), 8) == 9);
|
||||||
ASL_TEST_EXPECT(asl::invoke(some_func2, 4, 8) == 12);
|
ASL_TEST_EXPECT(asl::invoke(some_func2, 4, 8) == 12);
|
||||||
ASL_TEST_EXPECT(asl::invoke(&some_func0) == 1);
|
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(static_cast<int(*)(int)>(&some_func1), 8) == 9);
|
||||||
ASL_TEST_EXPECT(asl::invoke(&some_func2, 4, 8) == 12);
|
ASL_TEST_EXPECT(asl::invoke(&some_func2, 4, 8) == 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(invoke_operator_call)
|
ASL_TEST(invoke_operator_call)
|
||||||
{
|
{
|
||||||
Functor f;
|
Functor f;
|
||||||
ASL_TEST_EXPECT(asl::invoke(f) == 35);
|
ASL_TEST_EXPECT(asl::invoke(f) == 35);
|
||||||
ASL_TEST_EXPECT(asl::invoke(f, 8) == 8);
|
ASL_TEST_EXPECT(asl::invoke(f, 8) == 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(invoke_lambda)
|
ASL_TEST(invoke_lambda)
|
||||||
{
|
{
|
||||||
ASL_TEST_EXPECT(asl::invoke([](){ return 35; }) == 35);
|
ASL_TEST_EXPECT(asl::invoke([](){ return 35; }) == 35);
|
||||||
ASL_TEST_EXPECT(asl::invoke([](int x){ return x + 2; }, 6) == 8);
|
ASL_TEST_EXPECT(asl::invoke([](int x){ return x + 2; }, 6) == 8);
|
||||||
}
|
}
|
||||||
|
@ -1,48 +1,48 @@
|
|||||||
#include "asl/testing/testing.hpp"
|
#include "asl/testing/testing.hpp"
|
||||||
#include "asl/hash_map.hpp"
|
#include "asl/hash_map.hpp"
|
||||||
|
|
||||||
ASL_TEST(default)
|
ASL_TEST(default)
|
||||||
{
|
{
|
||||||
asl::hash_map<int, int> map;
|
asl::hash_map<int, int> map;
|
||||||
|
|
||||||
ASL_TEST_EXPECT(!map.contains(45));
|
ASL_TEST_EXPECT(!map.contains(45));
|
||||||
ASL_TEST_EXPECT(!map.contains(46));
|
ASL_TEST_EXPECT(!map.contains(46));
|
||||||
|
|
||||||
map.insert(45, 5);
|
map.insert(45, 5);
|
||||||
map.insert(46, 6);
|
map.insert(46, 6);
|
||||||
|
|
||||||
ASL_TEST_EXPECT(map.size() == 2);
|
ASL_TEST_EXPECT(map.size() == 2);
|
||||||
|
|
||||||
ASL_TEST_EXPECT(map.contains(45));
|
ASL_TEST_EXPECT(map.contains(45));
|
||||||
ASL_TEST_EXPECT(map.contains(46));
|
ASL_TEST_EXPECT(map.contains(46));
|
||||||
ASL_TEST_EXPECT(!map.contains(47));
|
ASL_TEST_EXPECT(!map.contains(47));
|
||||||
|
|
||||||
ASL_TEST_EXPECT(*map.get(45) == 5);
|
ASL_TEST_EXPECT(*map.get(45) == 5);
|
||||||
ASL_TEST_EXPECT(*map.get(46) == 6);
|
ASL_TEST_EXPECT(*map.get(46) == 6);
|
||||||
ASL_TEST_EXPECT(map.get(47) == nullptr);
|
ASL_TEST_EXPECT(map.get(47) == nullptr);
|
||||||
|
|
||||||
ASL_TEST_EXPECT(map.remove(45));
|
ASL_TEST_EXPECT(map.remove(45));
|
||||||
ASL_TEST_EXPECT(!map.remove(45));
|
ASL_TEST_EXPECT(!map.remove(45));
|
||||||
|
|
||||||
ASL_TEST_EXPECT(map.size() == 1);
|
ASL_TEST_EXPECT(map.size() == 1);
|
||||||
|
|
||||||
ASL_TEST_EXPECT(!map.contains(45));
|
ASL_TEST_EXPECT(!map.contains(45));
|
||||||
ASL_TEST_EXPECT(map.contains(46));
|
ASL_TEST_EXPECT(map.contains(46));
|
||||||
ASL_TEST_EXPECT(!map.contains(47));
|
ASL_TEST_EXPECT(!map.contains(47));
|
||||||
|
|
||||||
ASL_TEST_EXPECT(map.get(45) == nullptr);
|
ASL_TEST_EXPECT(map.get(45) == nullptr);
|
||||||
ASL_TEST_EXPECT(*map.get(46) == 6);
|
ASL_TEST_EXPECT(*map.get(46) == 6);
|
||||||
ASL_TEST_EXPECT(map.get(47) == nullptr);
|
ASL_TEST_EXPECT(map.get(47) == nullptr);
|
||||||
|
|
||||||
map.insert(46, 460);
|
map.insert(46, 460);
|
||||||
|
|
||||||
ASL_TEST_EXPECT(map.size() == 1);
|
ASL_TEST_EXPECT(map.size() == 1);
|
||||||
|
|
||||||
ASL_TEST_EXPECT(!map.contains(45));
|
ASL_TEST_EXPECT(!map.contains(45));
|
||||||
ASL_TEST_EXPECT(map.contains(46));
|
ASL_TEST_EXPECT(map.contains(46));
|
||||||
ASL_TEST_EXPECT(!map.contains(47));
|
ASL_TEST_EXPECT(!map.contains(47));
|
||||||
|
|
||||||
ASL_TEST_EXPECT(map.get(45) == nullptr);
|
ASL_TEST_EXPECT(map.get(45) == nullptr);
|
||||||
ASL_TEST_EXPECT(*map.get(46) == 460);
|
ASL_TEST_EXPECT(*map.get(46) == 460);
|
||||||
ASL_TEST_EXPECT(map.get(47) == nullptr);
|
ASL_TEST_EXPECT(map.get(47) == nullptr);
|
||||||
}
|
}
|
||||||
|
@ -1,185 +1,185 @@
|
|||||||
#include "asl/hash_set.hpp"
|
#include "asl/hash_set.hpp"
|
||||||
#include "asl/testing/testing.hpp"
|
#include "asl/testing/testing.hpp"
|
||||||
#include "asl/tests/test_types.hpp"
|
#include "asl/tests/test_types.hpp"
|
||||||
#include "asl/string.hpp"
|
#include "asl/string.hpp"
|
||||||
#include "asl/string_view.hpp"
|
#include "asl/string_view.hpp"
|
||||||
|
|
||||||
ASL_TEST(empty)
|
ASL_TEST(empty)
|
||||||
{
|
{
|
||||||
asl::hash_set<int> set;
|
asl::hash_set<int> set;
|
||||||
|
|
||||||
ASL_TEST_EXPECT(set.size() == 0);
|
ASL_TEST_EXPECT(set.size() == 0);
|
||||||
|
|
||||||
for (int i = 0; i < 100; ++i)
|
for (int i = 0; i < 100; ++i)
|
||||||
{
|
{
|
||||||
ASL_TEST_EXPECT(!set.contains(i));
|
ASL_TEST_EXPECT(!set.contains(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(a_bunch_of_strings)
|
ASL_TEST(a_bunch_of_strings)
|
||||||
{
|
{
|
||||||
asl::hash_set<asl::string<>> set;
|
asl::hash_set<asl::string<>> set;
|
||||||
|
|
||||||
set.insert("Hello, world!");
|
set.insert("Hello, world!");
|
||||||
ASL_TEST_EXPECT(set.size() == 1);
|
ASL_TEST_EXPECT(set.size() == 1);
|
||||||
|
|
||||||
set.insert("Hello, puppy!");
|
set.insert("Hello, puppy!");
|
||||||
ASL_TEST_EXPECT(set.size() == 2);
|
ASL_TEST_EXPECT(set.size() == 2);
|
||||||
|
|
||||||
set.insert("Hello, puppy!");
|
set.insert("Hello, puppy!");
|
||||||
ASL_TEST_EXPECT(set.size() == 2);
|
ASL_TEST_EXPECT(set.size() == 2);
|
||||||
|
|
||||||
ASL_TEST_EXPECT(set.contains("Hello, world!"_sv));
|
ASL_TEST_EXPECT(set.contains("Hello, world!"_sv));
|
||||||
ASL_TEST_EXPECT(set.contains("Hello, puppy!"_sv));
|
ASL_TEST_EXPECT(set.contains("Hello, puppy!"_sv));
|
||||||
ASL_TEST_EXPECT(!set.contains("Hello, Steven!"_sv));
|
ASL_TEST_EXPECT(!set.contains("Hello, Steven!"_sv));
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(a_bunch_of_ints)
|
ASL_TEST(a_bunch_of_ints)
|
||||||
{
|
{
|
||||||
asl::hash_set<int> set;
|
asl::hash_set<int> set;
|
||||||
|
|
||||||
int count = 3000;
|
int count = 3000;
|
||||||
|
|
||||||
for (int i = 0; i < count; ++i)
|
for (int i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
set.insert(i);
|
set.insert(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST_EXPECT(set.size() == count);
|
ASL_TEST_EXPECT(set.size() == count);
|
||||||
|
|
||||||
for (int i = 0; i < count * 2; ++i)
|
for (int i = 0; i < count * 2; ++i)
|
||||||
{
|
{
|
||||||
ASL_TEST_EXPECT(set.contains(i) == (i < count));
|
ASL_TEST_EXPECT(set.contains(i) == (i < count));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct HashWithDestructor: public DestructorObserver
|
struct HashWithDestructor: public DestructorObserver
|
||||||
{
|
{
|
||||||
int x;
|
int x;
|
||||||
|
|
||||||
HashWithDestructor(int x_, bool* ptr)
|
HashWithDestructor(int x_, bool* ptr)
|
||||||
: DestructorObserver{ptr}
|
: DestructorObserver{ptr}
|
||||||
, x{x_}
|
, x{x_}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
constexpr bool operator==(const HashWithDestructor& other) const
|
constexpr bool operator==(const HashWithDestructor& other) const
|
||||||
{
|
{
|
||||||
return x == other.x;
|
return x == other.x;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CustomComparator
|
struct CustomComparator
|
||||||
{
|
{
|
||||||
static bool eq(const HashWithDestructor& a, const HashWithDestructor& b)
|
static bool eq(const HashWithDestructor& a, const HashWithDestructor& b)
|
||||||
{
|
{
|
||||||
return a.x == b.x;
|
return a.x == b.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool eq(const HashWithDestructor& a, int b)
|
static bool eq(const HashWithDestructor& a, int b)
|
||||||
{
|
{
|
||||||
return a.x == b;
|
return a.x == b;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CustomHasher
|
struct CustomHasher
|
||||||
{
|
{
|
||||||
static uint64_t hash(const HashWithDestructor& b)
|
static uint64_t hash(const HashWithDestructor& b)
|
||||||
{
|
{
|
||||||
return asl::hash_value(b.x);
|
return asl::hash_value(b.x);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t hash(int x)
|
static uint64_t hash(int x)
|
||||||
{
|
{
|
||||||
return asl::hash_value(x);
|
return asl::hash_value(x);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ASL_TEST(destructor_and_remove)
|
ASL_TEST(destructor_and_remove)
|
||||||
{
|
{
|
||||||
static constexpr int kCount = 200;
|
static constexpr int kCount = 200;
|
||||||
bool destroyed[kCount]{};
|
bool destroyed[kCount]{};
|
||||||
|
|
||||||
{
|
{
|
||||||
asl::hash_set<HashWithDestructor, asl::DefaultAllocator, CustomHasher, CustomComparator> set;
|
asl::hash_set<HashWithDestructor, asl::DefaultAllocator, CustomHasher, CustomComparator> set;
|
||||||
|
|
||||||
for (int i = 0; i < kCount; ++i)
|
for (int i = 0; i < kCount; ++i)
|
||||||
{
|
{
|
||||||
set.insert(i, &destroyed[i]); // NOLINT
|
set.insert(i, &destroyed[i]); // NOLINT
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST_EXPECT(set.size() == kCount);
|
ASL_TEST_EXPECT(set.size() == kCount);
|
||||||
|
|
||||||
for (int i = 0; i < kCount; ++i)
|
for (int i = 0; i < kCount; ++i)
|
||||||
{
|
{
|
||||||
ASL_TEST_EXPECT(!destroyed[i]); // NOLINT
|
ASL_TEST_EXPECT(!destroyed[i]); // NOLINT
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < kCount; i += 2)
|
for (int i = 0; i < kCount; i += 2)
|
||||||
{
|
{
|
||||||
ASL_TEST_EXPECT(set.remove(i));
|
ASL_TEST_EXPECT(set.remove(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < kCount; i += 2)
|
for (int i = 0; i < kCount; i += 2)
|
||||||
{
|
{
|
||||||
ASL_TEST_EXPECT(!set.contains(i));
|
ASL_TEST_EXPECT(!set.contains(i));
|
||||||
ASL_TEST_EXPECT(set.contains(i+1));
|
ASL_TEST_EXPECT(set.contains(i+1));
|
||||||
ASL_TEST_EXPECT(destroyed[i]); // NOLINT
|
ASL_TEST_EXPECT(destroyed[i]); // NOLINT
|
||||||
ASL_TEST_EXPECT(!destroyed[i + 1]); // NOLINT
|
ASL_TEST_EXPECT(!destroyed[i + 1]); // NOLINT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < kCount; ++i)
|
for (int i = 0; i < kCount; ++i)
|
||||||
{
|
{
|
||||||
ASL_TEST_EXPECT(destroyed[i]); // NOLINT
|
ASL_TEST_EXPECT(destroyed[i]); // NOLINT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(copy)
|
ASL_TEST(copy)
|
||||||
{
|
{
|
||||||
asl::hash_set<int> set1;
|
asl::hash_set<int> set1;
|
||||||
|
|
||||||
for (int i = 0; i < 100; ++i)
|
for (int i = 0; i < 100; ++i)
|
||||||
{
|
{
|
||||||
set1.insert(i);
|
set1.insert(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
asl::hash_set<int> set2 = set1;
|
asl::hash_set<int> set2 = set1;
|
||||||
asl::hash_set<int> set3;
|
asl::hash_set<int> set3;
|
||||||
set3 = set1;
|
set3 = set1;
|
||||||
|
|
||||||
ASL_TEST_EXPECT(set2.size() == 100);
|
ASL_TEST_EXPECT(set2.size() == 100);
|
||||||
ASL_TEST_EXPECT(set3.size() == 100);
|
ASL_TEST_EXPECT(set3.size() == 100);
|
||||||
|
|
||||||
for (int i = 0; i < 100; ++i)
|
for (int i = 0; i < 100; ++i)
|
||||||
{
|
{
|
||||||
ASL_TEST_EXPECT(set2.contains(i));
|
ASL_TEST_EXPECT(set2.contains(i));
|
||||||
ASL_TEST_EXPECT(set3.contains(i));
|
ASL_TEST_EXPECT(set3.contains(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(move)
|
ASL_TEST(move)
|
||||||
{
|
{
|
||||||
asl::hash_set<int> set1;
|
asl::hash_set<int> set1;
|
||||||
|
|
||||||
for (int i = 0; i < 100; ++i)
|
for (int i = 0; i < 100; ++i)
|
||||||
{
|
{
|
||||||
set1.insert(i);
|
set1.insert(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
asl::hash_set<int> set2 = ASL_MOVE(set1);
|
asl::hash_set<int> set2 = ASL_MOVE(set1);
|
||||||
|
|
||||||
ASL_TEST_EXPECT(set2.size() == 100);
|
ASL_TEST_EXPECT(set2.size() == 100);
|
||||||
for (int i = 0; i < 100; ++i)
|
for (int i = 0; i < 100; ++i)
|
||||||
{
|
{
|
||||||
ASL_TEST_EXPECT(set2.contains(i));
|
ASL_TEST_EXPECT(set2.contains(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
set1 = ASL_MOVE(set2);
|
set1 = ASL_MOVE(set2);
|
||||||
|
|
||||||
ASL_TEST_EXPECT(set1.size() == 100);
|
ASL_TEST_EXPECT(set1.size() == 100);
|
||||||
for (int i = 0; i < 100; ++i)
|
for (int i = 0; i < 100; ++i)
|
||||||
{
|
{
|
||||||
ASL_TEST_EXPECT(set1.contains(i));
|
ASL_TEST_EXPECT(set1.contains(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,260 +1,260 @@
|
|||||||
#include "asl/testing/testing.hpp"
|
#include "asl/testing/testing.hpp"
|
||||||
#include "asl/hash.hpp"
|
#include "asl/hash.hpp"
|
||||||
#include "asl/string_view.hpp"
|
#include "asl/string_view.hpp"
|
||||||
#include "asl/string.hpp"
|
#include "asl/string.hpp"
|
||||||
#include "asl/buffer.hpp"
|
#include "asl/buffer.hpp"
|
||||||
#include "asl/box.hpp"
|
#include "asl/box.hpp"
|
||||||
#include "asl/option.hpp"
|
#include "asl/option.hpp"
|
||||||
#include "asl/status.hpp"
|
#include "asl/status.hpp"
|
||||||
#include "asl/status_or.hpp"
|
#include "asl/status_or.hpp"
|
||||||
|
|
||||||
static_assert(!asl::hashable<int*>);
|
static_assert(!asl::hashable<int*>);
|
||||||
static_assert(!asl::hashable<int[]>);
|
static_assert(!asl::hashable<int[]>);
|
||||||
static_assert(!asl::hashable<int[9]>);
|
static_assert(!asl::hashable<int[9]>);
|
||||||
|
|
||||||
static_assert(asl::hashable<uint8_t>);
|
static_assert(asl::hashable<uint8_t>);
|
||||||
static_assert(asl::hashable<uint16_t>);
|
static_assert(asl::hashable<uint16_t>);
|
||||||
static_assert(asl::hashable<uint32_t>);
|
static_assert(asl::hashable<uint32_t>);
|
||||||
static_assert(asl::hashable<uint64_t>);
|
static_assert(asl::hashable<uint64_t>);
|
||||||
static_assert(asl::hashable<uint128_t>);
|
static_assert(asl::hashable<uint128_t>);
|
||||||
|
|
||||||
static_assert(asl::hashable<int8_t>);
|
static_assert(asl::hashable<int8_t>);
|
||||||
static_assert(asl::hashable<int16_t>);
|
static_assert(asl::hashable<int16_t>);
|
||||||
static_assert(asl::hashable<int32_t>);
|
static_assert(asl::hashable<int32_t>);
|
||||||
static_assert(asl::hashable<int64_t>);
|
static_assert(asl::hashable<int64_t>);
|
||||||
|
|
||||||
ASL_TEST(integers)
|
ASL_TEST(integers)
|
||||||
{
|
{
|
||||||
uint64_t a = asl::hash_value<uint16_t>(45);
|
uint64_t a = asl::hash_value<uint16_t>(45);
|
||||||
uint64_t b = asl::hash_value<uint16_t>(45);
|
uint64_t b = asl::hash_value<uint16_t>(45);
|
||||||
uint64_t c = asl::hash_value<uint16_t>(46);
|
uint64_t c = asl::hash_value<uint16_t>(46);
|
||||||
uint64_t d = asl::hash_value<uint32_t>(45);
|
uint64_t d = asl::hash_value<uint32_t>(45);
|
||||||
|
|
||||||
ASL_TEST_EXPECT(a == b);
|
ASL_TEST_EXPECT(a == b);
|
||||||
ASL_TEST_EXPECT(a != c);
|
ASL_TEST_EXPECT(a != c);
|
||||||
ASL_TEST_EXPECT(a != d);
|
ASL_TEST_EXPECT(a != d);
|
||||||
}
|
}
|
||||||
|
|
||||||
static_assert(asl::hashable<bool>);
|
static_assert(asl::hashable<bool>);
|
||||||
|
|
||||||
ASL_TEST(bool)
|
ASL_TEST(bool)
|
||||||
{
|
{
|
||||||
ASL_TEST_EXPECT(asl::hash_value(true) == asl::hash_value(true));
|
ASL_TEST_EXPECT(asl::hash_value(true) == asl::hash_value(true));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(false) == asl::hash_value(false));
|
ASL_TEST_EXPECT(asl::hash_value(false) == asl::hash_value(false));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(true) != asl::hash_value(false));
|
ASL_TEST_EXPECT(asl::hash_value(true) != asl::hash_value(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
static_assert(asl::hashable<asl::string_view>);
|
static_assert(asl::hashable<asl::string_view>);
|
||||||
static_assert(asl::hashable<asl::string<>>);
|
static_assert(asl::hashable<asl::string<>>);
|
||||||
|
|
||||||
ASL_TEST(strings)
|
ASL_TEST(strings)
|
||||||
{
|
{
|
||||||
ASL_TEST_EXPECT(asl::hash_value("hello"_sv) == asl::hash_value("hello"_sv));
|
ASL_TEST_EXPECT(asl::hash_value("hello"_sv) == asl::hash_value("hello"_sv));
|
||||||
ASL_TEST_EXPECT(asl::hash_value("hello"_sv) != asl::hash_value("hello "_sv));
|
ASL_TEST_EXPECT(asl::hash_value("hello"_sv) != asl::hash_value("hello "_sv));
|
||||||
ASL_TEST_EXPECT(asl::hash_value("hello"_sv) != asl::hash_value("HELLO"_sv));
|
ASL_TEST_EXPECT(asl::hash_value("hello"_sv) != asl::hash_value("HELLO"_sv));
|
||||||
|
|
||||||
ASL_TEST_EXPECT(asl::hash_value(asl::string("hello"_sv)) == asl::hash_value(asl::string("hello"_sv)));
|
ASL_TEST_EXPECT(asl::hash_value(asl::string("hello"_sv)) == asl::hash_value(asl::string("hello"_sv)));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(asl::string("hello"_sv)) != asl::hash_value(asl::string("hello "_sv)));
|
ASL_TEST_EXPECT(asl::hash_value(asl::string("hello"_sv)) != asl::hash_value(asl::string("hello "_sv)));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(asl::string("hello"_sv)) != asl::hash_value(asl::string("HELLO"_sv)));
|
ASL_TEST_EXPECT(asl::hash_value(asl::string("hello"_sv)) != asl::hash_value(asl::string("HELLO"_sv)));
|
||||||
|
|
||||||
ASL_TEST_EXPECT(asl::hash_value("hello"_sv) == asl::hash_value(asl::string("hello"_sv)));
|
ASL_TEST_EXPECT(asl::hash_value("hello"_sv) == asl::hash_value(asl::string("hello"_sv)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static_assert(asl::hashable<asl::span<const int>>);
|
static_assert(asl::hashable<asl::span<const int>>);
|
||||||
static_assert(!asl::hashable<asl::span<const int*>>);
|
static_assert(!asl::hashable<asl::span<const int*>>);
|
||||||
static_assert(asl::hashable<asl::span<asl::string_view>>);
|
static_assert(asl::hashable<asl::span<asl::string_view>>);
|
||||||
|
|
||||||
ASL_TEST(span)
|
ASL_TEST(span)
|
||||||
{
|
{
|
||||||
int ints1[] = {1, 2, 3};
|
int ints1[] = {1, 2, 3};
|
||||||
int ints2[] = {1, 2, 3};
|
int ints2[] = {1, 2, 3};
|
||||||
int ints3[] = {1, 2};
|
int ints3[] = {1, 2};
|
||||||
int ints4[] = {3, 2, 1};
|
int ints4[] = {3, 2, 1};
|
||||||
|
|
||||||
ASL_TEST_EXPECT(asl::hash_value(asl::span<int>(ints1)) == asl::hash_value(asl::span<int>(ints2)));
|
ASL_TEST_EXPECT(asl::hash_value(asl::span<int>(ints1)) == asl::hash_value(asl::span<int>(ints2)));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(asl::span<int>(ints1)) != asl::hash_value(asl::span<int>(ints3)));
|
ASL_TEST_EXPECT(asl::hash_value(asl::span<int>(ints1)) != asl::hash_value(asl::span<int>(ints3)));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(asl::span<int>(ints1)) != asl::hash_value(asl::span<int>(ints4)));
|
ASL_TEST_EXPECT(asl::hash_value(asl::span<int>(ints1)) != asl::hash_value(asl::span<int>(ints4)));
|
||||||
|
|
||||||
asl::string_view strs1[] = {"a", "abc", "hello"};
|
asl::string_view strs1[] = {"a", "abc", "hello"};
|
||||||
asl::string_view strs2[] = {"a", "abc", "hello"};
|
asl::string_view strs2[] = {"a", "abc", "hello"};
|
||||||
asl::string_view strs3[] = {"a", "abc"};
|
asl::string_view strs3[] = {"a", "abc"};
|
||||||
asl::string_view strs4[] = {"a", "abc", "hello", "what"};
|
asl::string_view strs4[] = {"a", "abc", "hello", "what"};
|
||||||
|
|
||||||
ASL_TEST_EXPECT(asl::hash_value(asl::span<asl::string_view>(strs1)) == asl::hash_value(asl::span<asl::string_view>(strs2)));
|
ASL_TEST_EXPECT(asl::hash_value(asl::span<asl::string_view>(strs1)) == asl::hash_value(asl::span<asl::string_view>(strs2)));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(asl::span<asl::string_view>(strs1)) != asl::hash_value(asl::span<asl::string_view>(strs3)));
|
ASL_TEST_EXPECT(asl::hash_value(asl::span<asl::string_view>(strs1)) != asl::hash_value(asl::span<asl::string_view>(strs3)));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(asl::span<asl::string_view>(strs1)) != asl::hash_value(asl::span<asl::string_view>(strs4)));
|
ASL_TEST_EXPECT(asl::hash_value(asl::span<asl::string_view>(strs1)) != asl::hash_value(asl::span<asl::string_view>(strs4)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static_assert(asl::hashable<asl::buffer<int>>);
|
static_assert(asl::hashable<asl::buffer<int>>);
|
||||||
static_assert(!asl::hashable<asl::buffer<int*>>);
|
static_assert(!asl::hashable<asl::buffer<int*>>);
|
||||||
|
|
||||||
ASL_TEST(buffer)
|
ASL_TEST(buffer)
|
||||||
{
|
{
|
||||||
asl::buffer<int> ints1;
|
asl::buffer<int> ints1;
|
||||||
ints1.push(1);
|
ints1.push(1);
|
||||||
ints1.push(2);
|
ints1.push(2);
|
||||||
ints1.push(3);
|
ints1.push(3);
|
||||||
|
|
||||||
asl::buffer<int> ints2;
|
asl::buffer<int> ints2;
|
||||||
ints2.push(1);
|
ints2.push(1);
|
||||||
ints2.push(2);
|
ints2.push(2);
|
||||||
ints2.push(3);
|
ints2.push(3);
|
||||||
|
|
||||||
asl::buffer<int> ints3;
|
asl::buffer<int> ints3;
|
||||||
ints3.push(1);
|
ints3.push(1);
|
||||||
ints3.push(2);
|
ints3.push(2);
|
||||||
|
|
||||||
asl::buffer<int> ints4;
|
asl::buffer<int> ints4;
|
||||||
ints4.push(1);
|
ints4.push(1);
|
||||||
ints4.push(2);
|
ints4.push(2);
|
||||||
ints4.push(4);
|
ints4.push(4);
|
||||||
|
|
||||||
ASL_TEST_EXPECT(asl::hash_value(ints1) == asl::hash_value(ints2));
|
ASL_TEST_EXPECT(asl::hash_value(ints1) == asl::hash_value(ints2));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(ints1) != asl::hash_value(ints3));
|
ASL_TEST_EXPECT(asl::hash_value(ints1) != asl::hash_value(ints3));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(ints1) != asl::hash_value(ints4));
|
ASL_TEST_EXPECT(asl::hash_value(ints1) != asl::hash_value(ints4));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(ints1) == asl::hash_value(ints1.as_span()));
|
ASL_TEST_EXPECT(asl::hash_value(ints1) == asl::hash_value(ints1.as_span()));
|
||||||
|
|
||||||
asl::buffer<asl::string_view> strs1;
|
asl::buffer<asl::string_view> strs1;
|
||||||
strs1.push("Hello");
|
strs1.push("Hello");
|
||||||
strs1.push("World");
|
strs1.push("World");
|
||||||
|
|
||||||
asl::buffer<asl::string_view> strs2;
|
asl::buffer<asl::string_view> strs2;
|
||||||
strs2.push("Hello");
|
strs2.push("Hello");
|
||||||
strs2.push("World");
|
strs2.push("World");
|
||||||
|
|
||||||
asl::buffer<asl::string_view> strs3;
|
asl::buffer<asl::string_view> strs3;
|
||||||
strs3.push("Hello");
|
strs3.push("Hello");
|
||||||
strs3.push("world");
|
strs3.push("world");
|
||||||
|
|
||||||
asl::buffer<asl::string_view> strs4;
|
asl::buffer<asl::string_view> strs4;
|
||||||
strs4.push("Hello");
|
strs4.push("Hello");
|
||||||
strs4.push("World");
|
strs4.push("World");
|
||||||
strs4.push("World");
|
strs4.push("World");
|
||||||
|
|
||||||
ASL_TEST_EXPECT(asl::hash_value(strs1) == asl::hash_value(strs2));
|
ASL_TEST_EXPECT(asl::hash_value(strs1) == asl::hash_value(strs2));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(strs1) != asl::hash_value(strs3));
|
ASL_TEST_EXPECT(asl::hash_value(strs1) != asl::hash_value(strs3));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(strs1) != asl::hash_value(strs4));
|
ASL_TEST_EXPECT(asl::hash_value(strs1) != asl::hash_value(strs4));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(strs1) == asl::hash_value(strs1.as_span()));
|
ASL_TEST_EXPECT(asl::hash_value(strs1) == asl::hash_value(strs1.as_span()));
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Enum1 {};
|
enum Enum1 {};
|
||||||
enum class Enum2 {};
|
enum class Enum2 {};
|
||||||
|
|
||||||
static_assert(asl::hashable<Enum1>);
|
static_assert(asl::hashable<Enum1>);
|
||||||
static_assert(asl::hashable<Enum2>);
|
static_assert(asl::hashable<Enum2>);
|
||||||
|
|
||||||
static_assert(!asl::hashable<asl::box<int*>>);
|
static_assert(!asl::hashable<asl::box<int*>>);
|
||||||
static_assert(asl::hashable<asl::box<asl::string_view>>);
|
static_assert(asl::hashable<asl::box<asl::string_view>>);
|
||||||
|
|
||||||
ASL_TEST(box)
|
ASL_TEST(box)
|
||||||
{
|
{
|
||||||
auto b1 = asl::make_box<asl::string_view>("Hello, world!");
|
auto b1 = asl::make_box<asl::string_view>("Hello, world!");
|
||||||
auto b2 = asl::make_box<asl::string_view>("Hello, world!");
|
auto b2 = asl::make_box<asl::string_view>("Hello, world!");
|
||||||
auto b3 = asl::make_box<asl::string_view>("Hello, world! 2");
|
auto b3 = asl::make_box<asl::string_view>("Hello, world! 2");
|
||||||
|
|
||||||
ASL_TEST_EXPECT(asl::hash_value(b1) == asl::hash_value(b2));
|
ASL_TEST_EXPECT(asl::hash_value(b1) == asl::hash_value(b2));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(b1) != asl::hash_value(b3));
|
ASL_TEST_EXPECT(asl::hash_value(b1) != asl::hash_value(b3));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(b1) == asl::hash_value("Hello, world!"_sv));
|
ASL_TEST_EXPECT(asl::hash_value(b1) == asl::hash_value("Hello, world!"_sv));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct NonZero
|
struct NonZero
|
||||||
{
|
{
|
||||||
int value;
|
int value;
|
||||||
|
|
||||||
constexpr explicit NonZero(int x) : value(x)
|
constexpr explicit NonZero(int x) : value(x)
|
||||||
{
|
{
|
||||||
ASL_ASSERT(x != 0);
|
ASL_ASSERT(x != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr explicit NonZero(asl::niche_t) : value(0) {}
|
constexpr explicit NonZero(asl::niche_t) : value(0) {}
|
||||||
|
|
||||||
constexpr bool operator==(asl::niche_t) const { return value == 0; }
|
constexpr bool operator==(asl::niche_t) const { return value == 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace asl { template<> struct is_uniquely_represented<NonZero> : true_type {}; }
|
namespace asl { template<> struct is_uniquely_represented<NonZero> : true_type {}; }
|
||||||
static_assert(asl::has_niche<NonZero>);
|
static_assert(asl::has_niche<NonZero>);
|
||||||
static_assert(asl::uniquely_represented<NonZero>);
|
static_assert(asl::uniquely_represented<NonZero>);
|
||||||
|
|
||||||
static_assert(asl::hashable<asl::option<int>>);
|
static_assert(asl::hashable<asl::option<int>>);
|
||||||
static_assert(!asl::hashable<asl::option<int*>>);
|
static_assert(!asl::hashable<asl::option<int*>>);
|
||||||
static_assert(asl::hashable<asl::option<asl::string_view>>);
|
static_assert(asl::hashable<asl::option<asl::string_view>>);
|
||||||
static_assert(asl::hashable<asl::option<NonZero>>);
|
static_assert(asl::hashable<asl::option<NonZero>>);
|
||||||
static_assert(asl::uniquely_represented<asl::option<NonZero>>);
|
static_assert(asl::uniquely_represented<asl::option<NonZero>>);
|
||||||
|
|
||||||
ASL_TEST(option)
|
ASL_TEST(option)
|
||||||
{
|
{
|
||||||
asl::option<int> int1 = 0;
|
asl::option<int> int1 = 0;
|
||||||
asl::option<int> int2 = 0;
|
asl::option<int> int2 = 0;
|
||||||
asl::option<int> int3 = 1;
|
asl::option<int> int3 = 1;
|
||||||
asl::option<int> int4 = asl::nullopt;
|
asl::option<int> int4 = asl::nullopt;
|
||||||
|
|
||||||
ASL_TEST_EXPECT(asl::hash_value(int1) == asl::hash_value(int2));
|
ASL_TEST_EXPECT(asl::hash_value(int1) == asl::hash_value(int2));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(int1) != asl::hash_value(int3));
|
ASL_TEST_EXPECT(asl::hash_value(int1) != asl::hash_value(int3));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(int1) != asl::hash_value(int4));
|
ASL_TEST_EXPECT(asl::hash_value(int1) != asl::hash_value(int4));
|
||||||
|
|
||||||
asl::option<NonZero> noz1{8};
|
asl::option<NonZero> noz1{8};
|
||||||
asl::option<NonZero> noz2{8};
|
asl::option<NonZero> noz2{8};
|
||||||
asl::option<NonZero> noz3{9};
|
asl::option<NonZero> noz3{9};
|
||||||
asl::option<NonZero> noz4 = asl::nullopt;
|
asl::option<NonZero> noz4 = asl::nullopt;
|
||||||
|
|
||||||
ASL_TEST_EXPECT(asl::hash_value(noz1) == asl::hash_value(noz2));
|
ASL_TEST_EXPECT(asl::hash_value(noz1) == asl::hash_value(noz2));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(noz1) != asl::hash_value(noz3));
|
ASL_TEST_EXPECT(asl::hash_value(noz1) != asl::hash_value(noz3));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(noz1) != asl::hash_value(noz4));
|
ASL_TEST_EXPECT(asl::hash_value(noz1) != asl::hash_value(noz4));
|
||||||
}
|
}
|
||||||
|
|
||||||
static_assert(asl::hashable<asl::status>);
|
static_assert(asl::hashable<asl::status>);
|
||||||
|
|
||||||
ASL_TEST(status)
|
ASL_TEST(status)
|
||||||
{
|
{
|
||||||
asl::status s1 = asl::ok();
|
asl::status s1 = asl::ok();
|
||||||
asl::status s2 = asl::ok();
|
asl::status s2 = asl::ok();
|
||||||
asl::status s3 = asl::internal_error();
|
asl::status s3 = asl::internal_error();
|
||||||
asl::status s4 = asl::internal_error();
|
asl::status s4 = asl::internal_error();
|
||||||
asl::status s5 = asl::runtime_error();
|
asl::status s5 = asl::runtime_error();
|
||||||
asl::status s6 = asl::internal_error("Oh, no!");
|
asl::status s6 = asl::internal_error("Oh, no!");
|
||||||
asl::status s7 = asl::internal_error("Oh, no!");
|
asl::status s7 = asl::internal_error("Oh, no!");
|
||||||
asl::status s8 = asl::internal_error("Oh, no");
|
asl::status s8 = asl::internal_error("Oh, no");
|
||||||
asl::status s9 = asl::runtime_error("Oh, no!");
|
asl::status s9 = asl::runtime_error("Oh, no!");
|
||||||
|
|
||||||
ASL_TEST_EXPECT(asl::hash_value(s1) == asl::hash_value(s2));
|
ASL_TEST_EXPECT(asl::hash_value(s1) == asl::hash_value(s2));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(s3) == asl::hash_value(s4));
|
ASL_TEST_EXPECT(asl::hash_value(s3) == asl::hash_value(s4));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(s6) == asl::hash_value(s7));
|
ASL_TEST_EXPECT(asl::hash_value(s6) == asl::hash_value(s7));
|
||||||
|
|
||||||
ASL_TEST_EXPECT(asl::hash_value(s1) != asl::hash_value(s3));
|
ASL_TEST_EXPECT(asl::hash_value(s1) != asl::hash_value(s3));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(s1) != asl::hash_value(s5));
|
ASL_TEST_EXPECT(asl::hash_value(s1) != asl::hash_value(s5));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(s1) != asl::hash_value(s6));
|
ASL_TEST_EXPECT(asl::hash_value(s1) != asl::hash_value(s6));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(s1) != asl::hash_value(s9));
|
ASL_TEST_EXPECT(asl::hash_value(s1) != asl::hash_value(s9));
|
||||||
|
|
||||||
ASL_TEST_EXPECT(asl::hash_value(s3) != asl::hash_value(s5));
|
ASL_TEST_EXPECT(asl::hash_value(s3) != asl::hash_value(s5));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(s3) != asl::hash_value(s6));
|
ASL_TEST_EXPECT(asl::hash_value(s3) != asl::hash_value(s6));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(s3) != asl::hash_value(s8));
|
ASL_TEST_EXPECT(asl::hash_value(s3) != asl::hash_value(s8));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(s3) != asl::hash_value(s9));
|
ASL_TEST_EXPECT(asl::hash_value(s3) != asl::hash_value(s9));
|
||||||
|
|
||||||
ASL_TEST_EXPECT(asl::hash_value(s6) != asl::hash_value(s8));
|
ASL_TEST_EXPECT(asl::hash_value(s6) != asl::hash_value(s8));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(s6) != asl::hash_value(s9));
|
ASL_TEST_EXPECT(asl::hash_value(s6) != asl::hash_value(s9));
|
||||||
}
|
}
|
||||||
|
|
||||||
static_assert(asl::hashable<asl::status_or<int>>);
|
static_assert(asl::hashable<asl::status_or<int>>);
|
||||||
static_assert(asl::hashable<asl::status_or<asl::string_view>>);
|
static_assert(asl::hashable<asl::status_or<asl::string_view>>);
|
||||||
static_assert(!asl::hashable<asl::status_or<int*>>);
|
static_assert(!asl::hashable<asl::status_or<int*>>);
|
||||||
|
|
||||||
ASL_TEST(status_or)
|
ASL_TEST(status_or)
|
||||||
{
|
{
|
||||||
asl::status_or<int> s1 = 42;
|
asl::status_or<int> s1 = 42;
|
||||||
asl::status_or<int> s2 = 42;
|
asl::status_or<int> s2 = 42;
|
||||||
asl::status_or<int> s3 = 43;
|
asl::status_or<int> s3 = 43;
|
||||||
asl::status_or<int> s4 = asl::runtime_error();
|
asl::status_or<int> s4 = asl::runtime_error();
|
||||||
asl::status_or<int> s5 = asl::runtime_error();
|
asl::status_or<int> s5 = asl::runtime_error();
|
||||||
asl::status_or<int> s6 = asl::runtime_error("Hello");
|
asl::status_or<int> s6 = asl::runtime_error("Hello");
|
||||||
asl::status_or<int> s7 = asl::runtime_error("Hello");
|
asl::status_or<int> s7 = asl::runtime_error("Hello");
|
||||||
|
|
||||||
ASL_TEST_EXPECT(asl::hash_value(s1) == asl::hash_value(s2));
|
ASL_TEST_EXPECT(asl::hash_value(s1) == asl::hash_value(s2));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(s4) == asl::hash_value(s5));
|
ASL_TEST_EXPECT(asl::hash_value(s4) == asl::hash_value(s5));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(s6) == asl::hash_value(s7));
|
ASL_TEST_EXPECT(asl::hash_value(s6) == asl::hash_value(s7));
|
||||||
|
|
||||||
ASL_TEST_EXPECT(asl::hash_value(s1) != asl::hash_value(s3));
|
ASL_TEST_EXPECT(asl::hash_value(s1) != asl::hash_value(s3));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(s1) != asl::hash_value(s4));
|
ASL_TEST_EXPECT(asl::hash_value(s1) != asl::hash_value(s4));
|
||||||
ASL_TEST_EXPECT(asl::hash_value(s1) != asl::hash_value(s6));
|
ASL_TEST_EXPECT(asl::hash_value(s1) != asl::hash_value(s6));
|
||||||
|
|
||||||
ASL_TEST_EXPECT(asl::hash_value(s4) != asl::hash_value(s6));
|
ASL_TEST_EXPECT(asl::hash_value(s4) != asl::hash_value(s6));
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
#include "asl/integers.hpp"
|
#include "asl/integers.hpp"
|
||||||
|
|
||||||
static_assert(sizeof(int8_t) == 1);
|
static_assert(sizeof(int8_t) == 1);
|
||||||
static_assert(sizeof(int16_t) == 2);
|
static_assert(sizeof(int16_t) == 2);
|
||||||
static_assert(sizeof(int32_t) == 4);
|
static_assert(sizeof(int32_t) == 4);
|
||||||
static_assert(sizeof(int64_t) == 8);
|
static_assert(sizeof(int64_t) == 8);
|
||||||
|
|
||||||
static_assert(sizeof(uint8_t) == 1);
|
static_assert(sizeof(uint8_t) == 1);
|
||||||
static_assert(sizeof(uint16_t) == 2);
|
static_assert(sizeof(uint16_t) == 2);
|
||||||
static_assert(sizeof(uint32_t) == 4);
|
static_assert(sizeof(uint32_t) == 4);
|
||||||
static_assert(sizeof(uint64_t) == 8);
|
static_assert(sizeof(uint64_t) == 8);
|
||||||
|
|
||||||
static_assert(sizeof(asl::byte) == 1);
|
static_assert(sizeof(asl::byte) == 1);
|
||||||
|
|
||||||
static_assert(sizeof(uintptr_t) == sizeof(void*));
|
static_assert(sizeof(uintptr_t) == sizeof(void*));
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
#include "asl/maybe_uninit.hpp"
|
#include "asl/maybe_uninit.hpp"
|
||||||
#include "asl/tests/test_types.hpp"
|
#include "asl/tests/test_types.hpp"
|
||||||
|
|
||||||
static_assert(asl::layout::of<int>() == asl::layout::of<asl::maybe_uninit<int>>());
|
static_assert(asl::layout::of<int>() == asl::layout::of<asl::maybe_uninit<int>>());
|
||||||
static_assert(asl::size_of<int> == asl::size_of<asl::maybe_uninit<int>>);
|
static_assert(asl::size_of<int> == asl::size_of<asl::maybe_uninit<int>>);
|
||||||
static_assert(asl::align_of<int> == asl::align_of<asl::maybe_uninit<int>>);
|
static_assert(asl::align_of<int> == asl::align_of<asl::maybe_uninit<int>>);
|
||||||
|
|
||||||
#define TEST_TYPE_PROPERTIES(PRP) \
|
#define TEST_TYPE_PROPERTIES(PRP) \
|
||||||
static_assert(asl::PRP<asl::maybe_uninit<TrivialType>> == asl::PRP<TrivialType>); \
|
static_assert(asl::PRP<asl::maybe_uninit<TrivialType>> == asl::PRP<TrivialType>); \
|
||||||
static_assert(asl::PRP<asl::maybe_uninit<TrivialTypeDefaultValue>> == asl::PRP<TrivialTypeDefaultValue>); \
|
static_assert(asl::PRP<asl::maybe_uninit<TrivialTypeDefaultValue>> == asl::PRP<TrivialTypeDefaultValue>); \
|
||||||
static_assert(asl::PRP<asl::maybe_uninit<WithDestructor>> == asl::PRP<WithDestructor>); \
|
static_assert(asl::PRP<asl::maybe_uninit<WithDestructor>> == asl::PRP<WithDestructor>); \
|
||||||
static_assert(asl::PRP<asl::maybe_uninit<Copyable>> == asl::PRP<Copyable>); \
|
static_assert(asl::PRP<asl::maybe_uninit<Copyable>> == asl::PRP<Copyable>); \
|
||||||
static_assert(asl::PRP<asl::maybe_uninit<MoveableOnly>> == asl::PRP<MoveableOnly>); \
|
static_assert(asl::PRP<asl::maybe_uninit<MoveableOnly>> == asl::PRP<MoveableOnly>); \
|
||||||
static_assert(asl::PRP<asl::maybe_uninit<Pinned>> == asl::PRP<Pinned>);
|
static_assert(asl::PRP<asl::maybe_uninit<Pinned>> == asl::PRP<Pinned>);
|
||||||
|
|
||||||
TEST_TYPE_PROPERTIES(trivially_default_constructible);
|
TEST_TYPE_PROPERTIES(trivially_default_constructible);
|
||||||
TEST_TYPE_PROPERTIES(trivially_copy_constructible);
|
TEST_TYPE_PROPERTIES(trivially_copy_constructible);
|
||||||
TEST_TYPE_PROPERTIES(trivially_move_constructible);
|
TEST_TYPE_PROPERTIES(trivially_move_constructible);
|
||||||
TEST_TYPE_PROPERTIES(trivially_copy_assignable);
|
TEST_TYPE_PROPERTIES(trivially_copy_assignable);
|
||||||
TEST_TYPE_PROPERTIES(trivially_move_assignable);
|
TEST_TYPE_PROPERTIES(trivially_move_assignable);
|
||||||
TEST_TYPE_PROPERTIES(trivially_destructible);
|
TEST_TYPE_PROPERTIES(trivially_destructible);
|
||||||
|
|
||||||
|
@ -1,249 +1,249 @@
|
|||||||
#include "asl/meta.hpp"
|
#include "asl/meta.hpp"
|
||||||
#include "asl/tests/test_types.hpp"
|
#include "asl/tests/test_types.hpp"
|
||||||
|
|
||||||
struct Struct {};
|
struct Struct {};
|
||||||
union Union {};
|
union Union {};
|
||||||
enum Enum : uint8_t { EnumVariant = 0, };
|
enum Enum : uint8_t { EnumVariant = 0, };
|
||||||
enum class EnumClass : uint8_t { Variant = 0, };
|
enum class EnumClass : uint8_t { Variant = 0, };
|
||||||
|
|
||||||
static_assert(!asl::same_as<long, short>);
|
static_assert(!asl::same_as<long, short>);
|
||||||
static_assert(asl::same_as<int, int>);
|
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<false, int, float>, float>);
|
||||||
static_assert(asl::same_as<asl::select_t<true, int, float>, int>);
|
static_assert(asl::same_as<asl::select_t<true, int, float>, int>);
|
||||||
|
|
||||||
static_assert(asl::default_constructible<int>);
|
static_assert(asl::default_constructible<int>);
|
||||||
static_assert(asl::default_constructible<TrivialType>);
|
static_assert(asl::default_constructible<TrivialType>);
|
||||||
static_assert(asl::default_constructible<TrivialTypeDefaultValue>);
|
static_assert(asl::default_constructible<TrivialTypeDefaultValue>);
|
||||||
|
|
||||||
static_assert(asl::trivially_default_constructible<int>);
|
static_assert(asl::trivially_default_constructible<int>);
|
||||||
static_assert(asl::trivially_default_constructible<TrivialType>);
|
static_assert(asl::trivially_default_constructible<TrivialType>);
|
||||||
static_assert(!asl::trivially_default_constructible<TrivialTypeDefaultValue>);
|
static_assert(!asl::trivially_default_constructible<TrivialTypeDefaultValue>);
|
||||||
|
|
||||||
static_assert(asl::copy_constructible<int>);
|
static_assert(asl::copy_constructible<int>);
|
||||||
static_assert(asl::copy_constructible<TrivialType>);
|
static_assert(asl::copy_constructible<TrivialType>);
|
||||||
static_assert(asl::copy_constructible<Copyable>);
|
static_assert(asl::copy_constructible<Copyable>);
|
||||||
static_assert(!asl::copy_constructible<MoveableOnly>);
|
static_assert(!asl::copy_constructible<MoveableOnly>);
|
||||||
static_assert(!asl::copy_constructible<Pinned>);
|
static_assert(!asl::copy_constructible<Pinned>);
|
||||||
|
|
||||||
static_assert(asl::trivially_copy_constructible<int>);
|
static_assert(asl::trivially_copy_constructible<int>);
|
||||||
static_assert(asl::trivially_copy_constructible<TrivialType>);
|
static_assert(asl::trivially_copy_constructible<TrivialType>);
|
||||||
static_assert(asl::trivially_copy_constructible<TrivialTypeDefaultValue>);
|
static_assert(asl::trivially_copy_constructible<TrivialTypeDefaultValue>);
|
||||||
static_assert(!asl::trivially_copy_constructible<WithDestructor>);
|
static_assert(!asl::trivially_copy_constructible<WithDestructor>);
|
||||||
static_assert(!asl::trivially_copy_constructible<Copyable>);
|
static_assert(!asl::trivially_copy_constructible<Copyable>);
|
||||||
static_assert(!asl::trivially_copy_constructible<MoveableOnly>);
|
static_assert(!asl::trivially_copy_constructible<MoveableOnly>);
|
||||||
static_assert(!asl::trivially_copy_constructible<Pinned>);
|
static_assert(!asl::trivially_copy_constructible<Pinned>);
|
||||||
|
|
||||||
static_assert(asl::move_constructible<int>);
|
static_assert(asl::move_constructible<int>);
|
||||||
static_assert(asl::move_constructible<TrivialType>);
|
static_assert(asl::move_constructible<TrivialType>);
|
||||||
static_assert(asl::move_constructible<Copyable>);
|
static_assert(asl::move_constructible<Copyable>);
|
||||||
static_assert(asl::move_constructible<MoveableOnly>);
|
static_assert(asl::move_constructible<MoveableOnly>);
|
||||||
static_assert(!asl::move_constructible<Pinned>);
|
static_assert(!asl::move_constructible<Pinned>);
|
||||||
|
|
||||||
static_assert(asl::trivially_move_constructible<int>);
|
static_assert(asl::trivially_move_constructible<int>);
|
||||||
static_assert(asl::trivially_move_constructible<TrivialType>);
|
static_assert(asl::trivially_move_constructible<TrivialType>);
|
||||||
static_assert(asl::trivially_move_constructible<TrivialTypeDefaultValue>);
|
static_assert(asl::trivially_move_constructible<TrivialTypeDefaultValue>);
|
||||||
static_assert(!asl::trivially_move_constructible<WithDestructor>);
|
static_assert(!asl::trivially_move_constructible<WithDestructor>);
|
||||||
static_assert(!asl::trivially_move_constructible<Copyable>);
|
static_assert(!asl::trivially_move_constructible<Copyable>);
|
||||||
static_assert(!asl::trivially_move_constructible<MoveableOnly>);
|
static_assert(!asl::trivially_move_constructible<MoveableOnly>);
|
||||||
static_assert(!asl::trivially_move_constructible<Pinned>);
|
static_assert(!asl::trivially_move_constructible<Pinned>);
|
||||||
|
|
||||||
static_assert(asl::copy_assignable<int>);
|
static_assert(asl::copy_assignable<int>);
|
||||||
static_assert(asl::copy_assignable<TrivialType>);
|
static_assert(asl::copy_assignable<TrivialType>);
|
||||||
static_assert(asl::copy_assignable<Copyable>);
|
static_assert(asl::copy_assignable<Copyable>);
|
||||||
static_assert(!asl::copy_assignable<MoveableOnly>);
|
static_assert(!asl::copy_assignable<MoveableOnly>);
|
||||||
static_assert(!asl::copy_assignable<Pinned>);
|
static_assert(!asl::copy_assignable<Pinned>);
|
||||||
|
|
||||||
static_assert(asl::trivially_copy_assignable<int>);
|
static_assert(asl::trivially_copy_assignable<int>);
|
||||||
static_assert(asl::trivially_copy_assignable<TrivialType>);
|
static_assert(asl::trivially_copy_assignable<TrivialType>);
|
||||||
static_assert(asl::trivially_copy_assignable<TrivialTypeDefaultValue>);
|
static_assert(asl::trivially_copy_assignable<TrivialTypeDefaultValue>);
|
||||||
static_assert(asl::trivially_copy_assignable<WithDestructor>);
|
static_assert(asl::trivially_copy_assignable<WithDestructor>);
|
||||||
static_assert(!asl::trivially_copy_assignable<Copyable>);
|
static_assert(!asl::trivially_copy_assignable<Copyable>);
|
||||||
static_assert(!asl::trivially_copy_assignable<MoveableOnly>);
|
static_assert(!asl::trivially_copy_assignable<MoveableOnly>);
|
||||||
static_assert(!asl::trivially_copy_assignable<Pinned>);
|
static_assert(!asl::trivially_copy_assignable<Pinned>);
|
||||||
|
|
||||||
static_assert(asl::copyable<int>);
|
static_assert(asl::copyable<int>);
|
||||||
static_assert(asl::copyable<TrivialType>);
|
static_assert(asl::copyable<TrivialType>);
|
||||||
static_assert(asl::copyable<Copyable>);
|
static_assert(asl::copyable<Copyable>);
|
||||||
static_assert(!asl::copyable<MoveableOnly>);
|
static_assert(!asl::copyable<MoveableOnly>);
|
||||||
static_assert(!asl::copyable<Pinned>);
|
static_assert(!asl::copyable<Pinned>);
|
||||||
|
|
||||||
static_assert(asl::moveable<int>);
|
static_assert(asl::moveable<int>);
|
||||||
static_assert(asl::moveable<TrivialType>);
|
static_assert(asl::moveable<TrivialType>);
|
||||||
static_assert(asl::moveable<Copyable>);
|
static_assert(asl::moveable<Copyable>);
|
||||||
static_assert(asl::moveable<MoveableOnly>);
|
static_assert(asl::moveable<MoveableOnly>);
|
||||||
static_assert(!asl::moveable<Pinned>);
|
static_assert(!asl::moveable<Pinned>);
|
||||||
|
|
||||||
static_assert(asl::move_assignable<int>);
|
static_assert(asl::move_assignable<int>);
|
||||||
static_assert(asl::move_assignable<TrivialType>);
|
static_assert(asl::move_assignable<TrivialType>);
|
||||||
static_assert(asl::move_assignable<Copyable>);
|
static_assert(asl::move_assignable<Copyable>);
|
||||||
static_assert(asl::move_assignable<MoveableOnly>);
|
static_assert(asl::move_assignable<MoveableOnly>);
|
||||||
static_assert(!asl::move_assignable<Pinned>);
|
static_assert(!asl::move_assignable<Pinned>);
|
||||||
|
|
||||||
static_assert(asl::trivially_move_assignable<int>);
|
static_assert(asl::trivially_move_assignable<int>);
|
||||||
static_assert(asl::trivially_move_assignable<TrivialType>);
|
static_assert(asl::trivially_move_assignable<TrivialType>);
|
||||||
static_assert(asl::trivially_move_assignable<TrivialTypeDefaultValue>);
|
static_assert(asl::trivially_move_assignable<TrivialTypeDefaultValue>);
|
||||||
static_assert(asl::trivially_move_assignable<WithDestructor>);
|
static_assert(asl::trivially_move_assignable<WithDestructor>);
|
||||||
static_assert(!asl::trivially_move_assignable<Copyable>);
|
static_assert(!asl::trivially_move_assignable<Copyable>);
|
||||||
static_assert(!asl::trivially_move_assignable<MoveableOnly>);
|
static_assert(!asl::trivially_move_assignable<MoveableOnly>);
|
||||||
static_assert(!asl::trivially_move_assignable<Pinned>);
|
static_assert(!asl::trivially_move_assignable<Pinned>);
|
||||||
|
|
||||||
static_assert(asl::trivially_destructible<int>);
|
static_assert(asl::trivially_destructible<int>);
|
||||||
static_assert(asl::trivially_destructible<TrivialType>);
|
static_assert(asl::trivially_destructible<TrivialType>);
|
||||||
static_assert(asl::trivially_destructible<TrivialTypeDefaultValue>);
|
static_assert(asl::trivially_destructible<TrivialTypeDefaultValue>);
|
||||||
static_assert(!asl::trivially_destructible<WithDestructor>);
|
static_assert(!asl::trivially_destructible<WithDestructor>);
|
||||||
static_assert(asl::trivially_destructible<Copyable>);
|
static_assert(asl::trivially_destructible<Copyable>);
|
||||||
static_assert(asl::trivially_destructible<MoveableOnly>);
|
static_assert(asl::trivially_destructible<MoveableOnly>);
|
||||||
static_assert(asl::trivially_destructible<Pinned>);
|
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<int>>);
|
||||||
static_assert(asl::same_as<int, asl::un_const_t<const 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<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<int>>);
|
||||||
static_assert(asl::same_as<int, asl::un_volatile_t<volatile 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<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<int>>);
|
||||||
static_assert(asl::same_as<int, asl::un_cv_t<const 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<const volatile int>>);
|
||||||
static_assert(asl::same_as<int, asl::un_cv_t<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<void>);
|
||||||
static_assert(asl::is_void<const void>);
|
static_assert(asl::is_void<const void>);
|
||||||
static_assert(asl::is_void<const volatile void>);
|
static_assert(asl::is_void<const volatile void>);
|
||||||
static_assert(asl::is_void<volatile void>);
|
static_assert(asl::is_void<volatile void>);
|
||||||
static_assert(!asl::is_void<int>);
|
static_assert(!asl::is_void<int>);
|
||||||
static_assert(!asl::is_void<Struct>);
|
static_assert(!asl::is_void<Struct>);
|
||||||
static_assert(!asl::is_void<int&>);
|
static_assert(!asl::is_void<int&>);
|
||||||
static_assert(!asl::is_void<int&&>);
|
static_assert(!asl::is_void<int&&>);
|
||||||
static_assert(!asl::is_void<void()>);
|
static_assert(!asl::is_void<void()>);
|
||||||
static_assert(!asl::is_void<void() const &&>);
|
static_assert(!asl::is_void<void() const &&>);
|
||||||
|
|
||||||
static_assert(asl::is_ref<int&>);
|
static_assert(asl::is_ref<int&>);
|
||||||
static_assert(asl::is_ref<const int&>);
|
static_assert(asl::is_ref<const int&>);
|
||||||
static_assert(asl::is_ref<const volatile 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<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()>);
|
static_assert(!asl::is_ref<void()>);
|
||||||
static_assert(!asl::is_ref<void() const &&>);
|
static_assert(!asl::is_ref<void() const &&>);
|
||||||
|
|
||||||
static_assert(asl::is_ptr<int*>);
|
static_assert(asl::is_ptr<int*>);
|
||||||
static_assert(asl::is_ptr<const int* const>);
|
static_assert(asl::is_ptr<const int* const>);
|
||||||
static_assert(asl::is_ptr<const volatile int*>);
|
static_assert(asl::is_ptr<const volatile int*>);
|
||||||
static_assert(!asl::is_ptr<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()>);
|
static_assert(!asl::is_ptr<void()>);
|
||||||
static_assert(!asl::is_ptr<void() const &&>);
|
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(), 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) &>>);
|
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) 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) 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) && noexcept>>);
|
||||||
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) const>>);
|
||||||
|
|
||||||
static_assert(asl::is_func<void()>);
|
static_assert(asl::is_func<void()>);
|
||||||
static_assert(asl::is_func<void(int)>);
|
static_assert(asl::is_func<void(int)>);
|
||||||
static_assert(asl::is_func<void(int, float)>);
|
static_assert(asl::is_func<void(int, float)>);
|
||||||
static_assert(asl::is_func<void() &>);
|
static_assert(asl::is_func<void() &>);
|
||||||
static_assert(asl::is_func<void() const &&>);
|
static_assert(asl::is_func<void() const &&>);
|
||||||
static_assert(asl::is_func<void() volatile noexcept>);
|
static_assert(asl::is_func<void() volatile noexcept>);
|
||||||
static_assert(!asl::is_func<void(*)()>);
|
static_assert(!asl::is_func<void(*)()>);
|
||||||
static_assert(!asl::is_func<int>);
|
static_assert(!asl::is_func<int>);
|
||||||
static_assert(!asl::is_func<int&>);
|
static_assert(!asl::is_func<int&>);
|
||||||
static_assert(!asl::is_func<void>);
|
static_assert(!asl::is_func<void>);
|
||||||
|
|
||||||
static_assert(asl::is_object<Struct>);
|
static_assert(asl::is_object<Struct>);
|
||||||
static_assert(asl::is_object<int>);
|
static_assert(asl::is_object<int>);
|
||||||
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::*>);
|
||||||
static_assert(asl::is_object<int (Struct::*)(float)>);
|
static_assert(asl::is_object<int (Struct::*)(float)>);
|
||||||
static_assert(asl::is_object<int[]>);
|
static_assert(asl::is_object<int[]>);
|
||||||
static_assert(asl::is_object<int[45]>);
|
static_assert(asl::is_object<int[45]>);
|
||||||
static_assert(asl::is_object<Enum>);
|
static_assert(asl::is_object<Enum>);
|
||||||
static_assert(!asl::is_object<int&>);
|
static_assert(!asl::is_object<int&>);
|
||||||
static_assert(!asl::is_object<void>);
|
static_assert(!asl::is_object<void>);
|
||||||
static_assert(!asl::is_object<void(int)>);
|
static_assert(!asl::is_object<void(int)>);
|
||||||
static_assert(!asl::is_object<int(float) const && noexcept>);
|
static_assert(!asl::is_object<int(float) const && noexcept>);
|
||||||
|
|
||||||
static_assert(!asl::is_array<Struct>);
|
static_assert(!asl::is_array<Struct>);
|
||||||
static_assert(!asl::is_array<int>);
|
static_assert(!asl::is_array<int>);
|
||||||
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::*>);
|
||||||
static_assert(!asl::is_array<int (Struct::*)(float)>);
|
static_assert(!asl::is_array<int (Struct::*)(float)>);
|
||||||
static_assert(asl::is_array<int[]>);
|
static_assert(asl::is_array<int[]>);
|
||||||
static_assert(asl::is_array<int[45]>);
|
static_assert(asl::is_array<int[45]>);
|
||||||
static_assert(!asl::is_array<Enum>);
|
static_assert(!asl::is_array<Enum>);
|
||||||
static_assert(!asl::is_array<int&>);
|
static_assert(!asl::is_array<int&>);
|
||||||
static_assert(!asl::is_array<void>);
|
static_assert(!asl::is_array<void>);
|
||||||
static_assert(!asl::is_array<void(int)>);
|
static_assert(!asl::is_array<void(int)>);
|
||||||
static_assert(!asl::is_array<int(float) const && noexcept>);
|
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::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, float> == 2);
|
||||||
static_assert(asl::types_count<int, int> == 2);
|
static_assert(asl::types_count<int, int> == 2);
|
||||||
static_assert(asl::types_count<int> == 1);
|
static_assert(asl::types_count<int> == 1);
|
||||||
static_assert(asl::types_count<> == 0);
|
static_assert(asl::types_count<> == 0);
|
||||||
|
|
||||||
class Base {};
|
class Base {};
|
||||||
class Derived : public Base {};
|
class Derived : public Base {};
|
||||||
class C {};
|
class C {};
|
||||||
class D { public: operator C() { return c; } C c; }; // NOLINT
|
class D { public: operator C() { return c; } C c; }; // NOLINT
|
||||||
class E { public: template<class T> E(T&&) {} }; // NOLINT
|
class E { public: template<class T> E(T&&) {} }; // NOLINT
|
||||||
|
|
||||||
static_assert(asl::convertible_from<Base*, Derived*>);
|
static_assert(asl::convertible_from<Base*, Derived*>);
|
||||||
static_assert(!asl::convertible_from<Derived*, Base*>);
|
static_assert(!asl::convertible_from<Derived*, Base*>);
|
||||||
static_assert(asl::convertible_from<C, D>);
|
static_assert(asl::convertible_from<C, D>);
|
||||||
static_assert(!asl::convertible_from<C*, Derived*>);
|
static_assert(!asl::convertible_from<C*, Derived*>);
|
||||||
static_assert(asl::convertible_from<E, Base>);
|
static_assert(asl::convertible_from<E, Base>);
|
||||||
|
|
||||||
static_assert(!asl::convertible_from<int16_t(&)[], int32_t(&)[]>);
|
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(&)[], int16_t(&)[]>);
|
||||||
static_assert(asl::convertible_from<const int16_t(&)[], const 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<int16_t(&)[], int16_t(&)[]>);
|
||||||
static_assert(!asl::convertible_from<int32_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<int16_t(&)[], const int16_t(&)[]>);
|
||||||
static_assert(!asl::convertible_from<C(&)[], D(&)[]>);
|
static_assert(!asl::convertible_from<C(&)[], D(&)[]>);
|
||||||
|
|
||||||
static_assert(asl::derived_from<Derived, Base>);
|
static_assert(asl::derived_from<Derived, Base>);
|
||||||
static_assert(!asl::derived_from<Base, Derived>);
|
static_assert(!asl::derived_from<Base, Derived>);
|
||||||
static_assert(!asl::derived_from<D, C>);
|
static_assert(!asl::derived_from<D, C>);
|
||||||
static_assert(!asl::derived_from<C, D>);
|
static_assert(!asl::derived_from<C, D>);
|
||||||
static_assert(!asl::derived_from<uint8_t, uint16_t>);
|
static_assert(!asl::derived_from<uint8_t, uint16_t>);
|
||||||
static_assert(!asl::derived_from<uint16_t, uint8_t>);
|
static_assert(!asl::derived_from<uint16_t, uint8_t>);
|
||||||
static_assert(!asl::derived_from<int, int>);
|
static_assert(!asl::derived_from<int, int>);
|
||||||
|
|
||||||
static_assert(!asl::is_const<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<const int*>);
|
static_assert(!asl::is_const<const int*>);
|
||||||
static_assert(asl::is_const<int* const>);
|
static_assert(asl::is_const<int* const>);
|
||||||
|
|
||||||
static_assert(asl::is_floating_point<float>);
|
static_assert(asl::is_floating_point<float>);
|
||||||
static_assert(asl::is_floating_point<const float>);
|
static_assert(asl::is_floating_point<const float>);
|
||||||
static_assert(asl::is_floating_point<volatile double>);
|
static_assert(asl::is_floating_point<volatile double>);
|
||||||
static_assert(!asl::is_floating_point<const float&>);
|
static_assert(!asl::is_floating_point<const float&>);
|
||||||
static_assert(!asl::is_floating_point<int>);
|
static_assert(!asl::is_floating_point<int>);
|
||||||
static_assert(!asl::is_floating_point<C>);
|
static_assert(!asl::is_floating_point<C>);
|
||||||
|
|
||||||
static_assert(asl::uniquely_represented<int>);
|
static_assert(asl::uniquely_represented<int>);
|
||||||
static_assert(asl::uniquely_represented<uint128_t>);
|
static_assert(asl::uniquely_represented<uint128_t>);
|
||||||
static_assert(!asl::uniquely_represented<bool>);
|
static_assert(!asl::uniquely_represented<bool>);
|
||||||
|
|
||||||
enum Enum1 {};
|
enum Enum1 {};
|
||||||
enum class Enum2 {};
|
enum class Enum2 {};
|
||||||
|
|
||||||
static_assert(asl::uniquely_represented<Enum1>);
|
static_assert(asl::uniquely_represented<Enum1>);
|
||||||
static_assert(asl::uniquely_represented<Enum2>);
|
static_assert(asl::uniquely_represented<Enum2>);
|
||||||
|
|
||||||
static_assert(!asl::is_enum<int>);
|
static_assert(!asl::is_enum<int>);
|
||||||
static_assert(asl::is_enum<Enum1>);
|
static_assert(asl::is_enum<Enum1>);
|
||||||
static_assert(asl::is_enum<Enum2>);
|
static_assert(asl::is_enum<Enum2>);
|
||||||
|
|
||||||
|
@ -1,330 +1,330 @@
|
|||||||
#include "asl/option.hpp"
|
#include "asl/option.hpp"
|
||||||
#include "asl/tests/test_types.hpp"
|
#include "asl/tests/test_types.hpp"
|
||||||
#include "asl/testing/testing.hpp"
|
#include "asl/testing/testing.hpp"
|
||||||
|
|
||||||
class Base {};
|
class Base {};
|
||||||
class Derived : public Base {};
|
class Derived : public Base {};
|
||||||
|
|
||||||
struct NonZero
|
struct NonZero
|
||||||
{
|
{
|
||||||
int value;
|
int value;
|
||||||
|
|
||||||
constexpr explicit NonZero(int x) : value(x)
|
constexpr explicit NonZero(int x) : value(x)
|
||||||
{
|
{
|
||||||
ASL_ASSERT(x != 0);
|
ASL_ASSERT(x != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr explicit NonZero(asl::niche_t) : value(0) {}
|
constexpr explicit NonZero(asl::niche_t) : value(0) {}
|
||||||
|
|
||||||
constexpr bool operator==(asl::niche_t) const { return value == 0; }
|
constexpr bool operator==(asl::niche_t) const { return value == 0; }
|
||||||
};
|
};
|
||||||
static_assert(asl::has_niche<NonZero>);
|
static_assert(asl::has_niche<NonZero>);
|
||||||
static_assert(!asl::has_niche<int>);
|
static_assert(!asl::has_niche<int>);
|
||||||
|
|
||||||
static_assert(sizeof(asl::option<int>) >= sizeof(int));
|
static_assert(sizeof(asl::option<int>) >= sizeof(int));
|
||||||
static_assert(sizeof(asl::option<NonZero>) == sizeof(NonZero));
|
static_assert(sizeof(asl::option<NonZero>) == sizeof(NonZero));
|
||||||
|
|
||||||
static_assert(!asl::is_option<int>);
|
static_assert(!asl::is_option<int>);
|
||||||
static_assert(asl::is_option<asl::option<int>>);
|
static_assert(asl::is_option<asl::option<int>>);
|
||||||
static_assert(asl::is_option<const asl::option<int>>);
|
static_assert(asl::is_option<const asl::option<int>>);
|
||||||
|
|
||||||
static_assert(asl::trivially_destructible<asl::option<TrivialType>>);
|
static_assert(asl::trivially_destructible<asl::option<TrivialType>>);
|
||||||
static_assert(!asl::trivially_destructible<asl::option<WithDestructor>>);
|
static_assert(!asl::trivially_destructible<asl::option<WithDestructor>>);
|
||||||
|
|
||||||
static_assert(asl::trivially_copy_constructible<asl::option<int>>);
|
static_assert(asl::trivially_copy_constructible<asl::option<int>>);
|
||||||
static_assert(asl::trivially_copy_constructible<asl::option<NonZero>>);
|
static_assert(asl::trivially_copy_constructible<asl::option<NonZero>>);
|
||||||
static_assert(asl::copy_constructible<asl::option<Copyable>>);
|
static_assert(asl::copy_constructible<asl::option<Copyable>>);
|
||||||
static_assert(!asl::copy_constructible<asl::option<MoveableOnly>>);
|
static_assert(!asl::copy_constructible<asl::option<MoveableOnly>>);
|
||||||
static_assert(!asl::copy_constructible<asl::option<Pinned>>);
|
static_assert(!asl::copy_constructible<asl::option<Pinned>>);
|
||||||
|
|
||||||
static_assert(asl::trivially_move_constructible<asl::option<int>>);
|
static_assert(asl::trivially_move_constructible<asl::option<int>>);
|
||||||
static_assert(asl::trivially_move_constructible<asl::option<NonZero>>);
|
static_assert(asl::trivially_move_constructible<asl::option<NonZero>>);
|
||||||
static_assert(asl::move_constructible<asl::option<Copyable>>);
|
static_assert(asl::move_constructible<asl::option<Copyable>>);
|
||||||
static_assert(asl::move_constructible<asl::option<MoveableOnly>>);
|
static_assert(asl::move_constructible<asl::option<MoveableOnly>>);
|
||||||
static_assert(!asl::move_constructible<asl::option<Pinned>>);
|
static_assert(!asl::move_constructible<asl::option<Pinned>>);
|
||||||
|
|
||||||
static_assert(asl::trivially_copy_assignable<asl::option<int>>);
|
static_assert(asl::trivially_copy_assignable<asl::option<int>>);
|
||||||
static_assert(asl::trivially_copy_assignable<asl::option<NonZero>>);
|
static_assert(asl::trivially_copy_assignable<asl::option<NonZero>>);
|
||||||
static_assert(asl::copy_assignable<asl::option<Copyable>>);
|
static_assert(asl::copy_assignable<asl::option<Copyable>>);
|
||||||
static_assert(!asl::copy_assignable<asl::option<MoveableOnly>>);
|
static_assert(!asl::copy_assignable<asl::option<MoveableOnly>>);
|
||||||
static_assert(!asl::copy_assignable<asl::option<Pinned>>);
|
static_assert(!asl::copy_assignable<asl::option<Pinned>>);
|
||||||
|
|
||||||
static_assert(asl::trivially_move_assignable<asl::option<int>>);
|
static_assert(asl::trivially_move_assignable<asl::option<int>>);
|
||||||
static_assert(asl::trivially_move_assignable<asl::option<NonZero>>);
|
static_assert(asl::trivially_move_assignable<asl::option<NonZero>>);
|
||||||
static_assert(asl::move_assignable<asl::option<Copyable>>);
|
static_assert(asl::move_assignable<asl::option<Copyable>>);
|
||||||
static_assert(asl::move_assignable<asl::option<MoveableOnly>>);
|
static_assert(asl::move_assignable<asl::option<MoveableOnly>>);
|
||||||
static_assert(!asl::move_assignable<asl::option<Pinned>>);
|
static_assert(!asl::move_assignable<asl::option<Pinned>>);
|
||||||
|
|
||||||
static_assert(asl::assignable_from<asl::option<Base*>&, asl::option<Derived*>>);
|
static_assert(asl::assignable_from<asl::option<Base*>&, asl::option<Derived*>>);
|
||||||
static_assert(!asl::assignable_from<asl::option<Derived*>&, asl::option<Base*>>);
|
static_assert(!asl::assignable_from<asl::option<Derived*>&, asl::option<Base*>>);
|
||||||
|
|
||||||
static_assert(asl::convertible_from<asl::option<Base*>, asl::option<Derived*>>);
|
static_assert(asl::convertible_from<asl::option<Base*>, asl::option<Derived*>>);
|
||||||
static_assert(!asl::convertible_from<asl::option<Derived*>, asl::option<Base*>>);
|
static_assert(!asl::convertible_from<asl::option<Derived*>, asl::option<Base*>>);
|
||||||
|
|
||||||
class ExplicitConversion { public: explicit ExplicitConversion(int) {} };
|
class ExplicitConversion { public: explicit ExplicitConversion(int) {} };
|
||||||
class ImplicitConversion { public: ImplicitConversion(int) {} }; // NOLINT
|
class ImplicitConversion { public: ImplicitConversion(int) {} }; // NOLINT
|
||||||
|
|
||||||
static_assert(!asl::convertible_from<ExplicitConversion, int>);
|
static_assert(!asl::convertible_from<ExplicitConversion, int>);
|
||||||
static_assert(asl::convertible_from<ImplicitConversion, int>);
|
static_assert(asl::convertible_from<ImplicitConversion, int>);
|
||||||
|
|
||||||
static_assert(!asl::convertible_from<asl::option<ExplicitConversion>, int>);
|
static_assert(!asl::convertible_from<asl::option<ExplicitConversion>, int>);
|
||||||
static_assert(asl::convertible_from<asl::option<ImplicitConversion>, int>);
|
static_assert(asl::convertible_from<asl::option<ImplicitConversion>, int>);
|
||||||
|
|
||||||
static_assert(!asl::convertible_from<asl::option<ExplicitConversion>, asl::option<int>>);
|
static_assert(!asl::convertible_from<asl::option<ExplicitConversion>, asl::option<int>>);
|
||||||
static_assert(asl::convertible_from<asl::option<ImplicitConversion>, asl::option<int>>);
|
static_assert(asl::convertible_from<asl::option<ImplicitConversion>, asl::option<int>>);
|
||||||
|
|
||||||
static_assert(asl::trivially_copy_constructible<asl::option<int>>);
|
static_assert(asl::trivially_copy_constructible<asl::option<int>>);
|
||||||
static_assert(asl::trivially_copy_constructible<asl::option<TrivialType>>);
|
static_assert(asl::trivially_copy_constructible<asl::option<TrivialType>>);
|
||||||
static_assert(asl::trivially_copy_constructible<asl::option<TrivialTypeDefaultValue>>);
|
static_assert(asl::trivially_copy_constructible<asl::option<TrivialTypeDefaultValue>>);
|
||||||
static_assert(!asl::trivially_copy_constructible<asl::option<Copyable>>);
|
static_assert(!asl::trivially_copy_constructible<asl::option<Copyable>>);
|
||||||
|
|
||||||
static_assert(asl::trivially_move_constructible<asl::option<int>>);
|
static_assert(asl::trivially_move_constructible<asl::option<int>>);
|
||||||
static_assert(asl::trivially_move_constructible<asl::option<TrivialType>>);
|
static_assert(asl::trivially_move_constructible<asl::option<TrivialType>>);
|
||||||
static_assert(asl::trivially_move_constructible<asl::option<TrivialTypeDefaultValue>>);
|
static_assert(asl::trivially_move_constructible<asl::option<TrivialTypeDefaultValue>>);
|
||||||
static_assert(!asl::trivially_move_constructible<asl::option<MoveableOnly>>);
|
static_assert(!asl::trivially_move_constructible<asl::option<MoveableOnly>>);
|
||||||
|
|
||||||
static_assert(asl::trivially_copy_assignable<asl::option<int>>);
|
static_assert(asl::trivially_copy_assignable<asl::option<int>>);
|
||||||
static_assert(asl::trivially_copy_assignable<asl::option<TrivialType>>);
|
static_assert(asl::trivially_copy_assignable<asl::option<TrivialType>>);
|
||||||
static_assert(asl::trivially_copy_assignable<asl::option<TrivialTypeDefaultValue>>);
|
static_assert(asl::trivially_copy_assignable<asl::option<TrivialTypeDefaultValue>>);
|
||||||
static_assert(!asl::trivially_copy_assignable<asl::option<Copyable>>);
|
static_assert(!asl::trivially_copy_assignable<asl::option<Copyable>>);
|
||||||
|
|
||||||
static_assert(asl::trivially_move_assignable<asl::option<int>>);
|
static_assert(asl::trivially_move_assignable<asl::option<int>>);
|
||||||
static_assert(asl::trivially_move_assignable<asl::option<TrivialType>>);
|
static_assert(asl::trivially_move_assignable<asl::option<TrivialType>>);
|
||||||
static_assert(asl::trivially_move_assignable<asl::option<TrivialTypeDefaultValue>>);
|
static_assert(asl::trivially_move_assignable<asl::option<TrivialTypeDefaultValue>>);
|
||||||
static_assert(!asl::trivially_move_assignable<asl::option<MoveableOnly>>);
|
static_assert(!asl::trivially_move_assignable<asl::option<MoveableOnly>>);
|
||||||
|
|
||||||
ASL_TEST(make_null)
|
ASL_TEST(make_null)
|
||||||
{
|
{
|
||||||
asl::option<int> a;
|
asl::option<int> a;
|
||||||
asl::option<int> b = asl::nullopt;
|
asl::option<int> b = asl::nullopt;
|
||||||
|
|
||||||
ASL_TEST_EXPECT(!a.has_value());
|
ASL_TEST_EXPECT(!a.has_value());
|
||||||
ASL_TEST_EXPECT(!b.has_value());
|
ASL_TEST_EXPECT(!b.has_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(make_value)
|
ASL_TEST(make_value)
|
||||||
{
|
{
|
||||||
asl::option<int> a = 48;
|
asl::option<int> a = 48;
|
||||||
|
|
||||||
ASL_TEST_EXPECT(a.has_value());
|
ASL_TEST_EXPECT(a.has_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(reset)
|
ASL_TEST(reset)
|
||||||
{
|
{
|
||||||
asl::option<int> b = 48;
|
asl::option<int> b = 48;
|
||||||
ASL_TEST_EXPECT(b.has_value());
|
ASL_TEST_EXPECT(b.has_value());
|
||||||
|
|
||||||
b.reset();
|
b.reset();
|
||||||
ASL_TEST_EXPECT(!b.has_value());
|
ASL_TEST_EXPECT(!b.has_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(call_destructor)
|
ASL_TEST(call_destructor)
|
||||||
{
|
{
|
||||||
bool destroyed = false;
|
bool destroyed = false;
|
||||||
|
|
||||||
{
|
{
|
||||||
DestructorObserver obs(&destroyed);
|
DestructorObserver obs(&destroyed);
|
||||||
|
|
||||||
asl::option<DestructorObserver> opt(ASL_MOVE(obs));
|
asl::option<DestructorObserver> opt(ASL_MOVE(obs));
|
||||||
ASL_TEST_EXPECT(!destroyed);
|
ASL_TEST_EXPECT(!destroyed);
|
||||||
|
|
||||||
asl::option<DestructorObserver> opt2 = ASL_MOVE(opt);
|
asl::option<DestructorObserver> opt2 = ASL_MOVE(opt);
|
||||||
ASL_TEST_EXPECT(!destroyed);
|
ASL_TEST_EXPECT(!destroyed);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST_EXPECT(destroyed);
|
ASL_TEST_EXPECT(destroyed);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(call_destructor_on_reset)
|
ASL_TEST(call_destructor_on_reset)
|
||||||
{
|
{
|
||||||
bool destroyed = false;
|
bool destroyed = false;
|
||||||
|
|
||||||
asl::option<DestructorObserver> opt(&destroyed);
|
asl::option<DestructorObserver> opt(&destroyed);
|
||||||
ASL_TEST_EXPECT(!destroyed);
|
ASL_TEST_EXPECT(!destroyed);
|
||||||
|
|
||||||
opt.reset();
|
opt.reset();
|
||||||
ASL_TEST_EXPECT(destroyed);
|
ASL_TEST_EXPECT(destroyed);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(value)
|
ASL_TEST(value)
|
||||||
{
|
{
|
||||||
asl::option<int> a = 1;
|
asl::option<int> a = 1;
|
||||||
asl::option<int> b = 2;
|
asl::option<int> b = 2;
|
||||||
asl::option<int> c = a;
|
asl::option<int> c = a;
|
||||||
|
|
||||||
ASL_TEST_EXPECT(a.value() == 1);
|
ASL_TEST_EXPECT(a.value() == 1);
|
||||||
ASL_TEST_EXPECT(b.value() == 2);
|
ASL_TEST_EXPECT(b.value() == 2);
|
||||||
ASL_TEST_EXPECT(c.value() == 1);
|
ASL_TEST_EXPECT(c.value() == 1);
|
||||||
|
|
||||||
c = b;
|
c = b;
|
||||||
ASL_TEST_EXPECT(c.value() == 2);
|
ASL_TEST_EXPECT(c.value() == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(value_move)
|
ASL_TEST(value_move)
|
||||||
{
|
{
|
||||||
bool destroyed = false;
|
bool destroyed = false;
|
||||||
|
|
||||||
asl::option<DestructorObserver> opt(&destroyed);
|
asl::option<DestructorObserver> opt(&destroyed);
|
||||||
ASL_TEST_EXPECT(!destroyed);
|
ASL_TEST_EXPECT(!destroyed);
|
||||||
|
|
||||||
{
|
{
|
||||||
auto x = ASL_MOVE(opt).value();
|
auto x = ASL_MOVE(opt).value();
|
||||||
ASL_TEST_EXPECT(!destroyed);
|
ASL_TEST_EXPECT(!destroyed);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST_EXPECT(destroyed);
|
ASL_TEST_EXPECT(destroyed);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(deduction_guide)
|
ASL_TEST(deduction_guide)
|
||||||
{
|
{
|
||||||
asl::option opt(45);
|
asl::option opt(45);
|
||||||
ASL_TEST_EXPECT(opt.value() == 45);
|
ASL_TEST_EXPECT(opt.value() == 45);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(convert_copy)
|
ASL_TEST(convert_copy)
|
||||||
{
|
{
|
||||||
asl::option<uint8_t> opt8 = uint8_t{8};
|
asl::option<uint8_t> opt8 = uint8_t{8};
|
||||||
asl::option<uint16_t> opt16 = opt8;
|
asl::option<uint16_t> opt16 = opt8;
|
||||||
|
|
||||||
ASL_TEST_ASSERT(opt16.has_value());
|
ASL_TEST_ASSERT(opt16.has_value());
|
||||||
ASL_TEST_EXPECT(opt16.value() == 8);
|
ASL_TEST_EXPECT(opt16.value() == 8);
|
||||||
|
|
||||||
opt8 = uint8_t{10};
|
opt8 = uint8_t{10};
|
||||||
ASL_TEST_ASSERT(opt8.has_value());
|
ASL_TEST_ASSERT(opt8.has_value());
|
||||||
ASL_TEST_EXPECT(opt8.value() == 10);
|
ASL_TEST_EXPECT(opt8.value() == 10);
|
||||||
|
|
||||||
opt16 = asl::nullopt;
|
opt16 = asl::nullopt;
|
||||||
ASL_TEST_EXPECT(!opt16.has_value());
|
ASL_TEST_EXPECT(!opt16.has_value());
|
||||||
|
|
||||||
opt16 = opt8;
|
opt16 = opt8;
|
||||||
ASL_TEST_ASSERT(opt16.has_value());
|
ASL_TEST_ASSERT(opt16.has_value());
|
||||||
ASL_TEST_EXPECT(opt16.value() == 10);
|
ASL_TEST_EXPECT(opt16.value() == 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(convert_move)
|
ASL_TEST(convert_move)
|
||||||
{
|
{
|
||||||
asl::option<uint8_t> opt8 = uint8_t{8};
|
asl::option<uint8_t> opt8 = uint8_t{8};
|
||||||
asl::option<uint16_t> opt16 = ASL_MOVE(opt8);
|
asl::option<uint16_t> opt16 = ASL_MOVE(opt8);
|
||||||
|
|
||||||
ASL_TEST_ASSERT(opt16.has_value());
|
ASL_TEST_ASSERT(opt16.has_value());
|
||||||
ASL_TEST_EXPECT(opt16.value() == 8);
|
ASL_TEST_EXPECT(opt16.value() == 8);
|
||||||
|
|
||||||
opt8 = ASL_MOVE(uint8_t{10});
|
opt8 = ASL_MOVE(uint8_t{10});
|
||||||
ASL_TEST_ASSERT(opt8.has_value());
|
ASL_TEST_ASSERT(opt8.has_value());
|
||||||
ASL_TEST_EXPECT(opt8.value() == 10);
|
ASL_TEST_EXPECT(opt8.value() == 10);
|
||||||
|
|
||||||
opt16 = asl::nullopt;
|
opt16 = asl::nullopt;
|
||||||
ASL_TEST_EXPECT(!opt16.has_value());
|
ASL_TEST_EXPECT(!opt16.has_value());
|
||||||
|
|
||||||
opt16 = ASL_MOVE(opt8);
|
opt16 = ASL_MOVE(opt8);
|
||||||
ASL_TEST_ASSERT(opt16.has_value());
|
ASL_TEST_ASSERT(opt16.has_value());
|
||||||
ASL_TEST_EXPECT(opt16.value() == 10);
|
ASL_TEST_EXPECT(opt16.value() == 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(value_or)
|
ASL_TEST(value_or)
|
||||||
{
|
{
|
||||||
asl::option<int> a = asl::nullopt;
|
asl::option<int> a = asl::nullopt;
|
||||||
asl::option<int> b = 2;
|
asl::option<int> b = 2;
|
||||||
|
|
||||||
ASL_TEST_EXPECT(a.value_or(5) == 5);
|
ASL_TEST_EXPECT(a.value_or(5) == 5);
|
||||||
ASL_TEST_EXPECT(b.value_or(5) == 2);
|
ASL_TEST_EXPECT(b.value_or(5) == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(emplace)
|
ASL_TEST(emplace)
|
||||||
{
|
{
|
||||||
asl::option<int> a = asl::nullopt;
|
asl::option<int> a = asl::nullopt;
|
||||||
|
|
||||||
a.emplace(42);
|
a.emplace(42);
|
||||||
ASL_TEST_ASSERT(a.has_value());
|
ASL_TEST_ASSERT(a.has_value());
|
||||||
ASL_TEST_EXPECT(a.value() == 42);
|
ASL_TEST_EXPECT(a.value() == 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(emplace_destroys_previous)
|
ASL_TEST(emplace_destroys_previous)
|
||||||
{
|
{
|
||||||
bool b1 = false;
|
bool b1 = false;
|
||||||
bool b2 = false;
|
bool b2 = false;
|
||||||
|
|
||||||
{
|
{
|
||||||
asl::option<DestructorObserver> a{&b1};
|
asl::option<DestructorObserver> a{&b1};
|
||||||
ASL_TEST_EXPECT(!b1);
|
ASL_TEST_EXPECT(!b1);
|
||||||
|
|
||||||
a.emplace(&b2);
|
a.emplace(&b2);
|
||||||
ASL_TEST_EXPECT(b1);
|
ASL_TEST_EXPECT(b1);
|
||||||
ASL_TEST_EXPECT(!b2);
|
ASL_TEST_EXPECT(!b2);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST_EXPECT(b2);
|
ASL_TEST_EXPECT(b2);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(and_then)
|
ASL_TEST(and_then)
|
||||||
{
|
{
|
||||||
asl::option<int> a = 5;
|
asl::option<int> a = 5;
|
||||||
asl::option<int> b;
|
asl::option<int> b;
|
||||||
|
|
||||||
auto fn = [](int x) -> asl::option<float> { return static_cast<float>(x) + 0.5F; };
|
auto fn = [](int x) -> asl::option<float> { return static_cast<float>(x) + 0.5F; };
|
||||||
|
|
||||||
auto a2 = a.and_then(fn);
|
auto a2 = a.and_then(fn);
|
||||||
static_assert(asl::same_as<decltype(a2), asl::option<float>>);
|
static_assert(asl::same_as<decltype(a2), asl::option<float>>);
|
||||||
ASL_TEST_ASSERT(a2.has_value());
|
ASL_TEST_ASSERT(a2.has_value());
|
||||||
ASL_TEST_EXPECT(a2.value() == 5.5F);
|
ASL_TEST_EXPECT(a2.value() == 5.5F);
|
||||||
|
|
||||||
auto b2 = b.and_then(fn);
|
auto b2 = b.and_then(fn);
|
||||||
static_assert(asl::same_as<decltype(b2), asl::option<float>>);
|
static_assert(asl::same_as<decltype(b2), asl::option<float>>);
|
||||||
ASL_TEST_ASSERT(!b2.has_value());
|
ASL_TEST_ASSERT(!b2.has_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(transform)
|
ASL_TEST(transform)
|
||||||
{
|
{
|
||||||
asl::option<int> a = 5;
|
asl::option<int> a = 5;
|
||||||
asl::option<int> b;
|
asl::option<int> b;
|
||||||
|
|
||||||
auto fn = [](int x) -> float { return static_cast<float>(x) + 0.5F; };
|
auto fn = [](int x) -> float { return static_cast<float>(x) + 0.5F; };
|
||||||
|
|
||||||
auto a2 = a.transform(fn);
|
auto a2 = a.transform(fn);
|
||||||
static_assert(asl::same_as<decltype(a2), asl::option<float>>);
|
static_assert(asl::same_as<decltype(a2), asl::option<float>>);
|
||||||
ASL_TEST_ASSERT(a2.has_value());
|
ASL_TEST_ASSERT(a2.has_value());
|
||||||
ASL_TEST_EXPECT(a2.value() == 5.5F);
|
ASL_TEST_EXPECT(a2.value() == 5.5F);
|
||||||
|
|
||||||
auto b2 = b.transform(fn);
|
auto b2 = b.transform(fn);
|
||||||
static_assert(asl::same_as<decltype(b2), asl::option<float>>);
|
static_assert(asl::same_as<decltype(b2), asl::option<float>>);
|
||||||
ASL_TEST_ASSERT(!b2.has_value());
|
ASL_TEST_ASSERT(!b2.has_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(or_else)
|
ASL_TEST(or_else)
|
||||||
{
|
{
|
||||||
asl::option<int> a = 5;
|
asl::option<int> a = 5;
|
||||||
asl::option<int> b;
|
asl::option<int> b;
|
||||||
|
|
||||||
auto fn = []() -> asl::option<int> { return 12; };
|
auto fn = []() -> asl::option<int> { return 12; };
|
||||||
|
|
||||||
auto a2 = a.or_else(fn);
|
auto a2 = a.or_else(fn);
|
||||||
static_assert(asl::same_as<decltype(a2), asl::option<int>>);
|
static_assert(asl::same_as<decltype(a2), asl::option<int>>);
|
||||||
ASL_TEST_ASSERT(a2.has_value());
|
ASL_TEST_ASSERT(a2.has_value());
|
||||||
ASL_TEST_EXPECT(a2.value() == 5);
|
ASL_TEST_EXPECT(a2.value() == 5);
|
||||||
|
|
||||||
auto b2 = b.or_else(fn);
|
auto b2 = b.or_else(fn);
|
||||||
static_assert(asl::same_as<decltype(b2), asl::option<int>>);
|
static_assert(asl::same_as<decltype(b2), asl::option<int>>);
|
||||||
ASL_TEST_ASSERT(b2.has_value());
|
ASL_TEST_ASSERT(b2.has_value());
|
||||||
ASL_TEST_EXPECT(b2.value() == 12);
|
ASL_TEST_EXPECT(b2.value() == 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(niche)
|
ASL_TEST(niche)
|
||||||
{
|
{
|
||||||
asl::option<NonZero> opt;
|
asl::option<NonZero> opt;
|
||||||
ASL_TEST_EXPECT(!opt.has_value());
|
ASL_TEST_EXPECT(!opt.has_value());
|
||||||
|
|
||||||
asl::option<NonZero> opt2(2);
|
asl::option<NonZero> opt2(2);
|
||||||
ASL_TEST_EXPECT(opt2.has_value());
|
ASL_TEST_EXPECT(opt2.has_value());
|
||||||
ASL_TEST_EXPECT(opt2.value().value == 2);
|
ASL_TEST_EXPECT(opt2.value().value == 2);
|
||||||
|
|
||||||
opt = opt2;
|
opt = opt2;
|
||||||
ASL_TEST_EXPECT(opt2.has_value());
|
ASL_TEST_EXPECT(opt2.has_value());
|
||||||
ASL_TEST_EXPECT(opt2.value().value == 2);
|
ASL_TEST_EXPECT(opt2.value().value == 2);
|
||||||
|
|
||||||
opt.reset();
|
opt.reset();
|
||||||
ASL_TEST_EXPECT(!opt.has_value());
|
ASL_TEST_EXPECT(!opt.has_value());
|
||||||
|
|
||||||
opt = NonZero(87);
|
opt = NonZero(87);
|
||||||
ASL_TEST_EXPECT(opt.has_value());
|
ASL_TEST_EXPECT(opt.has_value());
|
||||||
ASL_TEST_EXPECT(opt.value().value == 87);
|
ASL_TEST_EXPECT(opt.value().value == 87);
|
||||||
}
|
}
|
||||||
|
@ -1,84 +1,84 @@
|
|||||||
#include "asl/status_or.hpp"
|
#include "asl/status_or.hpp"
|
||||||
#include "asl/testing/testing.hpp"
|
#include "asl/testing/testing.hpp"
|
||||||
#include "asl/tests/test_types.hpp"
|
#include "asl/tests/test_types.hpp"
|
||||||
|
|
||||||
static_assert(asl::copyable<asl::status_or<TrivialType>>);
|
static_assert(asl::copyable<asl::status_or<TrivialType>>);
|
||||||
static_assert(asl::moveable<asl::status_or<TrivialType>>);
|
static_assert(asl::moveable<asl::status_or<TrivialType>>);
|
||||||
|
|
||||||
static_assert(asl::copyable<asl::status_or<Copyable>>);
|
static_assert(asl::copyable<asl::status_or<Copyable>>);
|
||||||
static_assert(asl::moveable<asl::status_or<Copyable>>);
|
static_assert(asl::moveable<asl::status_or<Copyable>>);
|
||||||
|
|
||||||
static_assert(!asl::copyable<asl::status_or<MoveableOnly>>);
|
static_assert(!asl::copyable<asl::status_or<MoveableOnly>>);
|
||||||
static_assert(asl::moveable<asl::status_or<MoveableOnly>>);
|
static_assert(asl::moveable<asl::status_or<MoveableOnly>>);
|
||||||
|
|
||||||
static_assert(!asl::copyable<asl::status_or<Pinned>>);
|
static_assert(!asl::copyable<asl::status_or<Pinned>>);
|
||||||
static_assert(!asl::moveable<asl::status_or<Pinned>>);
|
static_assert(!asl::moveable<asl::status_or<Pinned>>);
|
||||||
|
|
||||||
ASL_TEST(ok)
|
ASL_TEST(ok)
|
||||||
{
|
{
|
||||||
asl::status_or<int> s = 6;
|
asl::status_or<int> s = 6;
|
||||||
ASL_TEST_EXPECT(s.ok());
|
ASL_TEST_EXPECT(s.ok());
|
||||||
ASL_TEST_EXPECT(s.code() == asl::status_code::ok);
|
ASL_TEST_EXPECT(s.code() == asl::status_code::ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(from_status)
|
ASL_TEST(from_status)
|
||||||
{
|
{
|
||||||
asl::status_or<char> s = asl::internal_error();
|
asl::status_or<char> s = asl::internal_error();
|
||||||
ASL_TEST_EXPECT(!s.ok());
|
ASL_TEST_EXPECT(!s.ok());
|
||||||
ASL_TEST_EXPECT(s.code() == asl::status_code::internal);
|
ASL_TEST_EXPECT(s.code() == asl::status_code::internal);
|
||||||
ASL_TEST_EXPECT(s.message() == ""_sv);
|
ASL_TEST_EXPECT(s.message() == ""_sv);
|
||||||
|
|
||||||
asl::status_or<int> s2 = asl::internal_error("oh no");
|
asl::status_or<int> s2 = asl::internal_error("oh no");
|
||||||
ASL_TEST_EXPECT(!s2.ok());
|
ASL_TEST_EXPECT(!s2.ok());
|
||||||
ASL_TEST_EXPECT(s2.code() == asl::status_code::internal);
|
ASL_TEST_EXPECT(s2.code() == asl::status_code::internal);
|
||||||
ASL_TEST_EXPECT(s2.message() == "oh no"_sv);
|
ASL_TEST_EXPECT(s2.message() == "oh no"_sv);
|
||||||
|
|
||||||
asl::status_or<int> s3 = asl::internal_error("{} {}", 1, 2);
|
asl::status_or<int> s3 = asl::internal_error("{} {}", 1, 2);
|
||||||
ASL_TEST_EXPECT(!s3.ok());
|
ASL_TEST_EXPECT(!s3.ok());
|
||||||
ASL_TEST_EXPECT(s3.code() == asl::status_code::internal);
|
ASL_TEST_EXPECT(s3.code() == asl::status_code::internal);
|
||||||
ASL_TEST_EXPECT(s3.message() == "1 2"_sv);
|
ASL_TEST_EXPECT(s3.message() == "1 2"_sv);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(destructor)
|
ASL_TEST(destructor)
|
||||||
{
|
{
|
||||||
bool d = false;
|
bool d = false;
|
||||||
|
|
||||||
{
|
{
|
||||||
asl::status_or<DestructorObserver> s{&d};
|
asl::status_or<DestructorObserver> s{&d};
|
||||||
ASL_TEST_EXPECT(s.ok());
|
ASL_TEST_EXPECT(s.ok());
|
||||||
ASL_TEST_EXPECT(!d);
|
ASL_TEST_EXPECT(!d);
|
||||||
|
|
||||||
asl::status_or s2 = ASL_MOVE(s);
|
asl::status_or s2 = ASL_MOVE(s);
|
||||||
ASL_TEST_EXPECT(s.ok());
|
ASL_TEST_EXPECT(s.ok());
|
||||||
ASL_TEST_EXPECT(!d);
|
ASL_TEST_EXPECT(!d);
|
||||||
|
|
||||||
s = ASL_MOVE(s2);
|
s = ASL_MOVE(s2);
|
||||||
ASL_TEST_EXPECT(s.ok());
|
ASL_TEST_EXPECT(s.ok());
|
||||||
ASL_TEST_EXPECT(!d);
|
ASL_TEST_EXPECT(!d);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST_EXPECT(d);
|
ASL_TEST_EXPECT(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(copy)
|
ASL_TEST(copy)
|
||||||
{
|
{
|
||||||
asl::status_or<int> s = 7;
|
asl::status_or<int> s = 7;
|
||||||
asl::status_or s2 = s;
|
asl::status_or s2 = s;
|
||||||
s = s2;
|
s = s2;
|
||||||
|
|
||||||
ASL_TEST_EXPECT(s.ok());
|
ASL_TEST_EXPECT(s.ok());
|
||||||
ASL_TEST_EXPECT(s2.ok());
|
ASL_TEST_EXPECT(s2.ok());
|
||||||
|
|
||||||
ASL_TEST_EXPECT(s.value() == 7);
|
ASL_TEST_EXPECT(s.value() == 7);
|
||||||
ASL_TEST_EXPECT(s2.value() == 7);
|
ASL_TEST_EXPECT(s2.value() == 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASL_TEST(value_or)
|
ASL_TEST(value_or)
|
||||||
{
|
{
|
||||||
asl::status_or<int> s = 7;
|
asl::status_or<int> s = 7;
|
||||||
asl::status_or<int> s2 = asl::internal_error();
|
asl::status_or<int> s2 = asl::internal_error();
|
||||||
|
|
||||||
ASL_TEST_EXPECT(s.value_or(45) == 7);
|
ASL_TEST_EXPECT(s.value_or(45) == 7);
|
||||||
ASL_TEST_EXPECT(s2.value_or(45) == 45);
|
ASL_TEST_EXPECT(s2.value_or(45) == 45);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,10 +30,10 @@ ASL_TEST(copy_inline)
|
|||||||
{
|
{
|
||||||
asl::status s = asl::ok();
|
asl::status s = asl::ok();
|
||||||
asl::status s2 = asl::internal_error();
|
asl::status s2 = asl::internal_error();
|
||||||
|
|
||||||
asl::status s3 = s;
|
asl::status s3 = s;
|
||||||
ASL_TEST_ASSERT(s3.code() == asl::status_code::ok);
|
ASL_TEST_ASSERT(s3.code() == asl::status_code::ok);
|
||||||
|
|
||||||
s3 = s2;
|
s3 = s2;
|
||||||
ASL_TEST_ASSERT(s3.code() == asl::status_code::internal);
|
ASL_TEST_ASSERT(s3.code() == asl::status_code::internal);
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ ASL_TEST(from_literal)
|
|||||||
ASL_TEST(substr1)
|
ASL_TEST(substr1)
|
||||||
{
|
{
|
||||||
asl::string_view s1 = "abcd";
|
asl::string_view s1 = "abcd";
|
||||||
|
|
||||||
asl::string_view s2 = s1.substr(0);
|
asl::string_view s2 = s1.substr(0);
|
||||||
ASL_TEST_ASSERT(s2.size() == 4);
|
ASL_TEST_ASSERT(s2.size() == 4);
|
||||||
ASL_TEST_EXPECT(asl::memcmp(s2.data(), "abcd", 4) == 0);
|
ASL_TEST_EXPECT(asl::memcmp(s2.data(), "abcd", 4) == 0);
|
||||||
@ -42,7 +42,7 @@ ASL_TEST(substr1)
|
|||||||
ASL_TEST(substr2)
|
ASL_TEST(substr2)
|
||||||
{
|
{
|
||||||
asl::string_view s1 = "abcd";
|
asl::string_view s1 = "abcd";
|
||||||
|
|
||||||
asl::string_view s2 = s1.substr(0, 4);
|
asl::string_view s2 = s1.substr(0, 4);
|
||||||
ASL_TEST_ASSERT(s2.size() == 4);
|
ASL_TEST_ASSERT(s2.size() == 4);
|
||||||
ASL_TEST_EXPECT(asl::memcmp(s2.data(), "abcd", 4) == 0);
|
ASL_TEST_EXPECT(asl::memcmp(s2.data(), "abcd", 4) == 0);
|
||||||
@ -61,7 +61,7 @@ ASL_TEST(substr2)
|
|||||||
ASL_TEST(first)
|
ASL_TEST(first)
|
||||||
{
|
{
|
||||||
asl::string_view s1 = "abcd";
|
asl::string_view s1 = "abcd";
|
||||||
|
|
||||||
asl::string_view s2 = s1.first(0);
|
asl::string_view s2 = s1.first(0);
|
||||||
ASL_TEST_ASSERT(s2.size() == 0);
|
ASL_TEST_ASSERT(s2.size() == 0);
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ ASL_TEST(first)
|
|||||||
ASL_TEST(last)
|
ASL_TEST(last)
|
||||||
{
|
{
|
||||||
asl::string_view s1 = "abcd";
|
asl::string_view s1 = "abcd";
|
||||||
|
|
||||||
asl::string_view s2 = s1.last(0);
|
asl::string_view s2 = s1.last(0);
|
||||||
ASL_TEST_ASSERT(s2.size() == 0);
|
ASL_TEST_ASSERT(s2.size() == 0);
|
||||||
|
|
||||||
|
@ -1,92 +1,92 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "asl/utility.hpp"
|
#include "asl/utility.hpp"
|
||||||
#include "asl/io.hpp"
|
#include "asl/io.hpp"
|
||||||
#include "asl/allocator.hpp"
|
#include "asl/allocator.hpp"
|
||||||
#include "asl/string_view.hpp"
|
#include "asl/string_view.hpp"
|
||||||
|
|
||||||
struct TrivialType
|
struct TrivialType
|
||||||
{
|
{
|
||||||
int x;
|
int x;
|
||||||
TrivialType() = default;
|
TrivialType() = default;
|
||||||
TrivialType(const TrivialType&) = default;
|
TrivialType(const TrivialType&) = default;
|
||||||
TrivialType(TrivialType&&) = default;
|
TrivialType(TrivialType&&) = default;
|
||||||
TrivialType& operator=(const TrivialType&) = default;
|
TrivialType& operator=(const TrivialType&) = default;
|
||||||
TrivialType& operator=(TrivialType&&) = default;
|
TrivialType& operator=(TrivialType&&) = default;
|
||||||
~TrivialType() = default;
|
~TrivialType() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TrivialTypeDefaultValue
|
struct TrivialTypeDefaultValue
|
||||||
{
|
{
|
||||||
int x{};
|
int x{};
|
||||||
TrivialTypeDefaultValue() = default;
|
TrivialTypeDefaultValue() = default;
|
||||||
TrivialTypeDefaultValue(const TrivialTypeDefaultValue&) = default;
|
TrivialTypeDefaultValue(const TrivialTypeDefaultValue&) = default;
|
||||||
TrivialTypeDefaultValue(TrivialTypeDefaultValue&&) = default;
|
TrivialTypeDefaultValue(TrivialTypeDefaultValue&&) = default;
|
||||||
TrivialTypeDefaultValue& operator=(const TrivialTypeDefaultValue&) = default;
|
TrivialTypeDefaultValue& operator=(const TrivialTypeDefaultValue&) = default;
|
||||||
TrivialTypeDefaultValue& operator=(TrivialTypeDefaultValue&&) = default;
|
TrivialTypeDefaultValue& operator=(TrivialTypeDefaultValue&&) = default;
|
||||||
~TrivialTypeDefaultValue() = default;
|
~TrivialTypeDefaultValue() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WithDestructor
|
struct WithDestructor
|
||||||
{
|
{
|
||||||
WithDestructor() = default;
|
WithDestructor() = default;
|
||||||
WithDestructor(const WithDestructor&) = default;
|
WithDestructor(const WithDestructor&) = default;
|
||||||
WithDestructor(WithDestructor&&) = default;
|
WithDestructor(WithDestructor&&) = default;
|
||||||
WithDestructor& operator=(const WithDestructor&) = default;
|
WithDestructor& operator=(const WithDestructor&) = default;
|
||||||
WithDestructor& operator=(WithDestructor&&) = default;
|
WithDestructor& operator=(WithDestructor&&) = default;
|
||||||
~WithDestructor() {} // NOLINT
|
~WithDestructor() {} // NOLINT
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Copyable // NOLINT
|
struct Copyable // NOLINT
|
||||||
{
|
{
|
||||||
Copyable(const Copyable&) {} // NOLINT
|
Copyable(const Copyable&) {} // NOLINT
|
||||||
Copyable& operator=(const Copyable&); // NOLINT
|
Copyable& operator=(const Copyable&); // NOLINT
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MoveableOnly // NOLINT
|
struct MoveableOnly // NOLINT
|
||||||
{
|
{
|
||||||
MoveableOnly(const MoveableOnly&) = delete;
|
MoveableOnly(const MoveableOnly&) = delete;
|
||||||
MoveableOnly& operator=(const MoveableOnly&) = delete;
|
MoveableOnly& operator=(const MoveableOnly&) = delete;
|
||||||
MoveableOnly(MoveableOnly&&);
|
MoveableOnly(MoveableOnly&&);
|
||||||
MoveableOnly& operator=(MoveableOnly&&); // NOLINT
|
MoveableOnly& operator=(MoveableOnly&&); // NOLINT
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Pinned // NOLINT
|
struct Pinned // NOLINT
|
||||||
{
|
{
|
||||||
Pinned(const Pinned&) = delete;
|
Pinned(const Pinned&) = delete;
|
||||||
Pinned& operator=(const Pinned&) = delete;
|
Pinned& operator=(const Pinned&) = delete;
|
||||||
Pinned(Pinned&&) = delete;
|
Pinned(Pinned&&) = delete;
|
||||||
Pinned& operator=(Pinned&&) = delete;
|
Pinned& operator=(Pinned&&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DestructorObserver
|
struct DestructorObserver
|
||||||
{
|
{
|
||||||
bool* destroyed;
|
bool* destroyed;
|
||||||
|
|
||||||
explicit DestructorObserver(bool* destroyed_) : destroyed{destroyed_} {}
|
explicit DestructorObserver(bool* destroyed_) : destroyed{destroyed_} {}
|
||||||
|
|
||||||
DestructorObserver(const DestructorObserver&) = delete;
|
DestructorObserver(const DestructorObserver&) = delete;
|
||||||
DestructorObserver& operator=(const DestructorObserver&) = delete;
|
DestructorObserver& operator=(const DestructorObserver&) = delete;
|
||||||
|
|
||||||
DestructorObserver(DestructorObserver&& other)
|
DestructorObserver(DestructorObserver&& other)
|
||||||
: destroyed{asl::exchange(other.destroyed, nullptr)}
|
: destroyed{asl::exchange(other.destroyed, nullptr)}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
DestructorObserver& operator=(DestructorObserver&& other)
|
DestructorObserver& operator=(DestructorObserver&& other)
|
||||||
{
|
{
|
||||||
if (this != &other)
|
if (this != &other)
|
||||||
{
|
{
|
||||||
destroyed = asl::exchange(other.destroyed, nullptr);
|
destroyed = asl::exchange(other.destroyed, nullptr);
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
|
||||||
|
|
||||||
~DestructorObserver()
|
|
||||||
{
|
|
||||||
if (destroyed != nullptr)
|
|
||||||
{
|
|
||||||
ASL_ASSERT_RELEASE(*destroyed == false);
|
|
||||||
*destroyed = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
~DestructorObserver()
|
||||||
|
{
|
||||||
|
if (destroyed != nullptr)
|
||||||
|
{
|
||||||
|
ASL_ASSERT_RELEASE(*destroyed == false);
|
||||||
|
*destroyed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -1 +1 @@
|
|||||||
#include "asl/utility.hpp"
|
#include "asl/utility.hpp"
|
||||||
|
168
asl/utility.hpp
168
asl/utility.hpp
@ -1,84 +1,84 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "asl/meta.hpp"
|
#include "asl/meta.hpp"
|
||||||
#include "asl/layout.hpp"
|
#include "asl/layout.hpp"
|
||||||
#include "asl/assert.hpp"
|
#include "asl/assert.hpp"
|
||||||
|
|
||||||
#define ASL_MOVE(...) (static_cast<::asl::un_ref_t<decltype(__VA_ARGS__)>&&>(__VA_ARGS__))
|
#define ASL_MOVE(...) (static_cast<::asl::un_ref_t<decltype(__VA_ARGS__)>&&>(__VA_ARGS__))
|
||||||
|
|
||||||
#define ASL_FWD(expr_) (static_cast<decltype(expr_)&&>(expr_))
|
#define ASL_FWD(expr_) (static_cast<decltype(expr_)&&>(expr_))
|
||||||
|
|
||||||
namespace asl
|
namespace asl
|
||||||
{
|
{
|
||||||
|
|
||||||
struct in_place_t {};
|
struct in_place_t {};
|
||||||
static constexpr in_place_t in_place{};
|
static constexpr in_place_t in_place{};
|
||||||
|
|
||||||
template<moveable T>
|
template<moveable T>
|
||||||
constexpr void swap(T& a, T& b)
|
constexpr void swap(T& a, T& b)
|
||||||
{
|
{
|
||||||
T tmp{ASL_MOVE(a)};
|
T tmp{ASL_MOVE(a)};
|
||||||
a = ASL_MOVE(b);
|
a = ASL_MOVE(b);
|
||||||
b = ASL_MOVE(tmp);
|
b = ASL_MOVE(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename U>
|
template<typename T, typename U>
|
||||||
T exchange(T& obj, U&& new_value)
|
T exchange(T& obj, U&& new_value)
|
||||||
{
|
{
|
||||||
T old_value = ASL_MOVE(obj);
|
T old_value = ASL_MOVE(obj);
|
||||||
obj = ASL_FWD(new_value);
|
obj = ASL_FWD(new_value);
|
||||||
return old_value;
|
return old_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<trivially_copy_constructible U, trivially_copy_constructible T>
|
template<trivially_copy_constructible U, trivially_copy_constructible T>
|
||||||
constexpr U bit_cast(T value) requires (size_of<T> == size_of<U>)
|
constexpr U bit_cast(T value) requires (size_of<T> == size_of<U>)
|
||||||
{
|
{
|
||||||
return __builtin_bit_cast(U, value);
|
return __builtin_bit_cast(U, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr T min(T a, T b)
|
constexpr T min(T a, T b)
|
||||||
{
|
{
|
||||||
return (a <= b) ? a : b;
|
return (a <= b) ? a : b;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr T max(T a, T b)
|
constexpr T max(T a, T b)
|
||||||
{
|
{
|
||||||
return (a >= b) ? a : b;
|
return (a >= b) ? a : b;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr uint64_t round_up_pow2(uint64_t v)
|
constexpr uint64_t round_up_pow2(uint64_t v)
|
||||||
{
|
{
|
||||||
ASL_ASSERT(v <= 0x8000'0000'0000'0000);
|
ASL_ASSERT(v <= 0x8000'0000'0000'0000);
|
||||||
|
|
||||||
v -= 1;
|
v -= 1;
|
||||||
|
|
||||||
v |= v >> 1;
|
v |= v >> 1;
|
||||||
v |= v >> 2;
|
v |= v >> 2;
|
||||||
v |= v >> 4;
|
v |= v >> 4;
|
||||||
v |= v >> 8;
|
v |= v >> 8;
|
||||||
v |= v >> 16;
|
v |= v >> 16;
|
||||||
v |= v >> 32;
|
v |= v >> 32;
|
||||||
|
|
||||||
return v + 1;
|
return v + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool is_pow2(isize_t v)
|
constexpr bool is_pow2(isize_t v)
|
||||||
{
|
{
|
||||||
return v > 0 && ((v - 1) & v) == 0;
|
return v > 0 && ((v - 1) & v) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ASL_DELETE_COPY(T) \
|
#define ASL_DELETE_COPY(T) \
|
||||||
T(const T&) = delete; \
|
T(const T&) = delete; \
|
||||||
T& operator=(const T&) = delete;
|
T& operator=(const T&) = delete;
|
||||||
|
|
||||||
#define ASL_DELETE_MOVE(T) \
|
#define ASL_DELETE_MOVE(T) \
|
||||||
T(T&&) = delete; \
|
T(T&&) = delete; \
|
||||||
T& operator=(T&&) = delete;
|
T& operator=(T&&) = delete;
|
||||||
|
|
||||||
#define ASL_DELETE_COPY_MOVE(T) \
|
#define ASL_DELETE_COPY_MOVE(T) \
|
||||||
ASL_DELETE_COPY(T) \
|
ASL_DELETE_COPY(T) \
|
||||||
ASL_DELETE_MOVE(T)
|
ASL_DELETE_MOVE(T)
|
||||||
|
|
||||||
} // namespace asl
|
} // namespace asl
|
||||||
|
8
tools/BUILD.bazel
Normal file
8
tools/BUILD.bazel
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
load("@rules_python//python:py_binary.bzl", "py_binary")
|
||||||
|
|
||||||
|
py_binary(
|
||||||
|
name = "fix_line_endings",
|
||||||
|
srcs = [
|
||||||
|
"fix_line_endings.py",
|
||||||
|
],
|
||||||
|
)
|
68
tools/fix_line_endings.py
Normal file
68
tools/fix_line_endings.py
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import glob
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
TO_FIX = [
|
||||||
|
".bazelrc",
|
||||||
|
".clang-tidy",
|
||||||
|
".gitignore",
|
||||||
|
"**/*.hpp",
|
||||||
|
"**/*.h",
|
||||||
|
"**/*.cpp",
|
||||||
|
"**/*.py",
|
||||||
|
"**/*.bzl",
|
||||||
|
"**/*.bazel",
|
||||||
|
"**/*.txt",
|
||||||
|
"**/*.bat",
|
||||||
|
"**/*.sh",
|
||||||
|
]
|
||||||
|
|
||||||
|
TO_IGNORE = [
|
||||||
|
"MODULE.bazel.lock",
|
||||||
|
]
|
||||||
|
|
||||||
|
TO_FIX = [re.compile(glob.translate(p, recursive=True, include_hidden=True)) for p in TO_FIX]
|
||||||
|
TO_IGNORE = [re.compile(glob.translate(p, recursive=True, include_hidden=True)) for p in TO_IGNORE]
|
||||||
|
|
||||||
|
def get_git_files():
|
||||||
|
return subprocess.check_output(["git", "ls-files"]).decode().splitlines()
|
||||||
|
|
||||||
|
def fix_file(file):
|
||||||
|
lines = []
|
||||||
|
with open(file, "rb") as fp:
|
||||||
|
lines = [l.rstrip() + b"\n" for l in fp.readlines()]
|
||||||
|
with open(file, "wb+") as fp:
|
||||||
|
fp.writelines(lines)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
os.chdir(os.getenv("BUILD_WORKSPACE_DIRECTORY"))
|
||||||
|
|
||||||
|
files = get_git_files()
|
||||||
|
files_to_fix = []
|
||||||
|
unhandled_files = []
|
||||||
|
|
||||||
|
for f in files:
|
||||||
|
for pattern in TO_FIX:
|
||||||
|
if pattern.match(f):
|
||||||
|
files_to_fix.append(f)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
for pattern in TO_IGNORE:
|
||||||
|
if pattern.match(f):
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
unhandled_files.append(f)
|
||||||
|
|
||||||
|
if len(unhandled_files):
|
||||||
|
print("Some files were not handled:")
|
||||||
|
for f in unhandled_files:
|
||||||
|
print(" ", f)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
for i, f in enumerate(files):
|
||||||
|
print(f"\033[K{i}/{len(files_to_fix)} {f}", end="\r", flush=True)
|
||||||
|
fix_file(f)
|
||||||
|
print("")
|
38
vendor/cityhash/LICENSE.txt
vendored
38
vendor/cityhash/LICENSE.txt
vendored
@ -1,19 +1,19 @@
|
|||||||
// Copyright (c) 2011 Google, Inc.
|
// Copyright (c) 2011 Google, Inc.
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
// in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
// furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
// The above copyright notice and this permission notice shall be included in
|
// The above copyright notice and this permission notice shall be included in
|
||||||
// all copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
12
vendor/dragonbox/BUILD.bazel
vendored
12
vendor/dragonbox/BUILD.bazel
vendored
@ -1,6 +1,6 @@
|
|||||||
cc_library(
|
cc_library(
|
||||||
name = "dragonbox",
|
name = "dragonbox",
|
||||||
hdrs = ["dragonbox.h"],
|
hdrs = ["dragonbox.h"],
|
||||||
includes = ["."],
|
includes = ["."],
|
||||||
visibility = ["//:__subpackages__"],
|
visibility = ["//:__subpackages__"],
|
||||||
)
|
)
|
||||||
|
Reference in New Issue
Block a user