diff --git a/CMakeLists.txt b/CMakeLists.txt index 227216f..49cbdb2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,7 @@ if(BUILD_TESTS) add_subdirectory(tests) endif() -set(LIBREXY_PUBLIC_HEADERS "include/rexy/rexy.hpp" "include/rexy/algorithm.hpp" "include/rexy/utility.hpp" "include/rexy/basic_string_hash.hpp" "include/rexy/hash.hpp" "include/rexy/static_string_hash.hpp" "include/rexy/string_hash.hpp" "include/rexy/mpmc_queue.hpp" "include/rexy/mpmc_queue.tpp" "include/rexy/traits.hpp" "include/rexy/steal.hpp" "include/rexy/binary.hpp" "include/rexy/expression.hpp" "include/rexy/binary_base.hpp" "include/rexy/binary_base.tpp" "include/rexy/string_base.hpp" "include/rexy/string.hpp" "include/rexy/filerd.hpp" "include/rexy/string_base.tpp" "include/rexy/allocator.hpp" "include/rexy/meta.hpp" "include/rexy/buffer.hpp" "include/rexy/buffer.tpp" "include/rexy/debug_print.hpp" "include/rexy/deferred.hpp" "include/rexy/demangle.hpp" "include/rexy/enum_traits.hpp" "include/rexy/source_location.hpp") +set(LIBREXY_PUBLIC_HEADERS "include/rexy/rexy.hpp" "include/rexy/algorithm.hpp" "include/rexy/utility.hpp" "include/rexy/basic_string_hash.hpp" "include/rexy/hash.hpp" "include/rexy/static_string_hash.hpp" "include/rexy/string_hash.hpp" "include/rexy/mpmc_queue.hpp" "include/rexy/mpmc_queue.tpp" "include/rexy/traits.hpp" "include/rexy/steal.hpp" "include/rexy/binary.hpp" "include/rexy/expression.hpp" "include/rexy/binary_base.hpp" "include/rexy/binary_base.tpp" "include/rexy/string_base.hpp" "include/rexy/string.hpp" "include/rexy/filerd.hpp" "include/rexy/string_base.tpp" "include/rexy/allocator.hpp" "include/rexy/meta.hpp" "include/rexy/buffer.hpp" "include/rexy/buffer.tpp" "include/rexy/debug_print.hpp" "include/rexy/deferred.hpp" "include/rexy/demangle.hpp" "include/rexy/enum_traits.hpp" "include/rexy/source_location.hpp" "include/rexy/storage_for.hpp" "include/rexy/storage_for.tpp") target_compile_options(rexy PRIVATE -Wall -Wextra -pedantic -std=c++20) install(TARGETS rexy diff --git a/include/rexy/storage_for.hpp b/include/rexy/storage_for.hpp new file mode 100644 index 0000000..3d308e4 --- /dev/null +++ b/include/rexy/storage_for.hpp @@ -0,0 +1,80 @@ +/** + This file is a part of rexy's general purpose library + Copyright (C) 2022 rexy712 + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef REXY_STORAGE_FOR_HPP +#define REXY_STORAGE_FOR_HPP + +#include //forward, move +#include //is_nothrow_constructible, etc + +namespace rexy{ + + //A wrapper around raw storage. + //Allows default constructing objects with members which cannot be default constructed + + template + class storage_for + { + public: + using value_type = T; + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using rvalue_reference = T&&; + + static constexpr auto align = alignof(value_type); + static constexpr auto size = sizeof(value_type); + + private: + alignas(align) unsigned char m_storage[size]; + unsigned char m_dirty:1 = 0; + + public: + constexpr storage_for(void) = default; + template + constexpr storage_for(Args&&... args)noexcept(std::is_nothrow_constructible::value); + constexpr storage_for(const_reference t)noexcept(std::is_nothrow_copy_constructible::value); + constexpr storage_for(rvalue_reference t)noexcept(std::is_nothrow_move_constructible::value); + constexpr storage_for(const storage_for& s)noexcept(std::is_nothrow_copy_constructible::value); + constexpr storage_for(storage_for&& s)noexcept(std::is_nothrow_move_constructible::value); + constexpr ~storage_for(void)noexcept(std::is_nothrow_destructible::value); + + constexpr storage_for& operator=(const storage_for& s)noexcept(std::is_nothrow_copy_assignable::value); + constexpr storage_for& operator=(storage_for&& s)noexcept(std::is_nothrow_move_assignable::value); + constexpr storage_for& operator=(const_reference t)noexcept(std::is_nothrow_copy_assignable::value); + constexpr storage_for& operator=(rvalue_reference t)noexcept(std::is_nothrow_move_assignable::value); + constexpr void destroy(void)noexcept(std::is_nothrow_destructible::value); + + constexpr operator reference(void)noexcept; + constexpr operator const_reference(void)const noexcept; + constexpr operator rvalue_reference(void)&& noexcept; + + constexpr pointer operator->(void)noexcept; + constexpr const_pointer operator->(void)const noexcept; + constexpr reference operator*(void)noexcept; + constexpr const_reference operator*(void)const noexcept; + + bool valid(void)const; + }; + +} + +#include "storage_for.tpp" + +#endif diff --git a/include/rexy/storage_for.tpp b/include/rexy/storage_for.tpp new file mode 100644 index 0000000..5e0e53b --- /dev/null +++ b/include/rexy/storage_for.tpp @@ -0,0 +1,123 @@ +/** + This file is a part of rexy's general purpose library + Copyright (C) 2022 rexy712 + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef REXY_STORAGE_FOR_TPP +#define REXY_STORAGE_FOR_TPP + +#include //forward, move + +namespace rexy{ + + template + template + constexpr storage_for::storage_for(Args&&... args)noexcept(std::is_nothrow_constructible::value){ + new (m_storage) T(std::forward(args)...); + m_dirty = 1; + } + template + constexpr storage_for::storage_for(const_reference t)noexcept(std::is_nothrow_copy_constructible::value){ + new (m_storage) T(t); + m_dirty = 1; + } + template + constexpr storage_for::storage_for(rvalue_reference t)noexcept(std::is_nothrow_move_constructible::value){ + new (m_storage) T(std::move(t)); + m_dirty = 1; + } + template + constexpr storage_for::storage_for(const storage_for& s)noexcept(std::is_nothrow_copy_constructible::value){ + new (m_storage) T(reinterpret_cast(s.m_storage)); + m_dirty = 1; + } + template + constexpr storage_for::storage_for(storage_for&& s)noexcept(std::is_nothrow_move_constructible::value){ + new (m_storage) T(std::move(reinterpret_cast(&s.m_storage))); + m_dirty = 1; + } + template + constexpr storage_for::~storage_for(void)noexcept(std::is_nothrow_destructible::value){ + if(m_dirty){ + destroy(); + } + } + + template + constexpr storage_for& storage_for::operator=(const storage_for& s)noexcept(std::is_nothrow_copy_assignable::value){ + reinterpret_cast(m_storage) = static_cast(s); + return *this; + } + template + constexpr storage_for& storage_for::operator=(storage_for&& s)noexcept(std::is_nothrow_move_assignable::value){ + reinterpret_cast(m_storage) = static_cast(std::move(s)); + return *this; + } + template + constexpr storage_for& storage_for::operator=(const_reference t)noexcept(std::is_nothrow_copy_assignable::value){ + reinterpret_cast(m_storage) = t; + return *this; + } + template + constexpr storage_for& storage_for::operator=(rvalue_reference t)noexcept(std::is_nothrow_move_assignable::value){ + reinterpret_cast(m_storage) = std::move(t); + return *this; + } + template + constexpr void storage_for::destroy(void)noexcept(std::is_nothrow_destructible::value){ + reinterpret_cast(&m_storage)->~T(); + m_dirty = 0; + } + + template + constexpr storage_for::operator reference(void)noexcept{ + return reinterpret_cast(m_storage); + } + template + constexpr storage_for::operator const_reference(void)const noexcept{ + return m_storage; + } + template + constexpr storage_for::operator rvalue_reference(void)&& noexcept{ + return reinterpret_cast(std::move(m_storage)); + } + + template + constexpr auto storage_for::operator->(void)noexcept -> pointer{ + return reinterpret_cast(&m_storage); + } + template + constexpr auto storage_for::operator->(void)const noexcept -> const_pointer{ + return reinterpret_cast(&m_storage); + } + + template + constexpr auto storage_for::operator*(void)noexcept -> reference{ + return reinterpret_cast(m_storage); + } + template + constexpr auto storage_for::operator*(void)const noexcept -> const_reference{ + return reinterpret_cast(m_storage); + } + + template + bool storage_for::valid(void)const{ + return m_dirty; + } + +} + +#endif diff --git a/src/ensure.cpp b/src/ensure.cpp index 5ff17c5..b53ebcf 100644 --- a/src/ensure.cpp +++ b/src/ensure.cpp @@ -24,6 +24,7 @@ #include "rexy/source_location.hpp" #include "rexy/demangle.hpp" #include "rexy/debug_print.hpp" +#include "rexy/storage_for.hpp" #include "rexy/detail/binary_string_conv.hpp" #include "rexy/detail/string_appender.hpp"