-
Notifications
You must be signed in to change notification settings - Fork 41
Expand file tree
/
Copy pathAPimpl.h
More file actions
116 lines (94 loc) · 3.1 KB
/
APimpl.h
File metadata and controls
116 lines (94 loc) · 3.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/*
* AUI Framework - Declarative UI toolkit for modern C++20
* Copyright (C) 2020-2025 Alex2772 and Contributors
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <cstdint>
#include <AUI/Traits/types.h>
namespace aui {
/**
* @brief Utility wrapper implementing the stack-allocated (fast) pimpl idiom.
* @ingroup useful_templates
* @details
* the following functions can be called only if <code>T</code> is a complete type:
* <ul>
* <li>ctor</li>
* <li>dtor</li>
* </ul>
*
* See https://youtu.be/mkPTreWiglk?t=157 (Russian)
*/
template<typename T, std::size_t storageSize, std::size_t storageAlignment = 8>
struct fast_pimpl {
public:
template<typename... Args>
fast_pimpl(Args&&... args) {
new (ptr()) T(std::forward<Args>(args)...);
static_assert(storageSize >= sizeof(T), "not enough size");
static_assert(storageAlignment % alignof(T) == 0, "alignment does not match");
}
fast_pimpl(const fast_pimpl& other) {
new (ptr()) T(other.value());
}
fast_pimpl(fast_pimpl&& other) noexcept {
new (ptr()) T(std::move(other.value()));
}
fast_pimpl& operator=(const fast_pimpl& other) {
new (ptr()) T(other.value());
return *this;
}
fast_pimpl& operator=(fast_pimpl&& other) noexcept {
new (ptr()) T(std::move(other.value()));
return *this;
}
fast_pimpl& operator=(T&& other) noexcept {
new (ptr()) T(std::move(other));
return *this;
}
~fast_pimpl() {
ptr()->~T();
}
[[nodiscard]]
T& value() noexcept {
return reinterpret_cast<T&>(mStorage);
}
[[nodiscard]]
const T& value() const noexcept {
return reinterpret_cast<const T&>(mStorage);
}
[[nodiscard]]
T* ptr() noexcept {
return &reinterpret_cast<T&>(mStorage);
}
[[nodiscard]]
const T* ptr() const noexcept {
return &reinterpret_cast<const T&>(mStorage);
}
[[nodiscard]]
T* operator->() noexcept {
return &reinterpret_cast<T&>(mStorage);
}
[[nodiscard]]
const T* operator->() const noexcept {
return &reinterpret_cast<const T&>(mStorage);
}
[[nodiscard]]
T& operator*() noexcept {
return reinterpret_cast<T&>(mStorage);
}
[[nodiscard]]
const T& operator*() const noexcept {
return reinterpret_cast<const T&>(mStorage);
}
private:
std::aligned_storage_t<storageSize, storageAlignment> mStorage;
};
}
template<typename T, std::size_t storageSize, std::size_t storageAlignment = 8>
using APimpl = aui::fast_pimpl<T, storageSize, storageAlignment>;