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 
43 namespace sreg_impl {
44 
45 template<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(const 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 
61 template<typename T>
63  std::conditional_t<std::is_move_assignable_v<T>,
64  std::optional<T>,
66 
67 template<typename T>
70 
71  constexpr semiregular_copy_assign() = default;
72  constexpr semiregular_copy_assign(const 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  }
81  constexpr semiregular_copy_assign& operator=(semiregular_copy_assign&&) noexcept = default;
82 };
83 
84 template<typename T>
86  std::conditional_t<std::is_copy_assignable_v<T>,
87  std::optional<T>,
89 
90 template<typename T> struct semiregular : semiregular_copy_layer<T> {
92 
93  constexpr semiregular() : semiregular(tag{}, std::is_default_constructible<T>{})
94  {
95  }
96 
97  constexpr T& get() & { return **this; }
98  constexpr T const& get() const& { return **this; }
99  constexpr T&& get() && { return *std::move(*this); }
100  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 
124 private:
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 
135 template<typename T>
136 struct 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 
152 template<typename T>
153 struct 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 
172 template<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
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 & get() &
Definition: semiregular.hh:97
constexpr auto operator()(Args &&... args) const &
Definition: semiregular.hh:111
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 T const && get() const &&
Definition: semiregular.hh:100
constexpr T && get() &&
Definition: semiregular.hh:99
constexpr semiregular()
Definition: semiregular.hh:93
constexpr auto operator()(Args &&... args) const &&
Definition: semiregular.hh:119