Github   Telegram
Loading...
Searching...
No Matches
fast_pimpl.hpp
Go to the documentation of this file.
1#pragma once
2
5
6#include <cstddef>
7#include <new>
8#include <type_traits>
9#include <utility>
10
11USERVER_NAMESPACE_BEGIN
12
13namespace utils {
14
16inline constexpr bool kStrictMatch = true;
17
45template <class T, std::size_t Size, std::size_t Alignment, bool Strict = false>
46class FastPimpl final {
47 public:
48 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init,performance-noexcept-move-constructor)
49 FastPimpl(FastPimpl&& v) noexcept(noexcept(T(std::declval<T>())))
50 : FastPimpl(std::move(*v)) {}
51
52 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
53 FastPimpl(const FastPimpl& v) noexcept(noexcept(T(std::declval<const T&>())))
54 : FastPimpl(*v) {}
55
56 // NOLINTNEXTLINE(bugprone-unhandled-self-assignment,cert-oop54-cpp)
57 FastPimpl& operator=(const FastPimpl& rhs) noexcept(
58 noexcept(std::declval<T&>() = std::declval<const T&>())) {
59 *AsHeld() = *rhs;
60 return *this;
61 }
62
63 FastPimpl& operator=(FastPimpl&& rhs) noexcept(
64 // NOLINTNEXTLINE(performance-noexcept-move-constructor)
65 noexcept(std::declval<T&>() = std::declval<T>())) {
66 *AsHeld() = std::move(*rhs);
67 return *this;
68 }
69
70 template <typename... Args>
71 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
72 explicit FastPimpl(Args&&... args) noexcept(
73 noexcept(T(std::declval<Args>()...))) {
74 ::new (AsHeld()) T(std::forward<Args>(args)...);
75 }
76
77 T* operator->() noexcept { return AsHeld(); }
78
79 const T* operator->() const noexcept { return AsHeld(); }
80
81 T& operator*() noexcept { return *AsHeld(); }
82
83 const T& operator*() const noexcept { return *AsHeld(); }
84
85 ~FastPimpl() noexcept {
86 Validate<sizeof(T), alignof(T)>();
87 AsHeld()->~T();
88 }
89
90 private:
91 // Use a template to make actual sizes visible in the compiler error message.
92 template <std::size_t ActualSize, std::size_t ActualAlignment>
93 static void Validate() noexcept {
94 static_assert(Size >= ActualSize, "invalid Size: Size >= sizeof(T) failed");
95 static_assert(!Strict || Size == ActualSize,
96 "invalid Size: Size == sizeof(T) failed");
97
98 static_assert(Alignment % ActualAlignment == 0,
99 "invalid Alignment: Alignment % alignof(T) == 0 failed");
100 static_assert(!Strict || Alignment == ActualAlignment,
101 "invalid Alignment: Alignment == alignof(T) failed");
102 }
103
104 alignas(Alignment) std::byte storage_[Size];
105
106 T* AsHeld() noexcept { return reinterpret_cast<T*>(&storage_); }
107
108 const T* AsHeld() const noexcept {
109 return reinterpret_cast<const T*>(&storage_);
110 }
111};
112
113} // namespace utils
114
115USERVER_NAMESPACE_END