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