kblib 0.2.3
General utilities library for modern C++
delayed_construct.h
Go to the documentation of this file.
1/* *****************************************************************************
2 * kblib is a general utility library for C++14 and C++17, intended to provide
3 * performant high-level abstractions and more expressive ways to do simple
4 * things.
5 *
6 * Copyright (c) 2021 killerbee
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 * ****************************************************************************/
21
32#ifndef DELAYED_CONSTRUCT_H
33#define DELAYED_CONSTRUCT_H
34
35#include "hash.h"
36#include "tdecl.h"
37
38#if KBLIB_USE_CXX17
39
40# include <optional>
41
42# if KBLIB_USE_CXX20
43
44# include <compare>
45
46# endif
47
48namespace KBLIB_NS {
49
50template <typename T>
52 private:
53 using Base = std::optional<T>;
54
55 protected:
56 Base storage;
57
58 public:
59 template <typename... Ts>
60 KBLIB_CXX20(requires(std::constructible_from<Base, Ts...>))
61 delayed_construct(Ts&&... args)
62 : storage(std::forward<Ts>(args)...) {}
63 template <typename U,
64 std::enable_if_t<std::is_assignable_v<T&, U&&>, int> = 0>
65 auto operator=(U&& t) -> delayed_construct& {
66 storage = std::forward<U>(t);
67 return *this;
68 }
69 auto operator=(std::nullopt_t) -> delayed_construct& = delete;
70
71 template <typename... Ts>
72 auto emplace(Ts&&... args) const -> decltype(auto) {
73 return storage.emplace(std::forward<Ts>(args)...);
74 }
75
78 auto operator=(const delayed_construct&) -> delayed_construct& = default;
80 ~delayed_construct() = default;
81
82 auto operator->() const -> decltype(auto) { return storage.operator->(); }
83 auto operator*() const -> decltype(auto) { return storage.operator*(); }
84 auto value() const -> decltype(auto) { return storage.value(); }
85 explicit operator bool() const { return static_cast<bool>(storage); }
86 KBLIB_NODISCARD constexpr auto is_constructed() const noexcept -> bool {
87 return storage.has_value();
88 }
89
90 // TODO(killerbee13): add C++20 operator<=> support to delayed_construct
91
92# if 0
93
94 template <std::three_way_comparable_with<Base> U>
95 requires(not std::same_as<U, delayed_construct>) KBLIB_NODISCARD auto
96 operator<=>(const U& other) const {
97 return storage <=> other;
98 }
99 template <std::equality_comparable_with<Base> U>
100 requires(not std::same_as<U, delayed_construct>) KBLIB_NODISCARD auto
101 operator==(const U& other) const {
102 return storage == other;
103 }
104 KBLIB_NODISCARD auto operator<=>(
105 const delayed_construct& other) const = default;
106 KBLIB_NODISCARD auto operator==(const delayed_construct& other) const -> bool
107 = default;
108
109# else
110
111# define OVERLOAD_DEFER_OP(op) \
112 KBLIB_NODISCARD friend constexpr auto operator op( \
113 const delayed_construct& lhs, \
114 const delayed_construct& rhs) noexcept->bool { \
115 return lhs.storage op rhs.storage; \
116 } \
117 template <typename U> \
118 KBLIB_NODISCARD friend constexpr auto operator op( \
119 const delayed_construct& lhs, \
120 const delayed_construct<U>& rhs) noexcept->bool { \
121 return lhs.storage op static_cast<const std::optional<U>&>(rhs); \
122 } \
123 KBLIB_NODISCARD friend constexpr auto operator op( \
124 const delayed_construct& lhs, \
125 std::nullopt_t rhs) noexcept->bool { \
126 return lhs.storage op rhs; \
127 } \
128 KBLIB_NODISCARD friend constexpr auto operator op( \
129 std::nullopt_t lhs, \
130 const delayed_construct& rhs) noexcept->bool { \
131 return lhs op rhs.storage; \
132 } \
133 template <typename U> \
134 KBLIB_NODISCARD friend constexpr auto operator op( \
135 const delayed_construct& opt, const U& value) noexcept->bool { \
136 return opt.storage op value; \
137 } \
138 template <typename U> \
139 KBLIB_NODISCARD friend constexpr auto operator op( \
140 const U& value, const delayed_construct& opt) noexcept->bool { \
141 return value op opt.storage; \
142 }
143
155
168
169# undef OVERLOAD_DEFER_OP
170# endif
171
172 friend struct std::hash<delayed_construct<T>>;
173 friend struct FNV_hash<delayed_construct<T>>;
174};
175
176template <typename T>
177struct FNV_hash<delayed_construct<T>, void> {
178 KBLIB_NODISCARD constexpr std::size_t operator()(
179 const delayed_construct<T>& key,
180 std::size_t offset
181 = fnv::fnv_offset<std::size_t>::value) const noexcept {
182 if (key) {
183 return FNV_hash<T>{}(key.value(), offset);
184 } else {
185 return FNV_hash<std::nullopt_t>{}(std::nullopt, offset);
186 }
187 }
188};
189
190} // namespace KBLIB_NS
191
192namespace std {
193
194// Inheriting from another hash specialization means that this hash is (mostly)
195// disabled when std::hash<T> is (if I read the requirements correctly,
196// operator() should not be declared in a disabled std::hash, but I basically
197// can't do that in any sensible way)
198template <typename T>
199struct hash<kblib::delayed_construct<T>> : hash<T> {
201 auto operator()(const argument_type& value) const noexcept -> std::size_t {
202 return hash<optional<T>>{}(static_cast<const optional<T>&>(value));
203 }
204};
205
206} // namespace std
207
208#endif // KBLIB_USE_CXX17
209
210#endif // DELAYED_CONSTRUCT_H
auto emplace(Ts &&... args) const -> decltype(auto)
auto value() const -> decltype(auto)
auto operator=(U &&t) -> delayed_construct &
auto operator=(std::nullopt_t) -> delayed_construct &=delete
constexpr auto is_constructed() const noexcept -> bool
delayed_construct(delayed_construct &&)=default
auto operator=(delayed_construct &&) -> delayed_construct &=default
delayed_construct(const delayed_construct &)=default
auto operator=(const delayed_construct &) -> delayed_construct &=default
auto operator->() const -> decltype(auto)
auto operator*() const -> decltype(auto)
#define OVERLOAD_DEFER_OP(op)
Provides generic facilities for hashing data, and aliases for standard unordered containers using the...
The main namespace in which all entities from kblib are defined.
Definition: algorithm.h:44
Definition: bits.h:721
constexpr std::size_t operator()(const delayed_construct< T > &key, std::size_t offset=fnv::fnv_offset< std::size_t >::value) const noexcept
The primary template has to exist, but not be constructible, in order to be compatible with std::hash...
Definition: hash.h:334
The starting value for the FNVa hash algorithm, as a type trait.
Definition: hash.h:128
auto operator()(const argument_type &value) const noexcept -> std::size_t
Provides macros and basic templates used by the rest of kblib.
#define KBLIB_NS
Definition: tdecl.h:113
#define KBLIB_NODISCARD
This internal macro is used to provide a fallback for [[nodiscard]] in C++14.
Definition: tdecl.h:129
#define KBLIB_CXX20(args)
This internal macro is used to selectively use C++20 features.
Definition: tdecl.h:96