318
|
1 // Copyright Toru Niina 2017.
|
|
2 // Distributed under the MIT License.
|
|
3 #ifndef TOML11_RESULT_HPP
|
|
4 #define TOML11_RESULT_HPP
|
|
5 #include "traits.hpp"
|
|
6 #include <type_traits>
|
|
7 #include <stdexcept>
|
|
8 #include <utility>
|
|
9 #include <new>
|
|
10 #include <string>
|
|
11 #include <sstream>
|
|
12 #include <cassert>
|
|
13
|
|
14 namespace toml
|
|
15 {
|
|
16
|
|
17 template<typename T>
|
|
18 struct success
|
|
19 {
|
|
20 using value_type = T;
|
|
21 value_type value;
|
|
22
|
|
23 explicit success(const value_type& v)
|
|
24 noexcept(std::is_nothrow_copy_constructible<value_type>::value)
|
|
25 : value(v)
|
|
26 {}
|
|
27 explicit success(value_type&& v)
|
|
28 noexcept(std::is_nothrow_move_constructible<value_type>::value)
|
|
29 : value(std::move(v))
|
|
30 {}
|
|
31
|
|
32 template<typename U>
|
|
33 explicit success(U&& v): value(std::forward<U>(v)) {}
|
|
34
|
|
35 template<typename U>
|
|
36 explicit success(const success<U>& v): value(v.value) {}
|
|
37 template<typename U>
|
|
38 explicit success(success<U>&& v): value(std::move(v.value)) {}
|
|
39
|
|
40 ~success() = default;
|
|
41 success(const success&) = default;
|
|
42 success(success&&) = default;
|
|
43 success& operator=(const success&) = default;
|
|
44 success& operator=(success&&) = default;
|
|
45 };
|
|
46
|
|
47 template<typename T>
|
|
48 struct failure
|
|
49 {
|
|
50 using value_type = T;
|
|
51 value_type value;
|
|
52
|
|
53 explicit failure(const value_type& v)
|
|
54 noexcept(std::is_nothrow_copy_constructible<value_type>::value)
|
|
55 : value(v)
|
|
56 {}
|
|
57 explicit failure(value_type&& v)
|
|
58 noexcept(std::is_nothrow_move_constructible<value_type>::value)
|
|
59 : value(std::move(v))
|
|
60 {}
|
|
61
|
|
62 template<typename U>
|
|
63 explicit failure(U&& v): value(std::forward<U>(v)) {}
|
|
64
|
|
65 template<typename U>
|
|
66 explicit failure(const failure<U>& v): value(v.value) {}
|
|
67 template<typename U>
|
|
68 explicit failure(failure<U>&& v): value(std::move(v.value)) {}
|
|
69
|
|
70 ~failure() = default;
|
|
71 failure(const failure&) = default;
|
|
72 failure(failure&&) = default;
|
|
73 failure& operator=(const failure&) = default;
|
|
74 failure& operator=(failure&&) = default;
|
|
75 };
|
|
76
|
|
77 template<typename T>
|
|
78 success<typename std::remove_cv<typename std::remove_reference<T>::type>::type>
|
|
79 ok(T&& v)
|
|
80 {
|
|
81 return success<
|
|
82 typename std::remove_cv<typename std::remove_reference<T>::type>::type
|
|
83 >(std::forward<T>(v));
|
|
84 }
|
|
85 template<typename T>
|
|
86 failure<typename std::remove_cv<typename std::remove_reference<T>::type>::type>
|
|
87 err(T&& v)
|
|
88 {
|
|
89 return failure<
|
|
90 typename std::remove_cv<typename std::remove_reference<T>::type>::type
|
|
91 >(std::forward<T>(v));
|
|
92 }
|
|
93
|
|
94 inline success<std::string> ok(const char* literal)
|
|
95 {
|
|
96 return success<std::string>(std::string(literal));
|
|
97 }
|
|
98 inline failure<std::string> err(const char* literal)
|
|
99 {
|
|
100 return failure<std::string>(std::string(literal));
|
|
101 }
|
|
102
|
|
103
|
|
104 template<typename T, typename E>
|
|
105 struct result
|
|
106 {
|
|
107 using value_type = T;
|
|
108 using error_type = E;
|
|
109 using success_type = success<value_type>;
|
|
110 using failure_type = failure<error_type>;
|
|
111
|
|
112 result(const success_type& s): is_ok_(true)
|
|
113 {
|
|
114 auto tmp = ::new(std::addressof(this->succ)) success_type(s);
|
|
115 assert(tmp == std::addressof(this->succ));
|
|
116 (void)tmp;
|
|
117 }
|
|
118 result(const failure_type& f): is_ok_(false)
|
|
119 {
|
|
120 auto tmp = ::new(std::addressof(this->fail)) failure_type(f);
|
|
121 assert(tmp == std::addressof(this->fail));
|
|
122 (void)tmp;
|
|
123 }
|
|
124 result(success_type&& s): is_ok_(true)
|
|
125 {
|
|
126 auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(s));
|
|
127 assert(tmp == std::addressof(this->succ));
|
|
128 (void)tmp;
|
|
129 }
|
|
130 result(failure_type&& f): is_ok_(false)
|
|
131 {
|
|
132 auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(f));
|
|
133 assert(tmp == std::addressof(this->fail));
|
|
134 (void)tmp;
|
|
135 }
|
|
136
|
|
137 template<typename U>
|
|
138 result(const success<U>& s): is_ok_(true)
|
|
139 {
|
|
140 auto tmp = ::new(std::addressof(this->succ)) success_type(s.value);
|
|
141 assert(tmp == std::addressof(this->succ));
|
|
142 (void)tmp;
|
|
143 }
|
|
144 template<typename U>
|
|
145 result(const failure<U>& f): is_ok_(false)
|
|
146 {
|
|
147 auto tmp = ::new(std::addressof(this->fail)) failure_type(f.value);
|
|
148 assert(tmp == std::addressof(this->fail));
|
|
149 (void)tmp;
|
|
150 }
|
|
151 template<typename U>
|
|
152 result(success<U>&& s): is_ok_(true)
|
|
153 {
|
|
154 auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(s.value));
|
|
155 assert(tmp == std::addressof(this->succ));
|
|
156 (void)tmp;
|
|
157 }
|
|
158 template<typename U>
|
|
159 result(failure<U>&& f): is_ok_(false)
|
|
160 {
|
|
161 auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(f.value));
|
|
162 assert(tmp == std::addressof(this->fail));
|
|
163 (void)tmp;
|
|
164 }
|
|
165
|
|
166 result& operator=(const success_type& s)
|
|
167 {
|
|
168 this->cleanup();
|
|
169 this->is_ok_ = true;
|
|
170 auto tmp = ::new(std::addressof(this->succ)) success_type(s);
|
|
171 assert(tmp == std::addressof(this->succ));
|
|
172 (void)tmp;
|
|
173 return *this;
|
|
174 }
|
|
175 result& operator=(const failure_type& f)
|
|
176 {
|
|
177 this->cleanup();
|
|
178 this->is_ok_ = false;
|
|
179 auto tmp = ::new(std::addressof(this->fail)) failure_type(f);
|
|
180 assert(tmp == std::addressof(this->fail));
|
|
181 (void)tmp;
|
|
182 return *this;
|
|
183 }
|
|
184 result& operator=(success_type&& s)
|
|
185 {
|
|
186 this->cleanup();
|
|
187 this->is_ok_ = true;
|
|
188 auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(s));
|
|
189 assert(tmp == std::addressof(this->succ));
|
|
190 (void)tmp;
|
|
191 return *this;
|
|
192 }
|
|
193 result& operator=(failure_type&& f)
|
|
194 {
|
|
195 this->cleanup();
|
|
196 this->is_ok_ = false;
|
|
197 auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(f));
|
|
198 assert(tmp == std::addressof(this->fail));
|
|
199 (void)tmp;
|
|
200 return *this;
|
|
201 }
|
|
202
|
|
203 template<typename U>
|
|
204 result& operator=(const success<U>& s)
|
|
205 {
|
|
206 this->cleanup();
|
|
207 this->is_ok_ = true;
|
|
208 auto tmp = ::new(std::addressof(this->succ)) success_type(s.value);
|
|
209 assert(tmp == std::addressof(this->succ));
|
|
210 (void)tmp;
|
|
211 return *this;
|
|
212 }
|
|
213 template<typename U>
|
|
214 result& operator=(const failure<U>& f)
|
|
215 {
|
|
216 this->cleanup();
|
|
217 this->is_ok_ = false;
|
|
218 auto tmp = ::new(std::addressof(this->fail)) failure_type(f.value);
|
|
219 assert(tmp == std::addressof(this->fail));
|
|
220 (void)tmp;
|
|
221 return *this;
|
|
222 }
|
|
223 template<typename U>
|
|
224 result& operator=(success<U>&& s)
|
|
225 {
|
|
226 this->cleanup();
|
|
227 this->is_ok_ = true;
|
|
228 auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(s.value));
|
|
229 assert(tmp == std::addressof(this->succ));
|
|
230 (void)tmp;
|
|
231 return *this;
|
|
232 }
|
|
233 template<typename U>
|
|
234 result& operator=(failure<U>&& f)
|
|
235 {
|
|
236 this->cleanup();
|
|
237 this->is_ok_ = false;
|
|
238 auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(f.value));
|
|
239 assert(tmp == std::addressof(this->fail));
|
|
240 (void)tmp;
|
|
241 return *this;
|
|
242 }
|
|
243
|
|
244 ~result() noexcept {this->cleanup();}
|
|
245
|
|
246 result(const result& other): is_ok_(other.is_ok())
|
|
247 {
|
|
248 if(other.is_ok())
|
|
249 {
|
|
250 auto tmp = ::new(std::addressof(this->succ)) success_type(other.as_ok());
|
|
251 assert(tmp == std::addressof(this->succ));
|
|
252 (void)tmp;
|
|
253 }
|
|
254 else
|
|
255 {
|
|
256 auto tmp = ::new(std::addressof(this->fail)) failure_type(other.as_err());
|
|
257 assert(tmp == std::addressof(this->fail));
|
|
258 (void)tmp;
|
|
259 }
|
|
260 }
|
|
261 result(result&& other): is_ok_(other.is_ok())
|
|
262 {
|
|
263 if(other.is_ok())
|
|
264 {
|
|
265 auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(other.as_ok()));
|
|
266 assert(tmp == std::addressof(this->succ));
|
|
267 (void)tmp;
|
|
268 }
|
|
269 else
|
|
270 {
|
|
271 auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(other.as_err()));
|
|
272 assert(tmp == std::addressof(this->fail));
|
|
273 (void)tmp;
|
|
274 }
|
|
275 }
|
|
276
|
|
277 template<typename U, typename F>
|
|
278 result(const result<U, F>& other): is_ok_(other.is_ok())
|
|
279 {
|
|
280 if(other.is_ok())
|
|
281 {
|
|
282 auto tmp = ::new(std::addressof(this->succ)) success_type(other.as_ok());
|
|
283 assert(tmp == std::addressof(this->succ));
|
|
284 (void)tmp;
|
|
285 }
|
|
286 else
|
|
287 {
|
|
288 auto tmp = ::new(std::addressof(this->fail)) failure_type(other.as_err());
|
|
289 assert(tmp == std::addressof(this->fail));
|
|
290 (void)tmp;
|
|
291 }
|
|
292 }
|
|
293 template<typename U, typename F>
|
|
294 result(result<U, F>&& other): is_ok_(other.is_ok())
|
|
295 {
|
|
296 if(other.is_ok())
|
|
297 {
|
|
298 auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(other.as_ok()));
|
|
299 assert(tmp == std::addressof(this->succ));
|
|
300 (void)tmp;
|
|
301 }
|
|
302 else
|
|
303 {
|
|
304 auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(other.as_err()));
|
|
305 assert(tmp == std::addressof(this->fail));
|
|
306 (void)tmp;
|
|
307 }
|
|
308 }
|
|
309
|
|
310 result& operator=(const result& other)
|
|
311 {
|
|
312 this->cleanup();
|
|
313 if(other.is_ok())
|
|
314 {
|
|
315 auto tmp = ::new(std::addressof(this->succ)) success_type(other.as_ok());
|
|
316 assert(tmp == std::addressof(this->succ));
|
|
317 (void)tmp;
|
|
318 }
|
|
319 else
|
|
320 {
|
|
321 auto tmp = ::new(std::addressof(this->fail)) failure_type(other.as_err());
|
|
322 assert(tmp == std::addressof(this->fail));
|
|
323 (void)tmp;
|
|
324 }
|
|
325 is_ok_ = other.is_ok();
|
|
326 return *this;
|
|
327 }
|
|
328 result& operator=(result&& other)
|
|
329 {
|
|
330 this->cleanup();
|
|
331 if(other.is_ok())
|
|
332 {
|
|
333 auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(other.as_ok()));
|
|
334 assert(tmp == std::addressof(this->succ));
|
|
335 (void)tmp;
|
|
336 }
|
|
337 else
|
|
338 {
|
|
339 auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(other.as_err()));
|
|
340 assert(tmp == std::addressof(this->fail));
|
|
341 (void)tmp;
|
|
342 }
|
|
343 is_ok_ = other.is_ok();
|
|
344 return *this;
|
|
345 }
|
|
346
|
|
347 template<typename U, typename F>
|
|
348 result& operator=(const result<U, F>& other)
|
|
349 {
|
|
350 this->cleanup();
|
|
351 if(other.is_ok())
|
|
352 {
|
|
353 auto tmp = ::new(std::addressof(this->succ)) success_type(other.as_ok());
|
|
354 assert(tmp == std::addressof(this->succ));
|
|
355 (void)tmp;
|
|
356 }
|
|
357 else
|
|
358 {
|
|
359 auto tmp = ::new(std::addressof(this->fail)) failure_type(other.as_err());
|
|
360 assert(tmp == std::addressof(this->fail));
|
|
361 (void)tmp;
|
|
362 }
|
|
363 is_ok_ = other.is_ok();
|
|
364 return *this;
|
|
365 }
|
|
366 template<typename U, typename F>
|
|
367 result& operator=(result<U, F>&& other)
|
|
368 {
|
|
369 this->cleanup();
|
|
370 if(other.is_ok())
|
|
371 {
|
|
372 auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(other.as_ok()));
|
|
373 assert(tmp == std::addressof(this->succ));
|
|
374 (void)tmp;
|
|
375 }
|
|
376 else
|
|
377 {
|
|
378 auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(other.as_err()));
|
|
379 assert(tmp == std::addressof(this->fail));
|
|
380 (void)tmp;
|
|
381 }
|
|
382 is_ok_ = other.is_ok();
|
|
383 return *this;
|
|
384 }
|
|
385
|
|
386 bool is_ok() const noexcept {return is_ok_;}
|
|
387 bool is_err() const noexcept {return !is_ok_;}
|
|
388
|
|
389 operator bool() const noexcept {return is_ok_;}
|
|
390
|
|
391 value_type& unwrap() &
|
|
392 {
|
|
393 if(is_err())
|
|
394 {
|
|
395 throw std::runtime_error("toml::result: bad unwrap: " +
|
|
396 format_error(this->as_err()));
|
|
397 }
|
|
398 return this->succ.value;
|
|
399 }
|
|
400 value_type const& unwrap() const&
|
|
401 {
|
|
402 if(is_err())
|
|
403 {
|
|
404 throw std::runtime_error("toml::result: bad unwrap: " +
|
|
405 format_error(this->as_err()));
|
|
406 }
|
|
407 return this->succ.value;
|
|
408 }
|
|
409 value_type&& unwrap() &&
|
|
410 {
|
|
411 if(is_err())
|
|
412 {
|
|
413 throw std::runtime_error("toml::result: bad unwrap: " +
|
|
414 format_error(this->as_err()));
|
|
415 }
|
|
416 return std::move(this->succ.value);
|
|
417 }
|
|
418
|
|
419 value_type& unwrap_or(value_type& opt) &
|
|
420 {
|
|
421 if(is_err()) {return opt;}
|
|
422 return this->succ.value;
|
|
423 }
|
|
424 value_type const& unwrap_or(value_type const& opt) const&
|
|
425 {
|
|
426 if(is_err()) {return opt;}
|
|
427 return this->succ.value;
|
|
428 }
|
|
429 value_type unwrap_or(value_type opt) &&
|
|
430 {
|
|
431 if(is_err()) {return opt;}
|
|
432 return this->succ.value;
|
|
433 }
|
|
434
|
|
435 error_type& unwrap_err() &
|
|
436 {
|
|
437 if(is_ok()) {throw std::runtime_error("toml::result: bad unwrap_err");}
|
|
438 return this->fail.value;
|
|
439 }
|
|
440 error_type const& unwrap_err() const&
|
|
441 {
|
|
442 if(is_ok()) {throw std::runtime_error("toml::result: bad unwrap_err");}
|
|
443 return this->fail.value;
|
|
444 }
|
|
445 error_type&& unwrap_err() &&
|
|
446 {
|
|
447 if(is_ok()) {throw std::runtime_error("toml::result: bad unwrap_err");}
|
|
448 return std::move(this->fail.value);
|
|
449 }
|
|
450
|
|
451 value_type& as_ok() & noexcept {return this->succ.value;}
|
|
452 value_type const& as_ok() const& noexcept {return this->succ.value;}
|
|
453 value_type&& as_ok() && noexcept {return std::move(this->succ.value);}
|
|
454
|
|
455 error_type& as_err() & noexcept {return this->fail.value;}
|
|
456 error_type const& as_err() const& noexcept {return this->fail.value;}
|
|
457 error_type&& as_err() && noexcept {return std::move(this->fail.value);}
|
|
458
|
|
459
|
|
460 // prerequisities
|
|
461 // F: T -> U
|
|
462 // retval: result<U, E>
|
|
463 template<typename F>
|
|
464 result<detail::return_type_of_t<F, value_type&>, error_type>
|
|
465 map(F&& f) &
|
|
466 {
|
|
467 if(this->is_ok()){return ok(f(this->as_ok()));}
|
|
468 return err(this->as_err());
|
|
469 }
|
|
470 template<typename F>
|
|
471 result<detail::return_type_of_t<F, value_type const&>, error_type>
|
|
472 map(F&& f) const&
|
|
473 {
|
|
474 if(this->is_ok()){return ok(f(this->as_ok()));}
|
|
475 return err(this->as_err());
|
|
476 }
|
|
477 template<typename F>
|
|
478 result<detail::return_type_of_t<F, value_type &&>, error_type>
|
|
479 map(F&& f) &&
|
|
480 {
|
|
481 if(this->is_ok()){return ok(f(std::move(this->as_ok())));}
|
|
482 return err(std::move(this->as_err()));
|
|
483 }
|
|
484
|
|
485 // prerequisities
|
|
486 // F: E -> F
|
|
487 // retval: result<T, F>
|
|
488 template<typename F>
|
|
489 result<value_type, detail::return_type_of_t<F, error_type&>>
|
|
490 map_err(F&& f) &
|
|
491 {
|
|
492 if(this->is_err()){return err(f(this->as_err()));}
|
|
493 return ok(this->as_ok());
|
|
494 }
|
|
495 template<typename F>
|
|
496 result<value_type, detail::return_type_of_t<F, error_type const&>>
|
|
497 map_err(F&& f) const&
|
|
498 {
|
|
499 if(this->is_err()){return err(f(this->as_err()));}
|
|
500 return ok(this->as_ok());
|
|
501 }
|
|
502 template<typename F>
|
|
503 result<value_type, detail::return_type_of_t<F, error_type&&>>
|
|
504 map_err(F&& f) &&
|
|
505 {
|
|
506 if(this->is_err()){return err(f(std::move(this->as_err())));}
|
|
507 return ok(std::move(this->as_ok()));
|
|
508 }
|
|
509
|
|
510 // prerequisities
|
|
511 // F: T -> U
|
|
512 // retval: U
|
|
513 template<typename F, typename U>
|
|
514 detail::return_type_of_t<F, value_type&>
|
|
515 map_or_else(F&& f, U&& opt) &
|
|
516 {
|
|
517 if(this->is_err()){return std::forward<U>(opt);}
|
|
518 return f(this->as_ok());
|
|
519 }
|
|
520 template<typename F, typename U>
|
|
521 detail::return_type_of_t<F, value_type const&>
|
|
522 map_or_else(F&& f, U&& opt) const&
|
|
523 {
|
|
524 if(this->is_err()){return std::forward<U>(opt);}
|
|
525 return f(this->as_ok());
|
|
526 }
|
|
527 template<typename F, typename U>
|
|
528 detail::return_type_of_t<F, value_type&&>
|
|
529 map_or_else(F&& f, U&& opt) &&
|
|
530 {
|
|
531 if(this->is_err()){return std::forward<U>(opt);}
|
|
532 return f(std::move(this->as_ok()));
|
|
533 }
|
|
534
|
|
535 // prerequisities
|
|
536 // F: E -> U
|
|
537 // retval: U
|
|
538 template<typename F, typename U>
|
|
539 detail::return_type_of_t<F, error_type&>
|
|
540 map_err_or_else(F&& f, U&& opt) &
|
|
541 {
|
|
542 if(this->is_ok()){return std::forward<U>(opt);}
|
|
543 return f(this->as_err());
|
|
544 }
|
|
545 template<typename F, typename U>
|
|
546 detail::return_type_of_t<F, error_type const&>
|
|
547 map_err_or_else(F&& f, U&& opt) const&
|
|
548 {
|
|
549 if(this->is_ok()){return std::forward<U>(opt);}
|
|
550 return f(this->as_err());
|
|
551 }
|
|
552 template<typename F, typename U>
|
|
553 detail::return_type_of_t<F, error_type&&>
|
|
554 map_err_or_else(F&& f, U&& opt) &&
|
|
555 {
|
|
556 if(this->is_ok()){return std::forward<U>(opt);}
|
|
557 return f(std::move(this->as_err()));
|
|
558 }
|
|
559
|
|
560 // prerequisities:
|
|
561 // F: func T -> U
|
|
562 // toml::err(error_type) should be convertible to U.
|
|
563 // normally, type U is another result<S, F> and E is convertible to F
|
|
564 template<typename F>
|
|
565 detail::return_type_of_t<F, value_type&>
|
|
566 and_then(F&& f) &
|
|
567 {
|
|
568 if(this->is_ok()){return f(this->as_ok());}
|
|
569 return err(this->as_err());
|
|
570 }
|
|
571 template<typename F>
|
|
572 detail::return_type_of_t<F, value_type const&>
|
|
573 and_then(F&& f) const&
|
|
574 {
|
|
575 if(this->is_ok()){return f(this->as_ok());}
|
|
576 return err(this->as_err());
|
|
577 }
|
|
578 template<typename F>
|
|
579 detail::return_type_of_t<F, value_type&&>
|
|
580 and_then(F&& f) &&
|
|
581 {
|
|
582 if(this->is_ok()){return f(std::move(this->as_ok()));}
|
|
583 return err(std::move(this->as_err()));
|
|
584 }
|
|
585
|
|
586 // prerequisities:
|
|
587 // F: func E -> U
|
|
588 // toml::ok(value_type) should be convertible to U.
|
|
589 // normally, type U is another result<S, F> and T is convertible to S
|
|
590 template<typename F>
|
|
591 detail::return_type_of_t<F, error_type&>
|
|
592 or_else(F&& f) &
|
|
593 {
|
|
594 if(this->is_err()){return f(this->as_err());}
|
|
595 return ok(this->as_ok());
|
|
596 }
|
|
597 template<typename F>
|
|
598 detail::return_type_of_t<F, error_type const&>
|
|
599 or_else(F&& f) const&
|
|
600 {
|
|
601 if(this->is_err()){return f(this->as_err());}
|
|
602 return ok(this->as_ok());
|
|
603 }
|
|
604 template<typename F>
|
|
605 detail::return_type_of_t<F, error_type&&>
|
|
606 or_else(F&& f) &&
|
|
607 {
|
|
608 if(this->is_err()){return f(std::move(this->as_err()));}
|
|
609 return ok(std::move(this->as_ok()));
|
|
610 }
|
|
611
|
|
612 // if *this is error, returns *this. otherwise, returns other.
|
|
613 result and_other(const result& other) const&
|
|
614 {
|
|
615 return this->is_err() ? *this : other;
|
|
616 }
|
|
617 result and_other(result&& other) &&
|
|
618 {
|
|
619 return this->is_err() ? std::move(*this) : std::move(other);
|
|
620 }
|
|
621
|
|
622 // if *this is okay, returns *this. otherwise, returns other.
|
|
623 result or_other(const result& other) const&
|
|
624 {
|
|
625 return this->is_ok() ? *this : other;
|
|
626 }
|
|
627 result or_other(result&& other) &&
|
|
628 {
|
|
629 return this->is_ok() ? std::move(*this) : std::move(other);
|
|
630 }
|
|
631
|
|
632 void swap(result<T, E>& other)
|
|
633 {
|
|
634 result<T, E> tmp(std::move(*this));
|
|
635 *this = std::move(other);
|
|
636 other = std::move(tmp);
|
|
637 return ;
|
|
638 }
|
|
639
|
|
640 private:
|
|
641
|
|
642 static std::string format_error(std::exception const& excpt)
|
|
643 {
|
|
644 return std::string(excpt.what());
|
|
645 }
|
|
646 template<typename U, typename std::enable_if<!std::is_base_of<
|
|
647 std::exception, U>::value, std::nullptr_t>::type = nullptr>
|
|
648 static std::string format_error(U const& others)
|
|
649 {
|
|
650 std::ostringstream oss; oss << others;
|
|
651 return oss.str();
|
|
652 }
|
|
653
|
|
654 void cleanup() noexcept
|
|
655 {
|
|
656 if(this->is_ok_) {this->succ.~success_type();}
|
|
657 else {this->fail.~failure_type();}
|
|
658 return;
|
|
659 }
|
|
660
|
|
661 private:
|
|
662
|
|
663 bool is_ok_;
|
|
664 union
|
|
665 {
|
|
666 success_type succ;
|
|
667 failure_type fail;
|
|
668 };
|
|
669 };
|
|
670
|
|
671 template<typename T, typename E>
|
|
672 void swap(result<T, E>& lhs, result<T, E>& rhs)
|
|
673 {
|
|
674 lhs.swap(rhs);
|
|
675 return;
|
|
676 }
|
|
677
|
|
678 // this might be confusing because it eagerly evaluated, while in the other
|
|
679 // cases operator && and || are short-circuited.
|
|
680 //
|
|
681 // template<typename T, typename E>
|
|
682 // inline result<T, E>
|
|
683 // operator&&(const result<T, E>& lhs, const result<T, E>& rhs) noexcept
|
|
684 // {
|
|
685 // return lhs.is_ok() ? rhs : lhs;
|
|
686 // }
|
|
687 //
|
|
688 // template<typename T, typename E>
|
|
689 // inline result<T, E>
|
|
690 // operator||(const result<T, E>& lhs, const result<T, E>& rhs) noexcept
|
|
691 // {
|
|
692 // return lhs.is_ok() ? lhs : rhs;
|
|
693 // }
|
|
694
|
|
695 // ----------------------------------------------------------------------------
|
|
696 // re-use result<T, E> as a optional<T> with none_t
|
|
697
|
|
698 namespace detail
|
|
699 {
|
|
700 struct none_t {};
|
|
701 inline bool operator==(const none_t&, const none_t&) noexcept {return true;}
|
|
702 inline bool operator!=(const none_t&, const none_t&) noexcept {return false;}
|
|
703 inline bool operator< (const none_t&, const none_t&) noexcept {return false;}
|
|
704 inline bool operator<=(const none_t&, const none_t&) noexcept {return true;}
|
|
705 inline bool operator> (const none_t&, const none_t&) noexcept {return false;}
|
|
706 inline bool operator>=(const none_t&, const none_t&) noexcept {return true;}
|
|
707 template<typename charT, typename traitsT>
|
|
708 std::basic_ostream<charT, traitsT>&
|
|
709 operator<<(std::basic_ostream<charT, traitsT>& os, const none_t&)
|
|
710 {
|
|
711 os << "none";
|
|
712 return os;
|
|
713 }
|
|
714 inline failure<none_t> none() noexcept {return failure<none_t>{none_t{}};}
|
|
715 } // detail
|
|
716 } // toml11
|
|
717 #endif// TOML11_RESULT_H
|