Bond
 
Loading...
Searching...
No Matches
maybe.h
1// Copyright (c) Microsoft. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
4#pragma once
5
6#include <bond/core/config.h>
7
8#include "detail/alloc.h"
9#include "traits.h"
10
11#include <boost/none.hpp>
12#include <boost/optional/optional.hpp>
13#include <boost/utility/enable_if.hpp>
14
15#include <memory>
16#include <type_traits>
17#include <utility>
18
19namespace bond
20{
21
22
23[[noreturn]] void NothingException();
24
25namespace detail
26{
27
31template <typename T>
33{
34public:
36 using value_type = T;
37
38 maybe_common() = default;
39
40 maybe_common(const maybe_common&) = default;
41
42 template <typename... Args>
43 explicit maybe_common(const T& value, Args&&... args)
44 {
45 _value.emplace(value, std::forward<Args>(args)...);
46 }
47
48 template <typename... Args>
49 explicit maybe_common(T&& value, Args&&... args)
50 {
51 _value.emplace(std::move(value), std::forward<Args>(args)...);
52 }
53
54 maybe_common(maybe_common&& that) BOND_NOEXCEPT_IF(std::is_nothrow_move_constructible<boost::optional<T>>::value)
55 : _value(std::move(that._value))
56 {
57 // unlike std::optional/boost::optional, moved-from bond::maybe
58 // instances are guaranteed to be nothing.
59 //
60 // asigning boost::none is noexcept, but assigning { } is not
61 that._value = boost::none;
62 }
63
66 bool is_nothing() const BOND_NOEXCEPT
67 {
68 return !static_cast<bool>(_value);
69 }
70
74 explicit operator bool() const BOND_NOEXCEPT
75 {
76 return !is_nothing();
77 }
78
80 void set_nothing() BOND_NOEXCEPT
81 {
82 // asigning boost::none is noexcept, but assigning { } is not
83 _value = boost::none;
84 }
85
89 template<typename... Args>
90 T& emplace(Args&&... args)
91 {
92 _value.emplace(std::forward<Args>(args)...);
93 return *_value;
94 }
95
98 T& value()
99 {
100 if (is_nothing())
101 {
102 NothingException();
103 }
104
105 return *_value;
106 }
107
110 const T& value() const
111 {
112 if (is_nothing())
113 {
114 NothingException();
115 }
116
117 return *_value;
118 }
119
126 T& value(const std::nothrow_t&) BOND_NOEXCEPT
127 {
128 BOOST_ASSERT(!is_nothing());
129 return *_value;
130 }
131
138 const T& value(const std::nothrow_t&) const BOND_NOEXCEPT
139 {
140 BOOST_ASSERT(!is_nothing());
141 return *_value;
142 }
143
148
155 friend bool operator==(const maybe_common& lhs, const T& rhs)
156 {
157 return lhs._value == rhs;
158 }
159
166 friend bool operator!=(const maybe_common& lhs, const T& rhs)
167 {
168 return !(lhs == rhs);
169 }
170
177 friend bool operator==(const T& lhs, const maybe_common& rhs)
178 {
179 return lhs == rhs._value;
180 }
181
188 friend bool operator!=(const T& lhs, const maybe_common& rhs)
189 {
190 return !(lhs == rhs);
191 }
192
193protected:
194 boost::optional<T> _value;
195};
196
197
198template <typename T, typename Enable = void> struct
199has_allocator
200 : std::false_type {};
201
202template <typename T> struct
203has_allocator<T, typename boost::enable_if<std::is_class<typename T::allocator_type> >::type>
204 : std::true_type {};
205
206} // namespace detail
207
208
209template <typename T, typename Enabled = void>
210class maybe;
211
227template <typename T>
228class maybe<T, typename boost::disable_if<detail::has_allocator<T> >::type>
229 : public detail::maybe_common<T>
230{
231public:
233 maybe() = default;
234
236 maybe(const maybe&) = default;
241 maybe(maybe&&) = default;
242
244 explicit
245 maybe(const T& value)
246 : detail::maybe_common<T>(value)
247 { }
248
252 explicit
253 maybe(T&& value)
254 : detail::maybe_common<T>(std::move(value))
255 { }
256
257 maybe& operator=(const maybe&) = default;
258 maybe& operator=(maybe&&) = default;
259
261 maybe& operator=(const T& value)
262 {
263 this->emplace(value);
264 return *this;
265 }
266
269 maybe& operator=(T&& value)
270 {
271 this->emplace(std::move(value));
272 return *this;
273 }
274
281 friend bool operator==(const maybe& lhs, const maybe& rhs)
282 {
283 return lhs._value == rhs._value;
284 }
285
291 friend bool operator!=(const maybe& lhs, const maybe& rhs)
292 {
293 return lhs._value != rhs._value;
294 }
295
303 {
304 if (this->is_nothing())
305 {
306 this->emplace();
307 }
308
309 return *this->_value;
310 }
311
313 void swap(maybe& that)
314 {
315 using std::swap;
316 swap(this->_value, that._value);
317 }
318};
319
335template <typename T>
336class maybe<T, typename boost::enable_if<detail::has_allocator<T> >::type>
337 : public detail::maybe_common<T>,
338 private detail::allocator_holder<typename T::allocator_type>
339{
341
342public:
343 // allocator_holder may inherit from an allocator that has its own
344 // value_type. Add an using to explicitly "export" the one from
345 // maybe_common
347
349 using allocator_type = typename T::allocator_type;
350
351 maybe() = default;
353 maybe(const maybe&) = default;
358 maybe(maybe&&) = default;
359
362 maybe(const maybe& that, const allocator_type& alloc)
363 : detail::maybe_common<T>(),
364 alloc_holder(alloc)
365 {
366 if (!that.is_nothing())
367 {
368 this->emplace(*that._value, alloc);
369 }
370 }
371
377 maybe(maybe&& that, const allocator_type& alloc)
378 : detail::maybe_common<T>(),
379 alloc_holder(alloc)
380 {
381 if (!that.is_nothing())
382 {
383 this->emplace(std::move(*that._value), alloc);
384
385 // asigning boost::none is noexcept, but assigning { } is not
386 that._value = boost::none;
387 }
388 }
389
394 explicit maybe(const allocator_type& alloc)
395 : detail::maybe_common<T>(),
396 alloc_holder(alloc)
397 { }
398
400 explicit maybe(const T& value)
401 : detail::maybe_common<T>(value),
403 { }
404
408 maybe(T&& value)
409 : detail::maybe_common<T>(std::move(value)),
411 { }
412
413 maybe& operator=(const maybe&) = default;
414 maybe& operator=(maybe&&) = default;
415
417 maybe& operator=(const T& value)
418 {
419 this->emplace(value);
420 return *this;
421 }
422
425 maybe& operator=(T&& value)
426 {
427 this->emplace(std::move(value));
428 return *this;
429 }
430
431 // We need to get rid of any operator== that may come from the
432 // allocator_holder so the friend free functions from maybe_common don't
433 // have any competition.
434 bool operator==(const alloc_holder&) = delete;
435
442 friend bool operator==(const maybe& lhs, const maybe& rhs)
443 {
444 return lhs._value == rhs._value;
445 }
446
452 friend bool operator!=(const maybe& lhs, const maybe& rhs)
453 {
454 return lhs._value != rhs._value;
455 }
456
464 {
465 if (this->is_nothing())
466 {
467 this->emplace(base_alloc_holder().get());
468 }
469
470 return *this->_value;
471 }
472
474 void swap(maybe& that)
475 {
476 using std::swap;
477 swap(this->_value, that._value);
478 swap(base_alloc_holder(), that.base_alloc_holder());
479 }
480
483 allocator_type get_allocator() const BOND_NOEXCEPT
484 {
485 return base_alloc_holder().get();
486 }
487
488private:
489 detail::maybe_common<T>& base_common() BOND_NOEXCEPT { return *this; }
490 const detail::maybe_common<T>& base_common() const BOND_NOEXCEPT { return *this; }
491 alloc_holder& base_alloc_holder() BOND_NOEXCEPT { return *this; }
492 const alloc_holder& base_alloc_holder() const BOND_NOEXCEPT { return *this; }
493};
494
496template<typename T>
497inline void swap(maybe<T>& x, maybe<T>& y)
498{
499 x.swap(y);
500}
501
502} // namespace bond
Helper type that holds an allocator.
Definition: alloc.h:22
Definition: maybe.h:33
maybe_common & operator=(maybe_common &&)=default
Move assign from another maybe.
void set_nothing() BOND_NOEXCEPT
Set to nothing.
Definition: maybe.h:80
T & value()
Get a reference to the value.
Definition: maybe.h:98
friend bool operator!=(const maybe_common &lhs, const T &rhs)
Compares a maybe and a value for inequality.
Definition: maybe.h:166
T value_type
The type of the value that may be inside the maybe.
Definition: maybe.h:36
friend bool operator==(const T &lhs, const maybe_common &rhs)
Compares a value and a maybe for equality.
Definition: maybe.h:177
maybe_common & operator=(const maybe_common &)=default
Assign from another maybe.
const T & value() const
Get a constant reference to the value.
Definition: maybe.h:110
const T & value(const std::nothrow_t &) const BOND_NOEXCEPT
Get a constant reference to the value.
Definition: maybe.h:138
T & emplace(Args &&... args)
Construct a value in place.
Definition: maybe.h:90
friend bool operator==(const maybe_common &lhs, const T &rhs)
Compares a maybe and a value for equality.
Definition: maybe.h:155
bool is_nothing() const BOND_NOEXCEPT
Check if this object contains nothing.
Definition: maybe.h:66
friend bool operator!=(const T &lhs, const maybe_common &rhs)
Compares and a value and a maybe for inequality.
Definition: maybe.h:188
T & value(const std::nothrow_t &) BOND_NOEXCEPT
Get a reference to the value.
Definition: maybe.h:126
friend bool operator==(const maybe &lhs, const maybe &rhs)
Compares two maybes for value equality.
Definition: maybe.h:281
T & set_value()
Set the maybe to hold a value, if needed.
Definition: maybe.h:302
friend bool operator!=(const maybe &lhs, const maybe &rhs)
Compares two maybes for value inequality.
Definition: maybe.h:291
maybe & operator=(const T &value)
Assign by copying a value.
Definition: maybe.h:261
void swap(maybe &that)
Swap this object with that.
Definition: maybe.h:313
maybe(T &&value)
Create a maybe that holds a value by moving from value.
Definition: maybe.h:253
maybe & operator=(T &&value)
Move-assign from a value.
Definition: maybe.h:269
maybe(const T &value)
Create a maybe that holds a value by copying value.
Definition: maybe.h:245
maybe & operator=(const T &value)
Assign by copying value.
Definition: maybe.h:417
friend bool operator==(const maybe &lhs, const maybe &rhs)
Compares two maybes for value equality.
Definition: maybe.h:442
maybe(const maybe &that, const allocator_type &alloc)
Allocator-extended copy constructor. Uses alloc as the new allocator, makes a copy of that.
Definition: maybe.h:362
friend bool operator!=(const maybe &lhs, const maybe &rhs)
Compares two maybes for value inequality.
Definition: maybe.h:452
typename T::allocator_type allocator_type
The type of the allocator in use.
Definition: maybe.h:349
maybe(T &&value)
Create a maybe that holds a value by moving from value.
Definition: maybe.h:408
maybe(const allocator_type &alloc)
Construct a maybe that holds nothing, but remember the allocator so that it can be used to construct ...
Definition: maybe.h:394
maybe(const T &value)
Create a maybe that holds a copy of value.
Definition: maybe.h:400
void swap(maybe &that)
Swap this object with that.
Definition: maybe.h:474
maybe & operator=(T &&value)
Move-assign from value.
Definition: maybe.h:425
T & set_value()
Set to non-empty, if needed.
Definition: maybe.h:463
allocator_type get_allocator() const BOND_NOEXCEPT
Get the allocator that this maybe uses.
Definition: maybe.h:483
maybe(maybe &&that, const allocator_type &alloc)
Allocator-extended move constructor. Uses alloc as the new allocator, makes moved from that.
Definition: maybe.h:377
namespace bond
Definition: apply.h:17
void swap(blob &src, blob &dst) BOND_NOEXCEPT
Swap two blobs.
Definition: blob.h:277
boost::enable_if< is_signed_int_or_enum< SignedT >, bool >::type operator==(const Variant &variant, SignedT value)
Compares variant for equality against the provided signed integer or enum value.
Definition: metadata.h:24
STL namespace.