From def67bba57e7cfdf9942bc2c88a4ce484963f9d2 Mon Sep 17 00:00:00 2001 From: Steven Le Rouzic Date: Fri, 6 Sep 2024 23:22:18 +0200 Subject: maybe_uninit --- .bazelrc | 1 + .clang-tidy | 30 ++++++++++++++++++++++++++++++ asl/BUILD.bazel | 5 ++++- asl/annotations.hpp | 11 +++++++++++ asl/layout.hpp | 29 +++++++++++++++++++++++++++++ asl/maybe_uninit.hpp | 44 ++++++++++++++++++++++++++++++++++++++++++++ asl/maybe_uninit_tests.cpp | 7 +++++++ asl/memory.hpp | 8 ++++++++ 8 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 asl/layout.hpp create mode 100644 asl/maybe_uninit.hpp create mode 100644 asl/maybe_uninit_tests.cpp create mode 100644 asl/memory.hpp diff --git a/.bazelrc b/.bazelrc index 66c9547..68bfb11 100644 --- a/.bazelrc +++ b/.bazelrc @@ -12,3 +12,4 @@ build --cxxopt=-Wno-c++98-compat-pedantic build --cxxopt=-Wno-pre-c++17-compat build --cxxopt=-Wno-c++20-compat build --cxxopt=-Wno-unused-macros +build --cxxopt=-Wno-documentation-unknown-command diff --git a/.clang-tidy b/.clang-tidy index d3f5a12..11ba839 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1 +1,31 @@ +Checks: + - "hicpp-*" + - "cppcoreguidelines-*" + - "misc-*" + - "clang-analyzer-*" + - "-misc-include-cleaner" + - "performance-*" + - "readability-*" + - "-*-named-parameter" + - "-*-avoid-do-while" + - "-*-magic-numbers" + - "-*-identifier-length" + - "-*-union-access" + - "-*-vararg" + - "-*-macro-usage" + - "-*-non-private-member-variables-in-classes" + - "-*-avoid-non-const-global-variables" + - "-*-missing-std-forward" + - "-*-owning-memory" + - "-*-no-malloc" + - "-*-avoid-c-arrays" + - "-*-use-anonymous-namespace" + - "-*-reinterpret-cast" + - "-*-noexcept-move" + - "-*-noexcept-move-constructor" + - "-*-noexcept-move-operations" + - "-*-bounds-array-to-pointer-decay" + - "-*-no-array-decay" + - "-*-signed-bitwise" + - "-readability-use-anyofallof" diff --git a/asl/BUILD.bazel b/asl/BUILD.bazel index e5d5eb3..d7371c1 100644 --- a/asl/BUILD.bazel +++ b/asl/BUILD.bazel @@ -3,6 +3,9 @@ cc_library( hdrs = [ "annotations.hpp", "integers.hpp", + "layout.hpp", + "maybe_uninit.hpp", + "memory.hpp", "meta.hpp", "option.hpp", "utility.hpp", @@ -19,4 +22,4 @@ cc_library( deps = [ ":asl", ], -) for name in ["integers", "meta", "option", "utility"]] +) for name in ["integers", "maybe_uninit", "meta", "option", "utility"]] diff --git a/asl/annotations.hpp b/asl/annotations.hpp index a94834d..c0d8f20 100644 --- a/asl/annotations.hpp +++ b/asl/annotations.hpp @@ -10,3 +10,14 @@ #define ASL_NO_UNIQUE_ADDRESS [[no_unique_address]] #endif +namespace asl +{ + +struct unsafe +{ + unsafe() = delete; + explicit unsafe(auto&&) {} +}; + +} // namespace asl + diff --git a/asl/layout.hpp b/asl/layout.hpp new file mode 100644 index 0000000..5141456 --- /dev/null +++ b/asl/layout.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include "asl/integers.hpp" +#include "asl/meta.hpp" + +namespace asl +{ + +template +inline constexpr int64_t size_of = static_cast(sizeof(T)); + +template +inline constexpr int64_t align_of = static_cast(alignof(T)); + +struct layout +{ + int64_t size; + int64_t align; + + constexpr bool operator==(const layout&) const = default; + + template + static constexpr layout of() + { + return layout{ size_of, align_of }; + } +}; + +} // namespace asl diff --git a/asl/maybe_uninit.hpp b/asl/maybe_uninit.hpp new file mode 100644 index 0000000..ffbbb1c --- /dev/null +++ b/asl/maybe_uninit.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include "asl/annotations.hpp" +#include "asl/layout.hpp" +#include "asl/memory.hpp" +#include "asl/meta.hpp" + +namespace asl +{ + +template +class alignas(align_of) maybe_uninit +{ + char m_storage[size_of]; + +public: + constexpr void* uninit_ptr() const { return m_storage; } + + // @Safety Pointer must only be accessed when in initialized state. + constexpr const T* init_ptr(unsafe) const { return reinterpret_cast(m_storage); } + constexpr T* init_ptr(unsafe) { return reinterpret_cast< T*>(m_storage); } + + // @Safety Reference must only be accessed when in initialized state. + constexpr const T& as_init(unsafe) const { return *reinterpret_cast(m_storage); } + constexpr T& as_init(unsafe) { return *reinterpret_cast< T*>(m_storage); } + + // @Safety Must be called only when in uninitialized state. + template + inline void init(unsafe, Args&&... args) + { + new(uninit_ptr()) T(ASL_FWD(args)...); + } + + // @Safety Must be called only when in initialized state. + inline void uninit(unsafe) + { + if constexpr (!trivially_destructible) + { + init_ptr(unsafe("Caller has checked init state"))->~T(); + } + } +}; + +} // namespace asl diff --git a/asl/maybe_uninit_tests.cpp b/asl/maybe_uninit_tests.cpp new file mode 100644 index 0000000..7efeff0 --- /dev/null +++ b/asl/maybe_uninit_tests.cpp @@ -0,0 +1,7 @@ +#include "asl/maybe_uninit.hpp" + +static_assert(asl::layout::of() == asl::layout::of>()); +static_assert(asl::size_of == asl::size_of>); +static_assert(asl::align_of == asl::align_of>); + +int main() { return 0; } diff --git a/asl/memory.hpp b/asl/memory.hpp new file mode 100644 index 0000000..33fa819 --- /dev/null +++ b/asl/memory.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "asl/integers.hpp" + +constexpr void* operator new(uint64_t, void* ptr) +{ + return ptr; +} -- cgit