Pretty Good Sum Type  1.0.0
sum_type.hpp
1 #if !defined(SUM_F8718480_DC1C_4410_84C0_DDDA2C2FED94_H)
2 # define SUM_F8718480_DC1C_4410_84C0_DDDA2C2FED94_H
3 
8 
9 /*
10  * Copyright (c) 2013 Björn Aili
11  *
12  * This software is provided 'as-is', without any express or implied
13  * warranty. In no event will the authors be held liable for any damages
14  * arising from the use of this software.
15  *
16  * Permission is granted to anyone to use this software for any purpose,
17  * including commercial applications, and to alter it and redistribute it
18  * freely, subject to the following restrictions:
19  *
20  * 1. The origin of this software must not be misrepresented; you must not
21  * claim that you wrote the original software. If you use this software
22  * in a product, an acknowledgment in the product documentation would be
23  * appreciated but is not required.
24  *
25  * 2. Altered source versions must be plainly marked as such, and must not be
26  * misrepresented as being the original software.
27  *
28  * 3. This notice may not be removed or altered from any source
29  * distribution.
30  */
31 
47 
69 
70 # include <pgs/recursive_union.hpp>
71 
72 # include <cstddef>
73 # include <iostream>
74 # include <string>
75 
76 namespace pgs {
77 
80 struct otherwise {
81  template <class T>
82  otherwise (T&&) {} //< Construct from anything
83 };
84 
86 template <class... Ts> class sum_type;//fwd. decl
88 
90 namespace detail {
91 
92  template <std::size_t I, class T, class... Ts>
93  struct index_of_impl;
94 
95  template <std::size_t I, class T, class... Ts>
96  struct index_of_impl<I, T, T, Ts...> {
97  static auto const value = I;
98  };
99 
100  template <std::size_t I, class T, class... Ts>
101  struct index_of_impl<I, T, recursive_wrapper<T>, Ts...> {
102  static auto const value = I;
103  };
104 
105  template <std::size_t I, class X, class T, class... Ts>
106  struct index_of_impl<I, X, T, Ts...>{
107  static auto const value = index_of_impl<I + 1, X, Ts...>::value;
108  };
109 
110  template <std::size_t I, class T, class... Ts>
111  struct type_at_impl : type_at_impl<I - 1, Ts...>
112  {};
113 
114  template <class T, class... Ts>
115  struct type_at_impl<0, T, Ts...> {
116  using type = recursive_wrapper_unwrap_t<T>;
117  };
118 
119  struct sum_type_accessor {
120 
121  template <class... Ts>
122  static constexpr std::size_t active_index (sum_type<Ts...> const& s)
123  noexcept {
124  return s.cons;
125  }
126 
127  template <class... Ts>
128  static constexpr bool compare_at (
129  std::size_t i, sum_type<Ts...> const& u, sum_type<Ts...> const& v)
130  noexcept {
131  return u.data.compare (i, v.data);
132  }
133 
134  };
135 
136  template <std::size_t I, class... Ts>
137  struct get_sum_type_element {
138 
139  static auto get (sum_type<Ts...>& u)
140  -> decltype (recursive_union_indexer<I, Ts...>::ref (u.data)) {
141  if (u.cons != I){
142  std::string message;
143  message += "Indexing with ";
144  message += std::to_string (I);
145  message += ", but the active index is ";
146  message += std::to_string (u.cons);
147 
148  throw invalid_sum_type_access{message};
149  }
151  }
152 
153  static auto get (sum_type<Ts...> const& u)
154  -> decltype (recursive_union_indexer<I, Ts...>::ref (u.data))
155  {
156  if (u.cons != I){
157  std::string message;
158  message += "Indexing with ";
159  message += std::to_string (I);
160  message += ", but the active index is ";
161  message += std::to_string (u.cons);
162 
163  throw invalid_sum_type_access{message};
164  }
166  }
167  };
168 
169 }//namespace detail
171 
177 template <class T, class... Ts>
178 struct index_of {
180  static constexpr auto const value =
181  detail::index_of_impl<0u, T, Ts...>::value;
182 };
183 
185 template <std::size_t I, class... Ts>
186 using type_at = typename detail::type_at_impl<I, Ts...>::type;
187 
192 template <class... Ts>
193 class sum_type {
194 private:
195  std::size_t cons;
196  recursive_union<Ts...> data;
197 
198 private:
199  friend struct detail::sum_type_accessor;
200  template <std::size_t I, class... Us>
201  friend struct detail::get_sum_type_element;
202 
203 public:
204 
206  template <class T, class... Args>
207  explicit sum_type (constructor<T> t, Args&&... args);
208 
209  sum_type () = delete;
210  sum_type (sum_type const& other);
211  sum_type (sum_type&& other);
212 
213  ~sum_type();
214 
216  sum_type& operator= (sum_type const& other);
217 
219  sum_type& operator= (sum_type&& other);
220 
222  template <class R, class... Fs> R match(Fs&&... fs) const;
224  template <class R, class... Fs> R match(Fs&&... fs);
226  template <class... Fs> void match(Fs&&... fs) const;
228  template <class... Fs> void match(Fs&&... fs);
229 
231  template<class T>
232  constexpr bool is () const noexcept;
233 
235  template<std::size_t I>
236  constexpr bool is_type_at () const noexcept;
237 };
238 
240 template <class... Ts>
241 sum_type<Ts...>::sum_type (sum_type const& other) : cons (other.cons) {
242  //std::cout << "sum_type::sum_type (sum_type const &)\n";
243  data.copy (cons, other.data);
244 }
245 
246 template <class... Ts>
247 sum_type<Ts...>::sum_type (sum_type&& other) : cons (other.cons) {
248  //std::cout << "sum_type::sum_type (sum_type&&)\n";
249  data.move (cons, std::move (other.data));
250 }
251 
252 template <class... Ts>
253  template <class T, class... Args>
254  sum_type<Ts...>::sum_type (constructor<T> t, Args&&... args)
255  : data (t, std::forward<Args>(args)...), cons (index_of<T, Ts...>::value){
256  //std::cout << "sum_type<Ts...>::sum_type (constructor<T> t, Args&&... args)\n";
257 }
258 
259 template <class... Ts>
261  data.destruct (cons);
262 }
263 
264 template <class... Ts>
265 sum_type<Ts...>& sum_type<Ts...>::operator= (sum_type const& other) {
266  if (std::addressof (other) == this)
267  return *this;
268 
269  data.destruct (cons);
270  cons = other.cons;
271  data.copy (cons, other.data);
272 
273  return *this;
274 }
275 
276 template <class... Ts>
277 sum_type<Ts...>& sum_type<Ts...>::operator= (sum_type&& other) {
278  if (std::addressof (other) == this)
279  return *this;
280 
281  data.destruct (cons);
282  cons = other.cons;
283  data.move (cons, std::move (other.data));
284 
285  return *this;
286 }
287 
288 template<class... Ts>
289  template <class R, class... Fs>
290 R sum_type<Ts...>::match(Fs&&... fs) const {
291  using indicies = range_t<0, sizeof... (Ts) - 1>;
293  data, cons, std::forward<Fs>(fs)...);
294 }
295 
296 template<class... Ts>
297  template <class R, class... Fs>
298 R sum_type<Ts...>::match(Fs&&... fs) {
299  using indicies = range_t<0, sizeof... (Ts) - 1>;
300 
302  data, cons, std::forward<Fs>(fs)...);
303 }
304 
305 template<class... Ts>
306  template <class... Fs>
307 void sum_type<Ts...>::match(Fs&&... fs) const {
308  using indicies = range_t<0, sizeof... (Ts) - 1>;
309 
311  data, cons, std::forward<Fs>(fs)...);
312 }
313 
314 template<class... Ts>
315  template <class... Fs>
316 void sum_type<Ts...>::match(Fs&&... fs) {
317  using indicies = range_t<0, sizeof... (Ts) - 1>;
318 
320  data, cons, std::forward<Fs>(fs)...);
321 }
322 
323 template <class... Ts>
324  template <class T>
325 constexpr bool sum_type<Ts...>::is () const noexcept {
326  return cons == index_of<T, Ts...>::value;
327 }
328 
329 template <class... Ts>
330  template <std::size_t I>
331 constexpr bool sum_type<Ts...>::is_type_at () const noexcept {
332  return cons == I;
333 }
335 
338 
339 template<class T, class ... Ts>
340 constexpr T const& get (sum_type<Ts...> const& s);
341 
344 
345 template<class T, class ... Ts>
346 constexpr T& get (sum_type<Ts...>& s);
347 
349 
350 template<class T, class ... Ts>
351 constexpr T const& get (sum_type<Ts...> const& s) {
352  return detail::get_sum_type_element<
353  index_of<T, Ts...>::value, Ts...>::get (s);
354 }
355 
356 template<class T, class ... Ts>
357 constexpr T& get (sum_type<Ts...>& s) {
358  return detail::get_sum_type_element<
359  index_of<T, Ts...>::value, Ts...>::get (s);
360 }
361 
363 
365 
366 template <std::size_t I, class... Ts>
367 constexpr type_at<I, Ts...>& get (sum_type<Ts...>& s);
368 
370 
371 template <std::size_t I, class... Ts>
372 constexpr type_at<I, Ts...> const& get (sum_type<Ts...> const& s);
373 
375 template <std::size_t I, class... Ts>
376 inline constexpr type_at<I, Ts...>& get (sum_type<Ts...>& s) {
377  return detail::get_sum_type_element<I, Ts...>::get (s);
378 }
379 
380 template <std::size_t I, class... Ts>
381 inline constexpr type_at<I, Ts...> const& get (sum_type<Ts...> const& s) {
382  return detail::get_sum_type_element<I, Ts...>::get (s);
383 }
385 
386 template <class... Ts>
387 bool operator == (sum_type<Ts...> const& u, sum_type<Ts...> const& v) {
388  std::size_t m = detail::sum_type_accessor::active_index (u);
389  std::size_t n = detail::sum_type_accessor::active_index (v);
390 
391  return m == n && detail::sum_type_accessor::compare_at (m, u, v);
392 }
393 
394 template <class... Ts>
395 bool operator != (sum_type<Ts...> const& u, sum_type<Ts...> const& v) {
396  return ! (u == v);
397 }
398 
399 }//namespace pgs
400 
401 #endif
A type modeling a "recursive union".
A type modeling "sums with constructors" as used in functional programming.
Definition: sum_type.hpp:193
R match(Fs &&...fs) const
match function, const overoad
constexpr bool is_type_at() const noexcept
The currently active v is at position I?
constexpr bool is() const noexcept
The currently active v is a T?
~sum_type()
Dtor.
T to_string(T...args)
Definition: logical.hpp:13
A utility suitable for use as a wildcard in a pattern match.
Definition: sum_type.hpp:80
sum_type & operator=(sum_type const &other)
Copy-assign operator.
static result_type visit(overload_tag< O >, T const &t, F &&f, Fs &&...)
f is callable on t (of type T const&)
Definition: recursive_union.hpp:171
A metafunction to compute the index I of a type T in a sequence Ts
Definition: sum_type.hpp:178
static constexpr auto const value
The index of T in Ts...
Definition: sum_type.hpp:180
T addressof(T...args)
T move(T...args)
A type to model a sum constructor.
Definition: recursive_union.hpp:22
recursive union<> primary template
Definition: recursive_union.hpp:25
static constexpr auto ref(recursive_union< T, Ts... > &u) -> decltype(recursive_union_indexer< I-1, Ts... >::ref(u.r))
Decrement I, strip off T and recurse.
Definition: recursive_union.hpp:96
T forward(T...args)