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;
50 constexpr semiregular_move_assign(semiregular_move_assign&&) noexcept = default;
51 constexpr semiregular_move_assign& operator=(const semiregular_move_assign&) = default;
52 constexpr semiregular_move_assign& operator=(semiregular_move_assign&& that) noexcept(
53 std::is_nothrow_move_constructible_v<T>)
54 {
55 this->reset();
56 if (that) { this->emplace(std::move(*that)); }
57 return *this;
58 }
59};
60
61template<typename T>
63 std::conditional_t<std::is_move_assignable_v<T>,
64 std::optional<T>,
66
67template<typename T>
70
71 constexpr semiregular_copy_assign() = default;
73 constexpr semiregular_copy_assign(semiregular_copy_assign&&) noexcept = default;
74 constexpr semiregular_copy_assign& operator=(const semiregular_copy_assign& that) noexcept(
75 std::is_nothrow_copy_constructible_v<T>)
76 {
77 this->reset();
78 if (that) { this->emplace(*that); }
79 return *this;
80 }
82};
83
84template<typename T>
86 std::conditional_t<std::is_copy_assignable_v<T>,
87 std::optional<T>,
89
90template<typename T> struct semiregular : semiregular_copy_layer<T> {
92
93 constexpr semiregular() : semiregular(tag{}, std::is_default_constructible<T>{})
94 {
95 }
96
97 [[nodiscard]] constexpr T& get() & { return **this; }
98 [[nodiscard]] constexpr T const& get() const& { return **this; }
99 [[nodiscard]] constexpr T&& get() && { return *std::move(*this); }
100 [[nodiscard]] constexpr T const&& get() const&& { return *std::move(*this); }
101
102 constexpr operator T&() & { return **this; }
103 constexpr operator const T&() const& { return **this; }
104 constexpr operator T &&() && { return *std::move(*this); }
105 constexpr operator const T &&() const&& { return *std::move(*this); }
106
107 template<typename... Args> constexpr auto operator()(Args&&... args) &
108 {
109 return (**this)(static_cast<Args&&>(args)...);
110 }
111 template<typename... Args> constexpr auto operator()(Args&&... args) const&
112 {
113 return (**this)(static_cast<Args&&>(args)...);
114 }
115 template<typename... Args> constexpr auto operator()(Args&&... args) &&
116 {
117 return (*std::move(*this))(static_cast<Args&&>(args)...);
118 }
119 template<typename... Args> constexpr auto operator()(Args&&... args) const&&
120 {
121 return (*std::move(*this))(static_cast<Args&&>(args)...);
122 }
123
124private:
125 struct tag {};
126
127 constexpr semiregular(tag, std::false_type) {}
128 constexpr semiregular(tag, std::true_type)
129 : semiregular_copy_layer<T>{std::in_place}
130 {
131 }
132};
133
134
135template<typename T>
136struct semiregular<T&> : private std::reference_wrapper<T&> {
137 semiregular() = default;
138
139 template<typename Arg, std::enable_if_t<(std::is_constructible<
140 std::reference_wrapper<T&>,
141 Arg&>::value)>* = nullptr>
142 constexpr semiregular(std::in_place_t, Arg& arg) : std::reference_wrapper<T&>(arg)
143 {
144 }
145
146 using std::reference_wrapper<T&>::reference_wrapper;
147 using std::reference_wrapper<T&>::get;
148 using std::reference_wrapper<T&>::operator T&;
149 using std::reference_wrapper<T&>::operator();
150};
151
152template<typename T>
153struct semiregular<T&&> : private std::reference_wrapper<T&&> {
154 semiregular() = default;
155
156 template<typename Arg, std::enable_if_t<(std::is_constructible<
157 std::reference_wrapper<T&&>,
158 Arg>::value)>* = nullptr>
159 constexpr semiregular(std::in_place_t, Arg&& arg)
160 : std::reference_wrapper<T&>(static_cast<Arg&&>(arg))
161 {
162 }
163
164 using std::reference_wrapper<T&&>::reference_wrapper;
165 using std::reference_wrapper<T&&>::get;
166 using std::reference_wrapper<T&&>::operator T&&;
167 using std::reference_wrapper<T&&>::operator();
168};
169
170} // namespace sreg_impl
171
172template<typename T>
174 std::conditional_t<std::is_default_constructible_v<T> &&
175 std::is_copy_assignable_v<T>,
177
178#endif
std::conditional_t< std::is_move_assignable_v< T >, std::optional< T >, semiregular_move_assign< T > > semiregular_move_layer
Definition: semiregular.hh:65
std::conditional_t< std::is_copy_assignable_v< T >, std::optional< T >, semiregular_copy_assign< T > > semiregular_copy_layer
Definition: semiregular.hh:88
STL namespace.
std::conditional_t< std::is_default_constructible_v< T > &&std::is_copy_assignable_v< T >, T, sreg_impl::semiregular< T > > semiregular_t
Definition: semiregular.hh:176
constexpr semiregular(std::in_place_t, Arg &arg)
Definition: semiregular.hh:142
constexpr semiregular(std::in_place_t, Arg &&arg)
Definition: semiregular.hh:159
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_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 &&
Definition: semiregular.hh:100
constexpr auto operator()(Args &&... args) const &
Definition: semiregular.hh:111
constexpr T && get() &&
Definition: semiregular.hh:99
constexpr auto operator()(Args &&... args) &
Definition: semiregular.hh:107
constexpr auto operator()(Args &&... args) &&
Definition: semiregular.hh:115
constexpr T const & get() const &
Definition: semiregular.hh:98
constexpr semiregular()
Definition: semiregular.hh:93
constexpr auto operator()(Args &&... args) const &&
Definition: semiregular.hh:119
constexpr T & get() &
Definition: semiregular.hh:97