-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
inclass_store_t
- for using as pimpl
- Loading branch information
Artur Bać (win10)
committed
Mar 31, 2024
1 parent
a540fe2
commit fc5c6b5
Showing
3 changed files
with
280 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
// SPDX-FileCopyrightText: 2024 Artur Bać | ||
// SPDX-License-Identifier: MIT | ||
// SPDX-PackageHomePage: https://github.com/arturbac/small_vectors | ||
#pragma once | ||
|
||
#include <cstddef> | ||
#include <new> | ||
#include <utility> | ||
#include <concepts> | ||
#include <memory> | ||
|
||
namespace small_vectors::inline v3_0 | ||
{ | ||
namespace concepts | ||
{ | ||
template<typename T> | ||
concept complete_type = requires { sizeof(T); }; | ||
} | ||
|
||
template< | ||
typename ValueType, | ||
std::size_t StorageSize = sizeof(ValueType), | ||
std::size_t Alignment = std::alignment_of_v<ValueType>> | ||
struct inclass_store_t | ||
{ | ||
using value_type = ValueType; | ||
static constexpr std::size_t storage_size{StorageSize}; | ||
|
||
struct store_t | ||
{ | ||
[[alignas(Alignment)]] std::byte data[storage_size]; | ||
}; | ||
|
||
store_t store_; | ||
|
||
private: | ||
constexpr auto ptr() noexcept -> value_type * | ||
{ | ||
return std::launder(reinterpret_cast<value_type *>(&store_.data[0])); | ||
} | ||
|
||
constexpr auto ptr() const noexcept -> value_type const * | ||
{ | ||
return std::launder(reinterpret_cast<value_type const *>(&store_.data[0])); | ||
} | ||
|
||
public: | ||
constexpr inclass_store_t() noexcept(std::is_nothrow_default_constructible_v<value_type>) | ||
requires concepts::complete_type<value_type> && std::default_initializable<value_type> | ||
{ | ||
if constexpr(std::is_trivially_default_constructible_v<value_type>) | ||
store_ = {}; | ||
else | ||
std::construct_at(ptr()); | ||
} | ||
|
||
constexpr inclass_store_t(inclass_store_t const & other) noexcept(std::is_nothrow_copy_constructible_v<value_type>) | ||
requires std::copy_constructible<value_type> | ||
{ | ||
if constexpr(std::is_trivially_copy_constructible_v<value_type>) | ||
store_ = other.store_; | ||
else | ||
std::construct_at(ptr(), *other.ptr()); | ||
} | ||
|
||
constexpr inclass_store_t(inclass_store_t && other) noexcept(std::is_nothrow_move_constructible_v<value_type>) | ||
requires concepts::complete_type<value_type> && std::move_constructible<value_type> | ||
{ | ||
if constexpr(std::is_trivially_move_constructible_v<value_type>) | ||
store_ = other.store_; | ||
else | ||
std::construct_at(ptr(), std::move(*other.ptr())); | ||
} | ||
|
||
constexpr auto operator=(inclass_store_t const & other) noexcept(std::is_nothrow_copy_assignable_v<value_type>) | ||
-> inclass_store_t & | ||
requires concepts::complete_type<value_type> && std::copyable<value_type> // Requires value_type to be copyable | ||
{ | ||
if(this != &other) | ||
{ | ||
if constexpr(std::is_trivially_copy_assignable_v<value_type>) | ||
store_ = other.store_; | ||
else | ||
*ptr() = *other.ptr(); | ||
} | ||
return *this; | ||
} | ||
|
||
constexpr auto operator=(inclass_store_t && other) noexcept(std::is_nothrow_move_assignable_v<value_type>) | ||
-> inclass_store_t & | ||
requires concepts::complete_type<value_type> && std::movable<value_type> // Requires value_type to be movable | ||
{ | ||
if(this != &other) | ||
{ | ||
if constexpr(std::is_trivially_destructible_v<value_type>) | ||
std::destroy_at(ptr()); | ||
if constexpr(std::is_trivially_move_assignable_v<value_type>) | ||
store_ = other.store_; | ||
else | ||
std::construct_at(ptr(), std::move(*other.ptr())); | ||
} | ||
return *this; | ||
} | ||
|
||
template<typename... Args> | ||
constexpr inclass_store_t(Args &&... args) | ||
requires concepts::complete_type<value_type> && std::constructible_from<value_type, Args &&...> | ||
{ | ||
std::construct_at(ptr(), std::forward<Args>(args)...); | ||
} | ||
|
||
constexpr ~inclass_store_t() noexcept(std::is_nothrow_destructible_v<value_type>) | ||
requires std::destructible<value_type> && (!std::is_trivially_constructible_v<value_type>) | ||
{ | ||
std::destroy_at(ptr()); | ||
} | ||
|
||
constexpr ~inclass_store_t() noexcept | ||
requires std::is_trivially_constructible_v<value_type> | ||
= default; | ||
|
||
constexpr auto operator*() noexcept -> value_type & { return *ptr(); } | ||
|
||
constexpr auto operator*() const noexcept -> value_type const & { return *ptr(); } | ||
|
||
constexpr auto operator->() noexcept -> value_type * { return ptr(); } | ||
|
||
constexpr auto operator->() const noexcept -> value_type const * { return ptr(); } | ||
}; | ||
|
||
} // namespace small_vectors::inline v3_0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
#include <small_vectors/inclass_buffer.hpp> | ||
|
||
#include <boost/ut.hpp> | ||
#include <string> | ||
#include <type_traits> | ||
|
||
using namespace boost::ut; | ||
using small_vectors::inclass_store_t; | ||
|
||
struct test_trivial_struct | ||
{ | ||
int content; | ||
}; | ||
|
||
static_assert(std::alignment_of_v<test_trivial_struct> == alignof(test_trivial_struct), "Alignment mismatch."); | ||
using namespace std::string_view_literals; | ||
|
||
suite<"inclass_store_trivial_tests"> inclass_store_trivial_tests = [] | ||
{ | ||
using inclass_string_store | ||
= inclass_store_t<test_trivial_struct, sizeof(test_trivial_struct), alignof(test_trivial_struct)>; | ||
"default_constructor"_test = [] | ||
{ | ||
inclass_string_store store; | ||
expect(eq(store->content, 0)); | ||
}; | ||
"parameterized_constructor"_test = [] | ||
{ | ||
inclass_string_store store{10}; | ||
expect(eq(10, store->content)); | ||
}; | ||
"copy_constructor"_test = [] | ||
{ | ||
inclass_string_store const original{-10}; | ||
inclass_string_store const copy{original}; | ||
expect(eq(-10, copy->content)); | ||
}; | ||
"move_constructor"_test = [] | ||
{ | ||
inclass_string_store original{0xfffffe}; | ||
inclass_string_store const moved{std::move(original)}; | ||
expect(eq(0xfffffe, moved->content)); | ||
}; | ||
|
||
"copy_assignment"_test = [] | ||
{ | ||
inclass_string_store original{0xfffffe}; | ||
inclass_string_store copy; | ||
copy = original; | ||
expect(eq(0xfffffe, (*copy).content)); | ||
}; | ||
|
||
"move_assignment"_test = [] | ||
{ | ||
inclass_string_store original{0xfffffe}; | ||
inclass_string_store moved; | ||
moved = std::move(original); | ||
expect(eq(0xfffffe, (*moved).content)); | ||
}; | ||
}; | ||
constexpr auto test_text | ||
= "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis sit amet dictum neque." | ||
" Aliquam erat volutpat. Vivamus bibendum pretium eros, eu porta libero dictum ut." | ||
" Vivamus feugiat nisi elit, quis finibus risus pellentesque non. Cras accumsan felis quis dolor malesuada," | ||
" eu consequat velit malesuada."sv; | ||
|
||
struct test_non_trivial_struct | ||
{ | ||
std::string content; | ||
}; | ||
|
||
suite<"inclass_store_non_trivial_tests"> inclass_store_non_trivial_tests = [] | ||
{ | ||
using inclass_string_store | ||
= inclass_store_t<test_non_trivial_struct, sizeof(test_non_trivial_struct), alignof(test_non_trivial_struct)>; | ||
|
||
"default_constructor"_test = [] | ||
{ | ||
inclass_string_store store; | ||
expect(store->content.empty()); | ||
}; | ||
|
||
"parameterized_constructor"_test = [] | ||
{ | ||
inclass_string_store store{std::string{test_text}}; | ||
expect(eq(test_text, (*store).content)); | ||
}; | ||
|
||
"copy_constructor"_test = [] | ||
{ | ||
inclass_string_store const original{std::string{test_text}}; | ||
inclass_string_store copy{original}; | ||
expect(eq(test_text, (*copy).content)); | ||
}; | ||
|
||
"move_constructor"_test = [] | ||
{ | ||
inclass_string_store original{std::string{test_text}}; | ||
inclass_string_store const moved{std::move(original)}; | ||
expect(eq(test_text, (*moved).content)); | ||
}; | ||
|
||
"copy_assignment"_test = [] | ||
{ | ||
inclass_string_store original{std::string{test_text}}; | ||
inclass_string_store copy; | ||
copy = original; | ||
expect(eq(test_text, (*copy).content)); | ||
}; | ||
|
||
"move_assignment"_test = [] | ||
{ | ||
inclass_string_store original{std::string{test_text}}; | ||
inclass_string_store moved; | ||
moved = std::move(original); | ||
expect(eq(test_text, (*moved).content)); | ||
}; | ||
}; | ||
|
||
struct test_multi_arg_struct | ||
{ | ||
std::string content; | ||
int integral; | ||
}; | ||
|
||
suite<"inclass_store_multi_arg_struct"> inclass_store_multi_arg_struct = [] | ||
{ | ||
using inclass_string_store = inclass_store_t<test_multi_arg_struct>; | ||
|
||
"default_constructor"_test = [] | ||
{ | ||
inclass_string_store store; | ||
expect(store->content.empty()); | ||
}; | ||
|
||
"parameterized_constructor"_test = [] | ||
{ | ||
inclass_string_store store{std::string{test_text}, 0x1f55aafe}; | ||
expect(eq(test_text, (*store).content)); | ||
expect(eq(0x1f55aafe, store->integral)); | ||
}; | ||
}; | ||
|
||
int main() | ||
{ | ||
// Running the tests | ||
return boost::ut::cfg<>.run(); | ||
} |