openMSX
semiregular.hh
Go to the documentation of this file.
1// semiregular_t<T>
2//
3// Background info:
4// See here for the definition of the SemiRegular concept
5// https://en.cppreference.com/w/cpp/concepts/Semiregular
6// In short: a type is Semiregular iff it is DefaultConstructible and Copyable
7// (and Copyable requires Movable, CopyConstructible, ...)
8//
9// Regular (instead of SemiRegular) additionally requires EqualityComparable,
10// but we don't need that here.
11//
12// The semiregular_t<T> utility, takes a (possibly) non-SemiRegular type T and
13// wraps it so that it does become SemiRegular. More specifically
14// semiregular_t<T> is default constructible and assignable (but if T is
15// move-only, then semiregular_t<T> remains move-only). Internally this works by
16// wrapping T in an std::optional<T> (but only when needed).
17//
18// This implementation is taken from (and simplified / stripped down):
19// https://github.com/ericniebler/range-v3/blob/master/include/range/v3/utility/semiregular.hpp
20//
21// Original file header:
22// Range v3 library
23//
24// Copyright Eric Niebler 2013-present
25//
26// Use, modification and distribution is subject to the
27// Boost Software License, Version 1.0. (See accompanying
28// file LICENSE_1_0.txt or copy at
29// http://www.boost.org/LICENSE_1_0.txt)
30//
31// Project home: https://github.com/ericniebler/range-v3
32//
33
34#ifndef SEMIREGULAR_HH
35#define SEMIREGULAR_HH
36
37#include <cstddef>
38#include <optional>
39#include <string>
40#include <type_traits>
41#include <utility>
42
43namespace sreg_impl {
44
45template<typename T> struct semiregular_move_assign : std::optional<T> {
46 using std::optional<T>::optional;
47
48 constexpr semiregular_move_assign() = default;
49 constexpr ~semiregular_move_assign() = default;
51 constexpr semiregular_move_assign(semiregular_move_assign&&) noexcept = default;
52 constexpr semiregular_move_assign& operator=(const semiregular_move_assign&) = default;
53 constexpr semiregular_move_assign& operator=(semiregular_move_assign&& that) noexcept(
54 std::is_nothrow_move_constructible_v<T>)
55 {
56 this->reset();
57 if (that) { this->emplace(std::move(*that)); }
58 return *this;
59 }
60};
61
62template<typename T>
64 std::conditional_t<std::is_move_assignable_v<T>,
65 std::optional<T>,
67
68template<typename T>
71
72 constexpr semiregular_copy_assign() = default;
73 constexpr ~semiregular_copy_assign() = default;
75 constexpr semiregular_copy_assign(semiregular_copy_assign&&) noexcept = default;
76 constexpr semiregular_copy_assign& operator=(const semiregular_copy_assign& that) noexcept(
77 std::is_nothrow_copy_constructible_v<T>)
78 {
79 this->reset();
80 if (that) { this->emplace(*that); }
81 return *this;
82 }
84};
85
86template<typename T>
88 std::conditional_t<std::is_copy_assignable_v<T>,
89 std::optional<T>,
91
92template<typename T> struct semiregular : semiregular_copy_layer<T> {
94
95 constexpr semiregular() : semiregular(tag{}, std::is_default_constructible<T>{})
96 {
97 }
98
99 [[nodiscard]] constexpr T& get() & { return **this; }
100 [[nodiscard]] constexpr T const& get() const& { return **this; }
101 [[nodiscard]] constexpr T&& get() && { return *std::move(*this); }
102 [[nodiscard]] constexpr T const&& get() const&& { return *std::move(*this); }
103
104 constexpr operator T&() & { return **this; }
105 constexpr operator const T&() const& { return **this; }
106 constexpr operator T &&() && { return *std::move(*this); }
107 constexpr operator const T &&() const&& { return *std::move(*this); }
108
109 template<typename... Args> constexpr auto operator()(Args&&... args) &
110 {
111 return (**this)(static_cast<Args&&>(args)...);
112 }
113 template<typename... Args> constexpr auto operator()(Args&&... args) const&
114 {
115 return (**this)(static_cast<Args&&>(args)...);
116 }
117 template<typename... Args> constexpr auto operator()(Args&&... args) &&
118 {
119 return (*std::move(*this))(static_cast<Args&&>(args)...);
120 }
121 template<typename... Args> constexpr auto operator()(Args&&... args) const&&
122 {
123 return (*std::move(*this))(static_cast<Args&&>(args)...);
124 }
125
126private:
127 struct tag {};
128
129 constexpr semiregular(tag, std::false_type) {}
130 constexpr semiregular(tag, std::true_type)
131 : semiregular_copy_layer<T>{std::in_place}
132 {
133 }
134};
135
136
137template<typename T>
138struct semiregular<T&> : private std::reference_wrapper<T&> {
139 semiregular() = default;
140
141 template<typename Arg, std::enable_if_t<(std::is_constructible_v<
142 std::reference_wrapper<T&>,
143 Arg&>)>* = nullptr>
144 constexpr semiregular(std::in_place_t, Arg& arg) : std::reference_wrapper<T&>(arg)
145 {
146 }
147
148 using std::reference_wrapper<T&>::reference_wrapper;
149 using std::reference_wrapper<T&>::get;
150 using std::reference_wrapper<T&>::operator T&;
151 using std::reference_wrapper<T&>::operator();
152};
153
154template<typename T>
155struct semiregular<T&&> : private std::reference_wrapper<T&&> {
156 semiregular() = default;
157
158 template<typename Arg, std::enable_if_t<(std::is_constructible_v<
159 std::reference_wrapper<T&&>,
160 Arg>)>* = nullptr>
161 constexpr semiregular(std::in_place_t, Arg&& arg)
162 : std::reference_wrapper<T&>(static_cast<Arg&&>(arg))
163 {
164 }
165
166 using std::reference_wrapper<T&&>::reference_wrapper;
167 using std::reference_wrapper<T&&>::get;
168 using std::reference_wrapper<T&&>::operator T&&;
169 using std::reference_wrapper<T&&>::operator();
170};
171
172} // namespace sreg_impl
173
174template<typename T>
176 std::conditional_t<std::is_default_constructible_v<T> &&
177 std::is_copy_assignable_v<T>,
179
180#endif
std::conditional_t< std::is_move_assignable_v< T >, std::optional< T >, semiregular_move_assign< T > > semiregular_move_layer
std::conditional_t< std::is_copy_assignable_v< T >, std::optional< T >, semiregular_copy_assign< T > > semiregular_copy_layer
STL namespace.
std::conditional_t< std::is_default_constructible_v< T > &&std::is_copy_assignable_v< T >, T, sreg_impl::semiregular< T > > semiregular_t
constexpr semiregular(std::in_place_t, Arg &arg)
constexpr semiregular(std::in_place_t, Arg &&arg)
constexpr semiregular_copy_assign()=default
constexpr semiregular_copy_assign & operator=(semiregular_copy_assign &&) noexcept=default
constexpr semiregular_copy_assign(const semiregular_copy_assign &)=default
constexpr semiregular_copy_assign(semiregular_copy_assign &&) noexcept=default
constexpr ~semiregular_copy_assign()=default
constexpr ~semiregular_move_assign()=default
constexpr semiregular_move_assign()=default
constexpr semiregular_move_assign(const semiregular_move_assign &)=default
constexpr semiregular_move_assign(semiregular_move_assign &&) noexcept=default
constexpr T const && get() const &&
constexpr auto operator()(Args &&... args) const &
constexpr T && get() &&
constexpr auto operator()(Args &&... args) &
constexpr auto operator()(Args &&... args) &&
constexpr T const & get() const &
constexpr auto operator()(Args &&... args) const &&
constexpr T & get() &