Simple-Utility v2.3.1
Loading...
Searching...
No Matches
adapter.hpp
Go to the documentation of this file.
1// Copyright Dominic Koepke 2019 - 2023.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at
4// https://www.boost.org/LICENSE_1_0.txt)
5
6#ifndef SL_UTILITY_NULLABLES_ADAPTER_HPP
7#define SL_UTILITY_NULLABLES_ADAPTER_HPP
8
9#pragma once
10
14
15#include <cassert>
16#include <ranges>
17
19{
20 namespace detail
21 {
22 template <class TAdapted>
24 && requires { { *std::declval<TAdapted>() } -> concepts::not_same_as<void>; }
25 [[nodiscard]]
26 constexpr decltype(auto) unwrap_adapted(TAdapted&& adapted)
27 {
28 return *std::forward<TAdapted>(adapted);
29 }
30
31 struct unwrap_adapted_fn
32 {
33 template <class TAdapted>
34 requires requires { unwrap_adapted(std::declval<TAdapted>()); }
35 [[nodiscard]]
36 constexpr decltype(auto) operator()(
37 TAdapted&& adapted
38 ) const
39 noexcept(noexcept(unwrap_adapted(std::forward<TAdapted>(adapted))))
40 {
41 return unwrap_adapted(std::forward<TAdapted>(adapted));
42 }
43 };
44 }
45
46 inline constexpr detail::unwrap_adapted_fn unwrap_adapted{};
47}
48
49namespace sl::nullables
50{
62 {
63 };
64
69 inline constexpr adapter_null_t adapter_null{};
70
77 {
78 };
79
85 inline constexpr in_place_null_t in_place_null{};
86
87 template <class T>
88 using adapted_value_t = std::remove_cvref_t<decltype(unwrap_adapted(std::declval<T>()))>;
89
95 template <class TAdapted, class TNull>
96 concept adaptable_with = std::movable<TNull>
97 && std::movable<TAdapted>
99 && requires
100 {
101 typename adapted_value_t<TAdapted>;
102 { unwrap_adapted(std::declval<TAdapted>()) } -> std::convertible_to<adapted_value_t<TAdapted>>;
103 };
104
105 template <class TNull, adaptable_with<TNull> TAdapted>
106 requires std::same_as<TNull, std::remove_cvref_t<TNull>>
107 && std::same_as<TAdapted, std::remove_cvref_t<TAdapted>>
108 class adapter;
109}
110
111namespace sl::nullables::detail
112{
113 template <std::ranges::borrowed_range TRange>
114 [[nodiscard]]
115 constexpr adapter<std::ranges::sentinel_t<TRange>, std::ranges::iterator_t<TRange>> to_nullables_adapter(TRange&& range)
116 {
117 return {std::ranges::end(range), std::ranges::begin(range)};
118 }
119
120 struct to_nullables_adapter_fn
121 {
122 template <class TArg>
123 requires requires { adapter{to_nullables_adapter(std::declval<TArg>())}; }
124 [[nodiscard]]
125 constexpr auto operator()(TArg&& arg) const noexcept(noexcept(to_nullables_adapter(std::forward<TArg>(arg))))
126 {
127 return to_nullables_adapter(std::forward<TArg>(arg));
128 }
129 };
130}
131
132namespace sl::nullables
133{
141 inline constexpr detail::to_nullables_adapter_fn to_nullables_adapter{};
142
143 namespace detail
144 {
145 template <class T>
146 concept convertible_to_adapter = requires
147 {
148 adapter{nullables::to_nullables_adapter(std::declval<T>())};
149 };
150 }
151
162 template <class TNull, adaptable_with<TNull> TAdapted>
163 requires std::same_as<TNull, std::remove_cvref_t<TNull>>
164 && std::same_as<TAdapted, std::remove_cvref_t<TAdapted>>
166 {
167 public:
168 using adapted_type = TAdapted;
170 using null_type = TNull;
171
175 constexpr ~adapter() noexcept = default;
176
181 [[nodiscard]]
182 constexpr adapter(
183 const adapter& other
184 ) noexcept(std::is_nothrow_copy_constructible_v<TNull>
185 && std::is_nothrow_copy_constructible_v<TAdapted>)
186 = default;
187
192 constexpr adapter& operator =(
193 const adapter& other
194 ) noexcept(std::is_nothrow_copy_assignable_v<TNull>
195 && std::is_nothrow_copy_assignable_v<TAdapted>)
196 = default;
197
202 [[nodiscard]]
203 constexpr adapter(
204 adapter&& other
205 ) noexcept(std::is_nothrow_move_constructible_v<TNull>
206 && std::is_nothrow_move_constructible_v<TAdapted>)
207 = default;
208
213 constexpr adapter& operator =(
214 adapter&& other
215 ) noexcept(std::is_nothrow_move_assignable_v<TNull>
216 && std::is_nothrow_move_assignable_v<TAdapted>)
217 = default;
218
225 template <concepts::initializes<null_type> TNullArg>
226 requires std::constructible_from<adapted_type, const null_type&>
227 [[nodiscard]]
228 explicit
229 constexpr adapter(
230 [[maybe_unused]] in_place_null_t,
231 TNullArg&& nullArg
232 )
233 noexcept(std::is_nothrow_constructible_v<null_type, TNullArg>
234 && std::is_nothrow_constructible_v<adapted_type, const null_type&>)
235 : m_Null{std::forward<TNullArg>(nullArg)},
236 m_Adapted{m_Null}
237 {
238 assert(*this == adapter_null && "Default constructed adapted_type must comapare equally to the provided null object.");
239 }
240
245 [[nodiscard]]
246 explicit
247 constexpr adapter(
248 [[maybe_unused]] adapter_null_t
249 )
250 noexcept(std::is_nothrow_default_constructible_v<null_type>
251 && std::is_nothrow_constructible_v<adapted_type, null_type&>)
252 requires std::default_initializable<null_type>
253 && std::constructible_from<adapted_type, null_type&>
255 {
256 }
257
261 template <concepts::initializes<null_type> TNullArg>
264 && (!detail::convertible_to_adapter<TNullArg>)
265 && std::constructible_from<adapted_type, const null_type&>
266 [[nodiscard]]
267 explicit
268 constexpr adapter(
269 TNullArg&& nullArg
270 )
271 noexcept(std::is_nothrow_constructible_v<adapter, std::in_place_t, TNullArg>)
272 : adapter{in_place_null, nullArg}
273 {
274 }
275
283 template <concepts::initializes<null_type> TNullArg, concepts::initializes<adapted_type> TAdaptedArg>
288 [[nodiscard]]
289 constexpr adapter(
290 TNullArg&& nullArg,
291 TAdaptedArg&& adaptedArg
292 )
293 noexcept(std::is_nothrow_constructible_v<null_type, TNullArg>
294 && std::is_nothrow_constructible_v<adapted_type, TAdaptedArg>)
295 : m_Null{std::forward<TNullArg>(nullArg)},
296 m_Adapted{std::forward<TAdaptedArg>(adaptedArg)}
297 {
298 }
299
306 template <detail::convertible_to_adapter TArg>
307 requires concepts::not_same_as<adapter_null_t, std::remove_cvref_t<TArg>>
308 && concepts::not_same_as<in_place_null_t, std::remove_cvref_t<TArg>>
309 [[nodiscard]]
310 explicit
311 constexpr adapter(
312 TArg&& arg
313 )
314 noexcept(noexcept(to_nullables_adapter(std::forward<TArg>(arg)))
315 && std::is_nothrow_constructible_v<adapter>)
316 : adapter{to_nullables_adapter(std::forward<TArg>(arg))}
317 {
318 }
319
325 constexpr adapter& operator =(
326 [[maybe_unused]] adapter_null_t
327 )
328 noexcept(std::is_nothrow_assignable_v<adapted_type&, null_type&>)
329 requires std::assignable_from<adapted_type&, null_type&>
330 {
331 m_Adapted = m_Null;
332 assert(*this == adapter_null && "adapted_type must comapare equally to the null object.");
333
334 return *this;
335 }
336
341 template <concepts::assignable_to<adapted_type&> TAdaptedArg>
343 constexpr adapter& operator =(
344 TAdaptedArg&& adaptedArg
345 )
346 noexcept(std::is_nothrow_assignable_v<adapted_type&, TAdaptedArg>)
347 {
348 m_Adapted = std::forward<TAdaptedArg>(adaptedArg);
349
350 return *this;
351 }
352
359 [[nodiscard]]
360 constexpr decltype(auto) operator *() const &
361 {
362 assert(*this != adapter_null && "Dereferenced adapted nullable is equally to its null.");
363
364 return unwrap_adapted(m_Adapted);
365 }
366
370 [[nodiscard]]
371 constexpr decltype(auto) operator *() &
372 {
373 assert(*this != adapter_null && "Dereferenced adapted nullable is equally to its null.");
374
375 return unwrap_adapted(m_Adapted);
376 }
377
381 [[nodiscard]]
382 constexpr decltype(auto) operator *() &&
383 {
384 assert(*this != adapter_null && "Dereferenced adapted nullable is equally to its null.");
385
386 return unwrap_adapted(std::move(m_Adapted));
387 }
388
393 [[nodiscard]]
394 constexpr bool operator ==(
396 ) const
398 {
399 return m_Adapted == m_Null;
400 }
401
402 private:
404 null_type m_Null{};
405 adapted_type m_Adapted{};
406 };
407
414 template <class TNull, class TAdapted>
416
422 template <class T>
423 requires requires { to_nullables_adapter(std::declval<T>()); }
425 T&& t
426 ) -> adapter<
427 typename std::remove_cvref_t<decltype(to_nullables_adapter(std::declval<T>()))>::null_type,
428 typename std::remove_cvref_t<decltype(to_nullables_adapter(std::declval<T>()))>::adapted_type
429 >;
430
438 template <class TNull, class TAdapted>
439 struct traits<adapter<TNull, TAdapted>>
440 {
442 constexpr static adapter_null_t null{adapter_null};
443 };
444
446}
447
448#endif
#define SL_UTILITY_NO_UNIQUE_ADDRESS
Definition: Config.hpp:21
A adapter class, mimic the behaviour of nullable types.
Definition: adapter.hpp:166
constexpr adapter & operator=(const adapter &other) noexcept(std::is_nothrow_copy_assignable_v< TNull > &&std::is_nothrow_copy_assignable_v< TAdapted >)=default
Default copy assignment operator.
constexpr adapter(TNullArg &&nullArg, TAdaptedArg &&adaptedArg) noexcept(std::is_nothrow_constructible_v< null_type, TNullArg > &&std::is_nothrow_constructible_v< adapted_type, TAdaptedArg >)
Constructs the null object and the adapted with the given arguments.
Definition: adapter.hpp:289
TNull null_type
Definition: adapter.hpp:170
constexpr adapter(TArg &&arg) noexcept(noexcept(to_nullables_adapter(std::forward< TArg >(arg))) &&std::is_nothrow_constructible_v< adapter >)
Constructs the adapter with the result of a to_nullables_adapter invocation.
Definition: adapter.hpp:311
constexpr bool operator==(adapter_null_t) const noexcept(concepts::nothrow_weakly_equality_comparable_with< TAdapted, TNull >)
Comparison operator with its adapter_null`object.
Definition: adapter.hpp:394
constexpr ~adapter() noexcept=default
Default destructor.
adapted_value_t< TAdapted > value_type
Definition: adapter.hpp:169
constexpr adapter(TNullArg &&nullArg) noexcept(std::is_nothrow_constructible_v< adapter, std::in_place_t, TNullArg >)
Constructs the null object with the given argument and then constructs the adapted object with the nu...
Definition: adapter.hpp:268
constexpr adapter(adapter_null_t) noexcept(std::is_nothrow_default_constructible_v< null_type > &&std::is_nothrow_constructible_v< adapted_type, null_type & >)
Default constructs the null object and then constructs the adapted object with the null object.
Definition: adapter.hpp:247
TAdapted adapted_type
Definition: adapter.hpp:168
Determines whether a type can be used in unary operator * expressions.
Definition: operators.hpp:725
Checks whether the left-hand-side type is unequal to the right-hand-side type.
Definition: stl_extensions.hpp:69
Checks whether a symmetrical set of operators == and != to compare both types with each other exists ...
Definition: stl_extensions.hpp:140
Checks whether a symmetrical set of operators == and != to compare both types with each other exists.
Definition: stl_extensions.hpp:124
Determines whether the given adapted and null type satisfy the requirements to be used within a adapt...
Definition: adapter.hpp:96
std::remove_cvref_t< decltype(unwrap_adapted(std::declval< T >()))> adapted_value_t
Definition: adapter.hpp:88
adapter(TNull, TAdapted) -> adapter< TNull, TAdapted >
Deduction guide.
adapter(T &&t) -> adapter< typename std::remove_cvref_t< decltype(to_nullables_adapter(std::declval< T >()))>::null_type, typename std::remove_cvref_t< decltype(to_nullables_adapter(std::declval< T >()))>::adapted_type >
Deduction guide, which makes use of to_nullables_adapter customization point.
constexpr in_place_null_t in_place_null
Tag object for adapters, which can be used to disambiguate the construction with just a null-object.
Definition: adapter.hpp:85
constexpr adapter_null_t adapter_null
Dedicated null object for adapters.
Definition: adapter.hpp:69
constexpr detail::to_nullables_adapter_fn to_nullables_adapter
Converts the given argument to a adapter object.
Definition: adapter.hpp:141
Definition: adapter.hpp:19
constexpr detail::unwrap_adapted_fn unwrap_adapted
Definition: adapter.hpp:46
Dedicated null type for adapters.
Definition: adapter.hpp:62
Tag type for adapters, which can be used to disambiguate the construction with just a null-object.
Definition: adapter.hpp:77
adapted_value_t< TAdapted > value_type
Definition: adapter.hpp:441
The main trait, which may be specialized from.
Definition: base.hpp:97