1// Copyright (C) 2017 Andrzej Krzemienski.
2//
3// Use, modification, and distribution is subject to the Boost Software
4// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
5// http://www.boost.org/LICENSE_1_0.txt)
6//
7// See http://www.boost.org/libs/optional for documentation.
8//
9// You are welcome to contact the author at:
10// akrzemi1@gmail.com
11
12// trivially-copyable version of the storage
13
14template<class T>
15class tc_optional_base : public optional_tag
16{
17 private :
18
19 typedef tc_optional_base<T> this_type ;
20
21 protected :
22
23 typedef T value_type ;
24
25 protected:
26 typedef T & reference_type ;
27 typedef T const& reference_const_type ;
28#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
29 typedef T && rval_reference_type ;
30 typedef T && reference_type_of_temporary_wrapper ;
31#endif
32 typedef T * pointer_type ;
33 typedef T const* pointer_const_type ;
34 typedef T const& argument_type ;
35
36 tc_optional_base()
37 :
38 m_initialized(false) {}
39
40 tc_optional_base ( none_t )
41 :
42 m_initialized(false) {}
43
44 tc_optional_base ( init_value_tag, argument_type val )
45 :
46 m_initialized(true), m_storage(val) {}
47
48 tc_optional_base ( bool cond, argument_type val )
49 :
50 m_initialized(cond), m_storage(val) {}
51
52 // tc_optional_base ( tc_optional_base const& ) = default;
53
54
55#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
56
57 template<class Expr, class PtrExpr>
58 explicit tc_optional_base ( Expr&& expr, PtrExpr const* tag )
59 :
60 m_initialized(false)
61 {
62 construct(boost::forward<Expr>(expr),tag);
63 }
64
65#else
66 // This is used for both converting and in-place constructions.
67 // Derived classes use the 'tag' to select the appropriate
68 // implementation (the correct 'construct()' overload)
69 template<class Expr>
70 explicit tc_optional_base ( Expr const& expr, Expr const* tag )
71 :
72 m_initialized(false)
73 {
74 construct(expr,tag);
75 }
76
77#endif
78
79 // tc_optional_base& operator= ( tc_optional_base const& ) = default;
80 // ~tc_optional_base() = default;
81
82 // Assigns from another optional<T> (deep-copies the rhs value)
83 void assign ( tc_optional_base const& rhs )
84 {
85 *this = rhs;
86 }
87
88 // Assigns from another _convertible_ optional<U> (deep-copies the rhs value)
89 template<class U>
90 void assign ( optional<U> const& rhs )
91 {
92 if ( rhs.is_initialized() )
93#ifndef BOOST_OPTIONAL_CONFIG_RESTORE_ASSIGNMENT_OF_NONCONVERTIBLE_TYPES
94 m_storage = rhs.get();
95#else
96 m_storage = static_cast<value_type>(rhs.get());
97#endif
98
99 m_initialized = rhs.is_initialized();
100 }
101
102#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
103 // move-assigns from another _convertible_ optional<U> (deep-moves from the rhs value)
104 template<class U>
105 void assign ( optional<U>&& rhs )
106 {
107 typedef BOOST_DEDUCED_TYPENAME optional<U>::rval_reference_type ref_type;
108 if ( rhs.is_initialized() )
109 m_storage = static_cast<ref_type>(rhs.get());
110 m_initialized = rhs.is_initialized();
111 }
112#endif
113
114 void assign ( argument_type val )
115 {
116 construct(val);
117 }
118
119 void assign ( none_t ) { destroy(); }
120
121#ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT
122
123#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
124 template<class Expr, class ExprPtr>
125 void assign_expr ( Expr&& expr, ExprPtr const* tag )
126 {
127 construct(boost::forward<Expr>(expr),tag);
128 }
129#else
130 template<class Expr>
131 void assign_expr ( Expr const& expr, Expr const* tag )
132 {
133 construct(expr,tag);
134 }
135#endif
136
137#endif
138
139 public :
140
141 // Destroys the current value, if any, leaving this UNINITIALIZED
142 // No-throw (assuming T::~T() doesn't)
143 void reset() BOOST_NOEXCEPT { destroy(); }
144
145 // **DEPRECATED** Replaces the current value -if any- with 'val'
146 void reset ( argument_type val ) BOOST_NOEXCEPT { assign(val); }
147
148 // Returns a pointer to the value if this is initialized, otherwise,
149 // returns NULL.
150 // No-throw
151 pointer_const_type get_ptr() const { return m_initialized ? get_ptr_impl() : 0 ; }
152 pointer_type get_ptr() { return m_initialized ? get_ptr_impl() : 0 ; }
153
154 bool is_initialized() const { return m_initialized ; }
155
156 protected :
157
158 void construct ( argument_type val )
159 {
160 m_storage = val ;
161 m_initialized = true ;
162 }
163
164
165#if (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) && (!defined BOOST_NO_CXX11_VARIADIC_TEMPLATES)
166 // Constructs in-place
167 // upon exception *this is always uninitialized
168 template<class... Args>
169 void construct ( in_place_init_t, Args&&... args )
170 {
171 m_storage = value_type( boost::forward<Args>(args)... ) ;
172 m_initialized = true ;
173 }
174
175 template<class... Args>
176 void emplace_assign ( Args&&... args )
177 {
178 construct(in_place_init, boost::forward<Args>(args)...);
179 }
180
181 template<class... Args>
182 explicit tc_optional_base ( in_place_init_t, Args&&... args )
183 :
184 m_initialized(false)
185 {
186 construct(in_place_init, boost::forward<Args>(args)...);
187 }
188
189 template<class... Args>
190 explicit tc_optional_base ( in_place_init_if_t, bool cond, Args&&... args )
191 :
192 m_initialized(false)
193 {
194 if ( cond )
195 construct(in_place_init, boost::forward<Args>(args)...);
196 }
197#elif (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES)
198 template<class Arg>
199 void construct ( in_place_init_t, Arg&& arg )
200 {
201 m_storage = value_type( boost::forward<Arg>(arg) );
202 m_initialized = true ;
203 }
204
205 void construct ( in_place_init_t )
206 {
207 m_storage = value_type();
208 m_initialized = true ;
209 }
210
211 template<class Arg>
212 void emplace_assign ( Arg&& arg )
213 {
214 construct(in_place_init, boost::forward<Arg>(arg)) ;
215 }
216
217 void emplace_assign ()
218 {
219 construct(in_place_init) ;
220 }
221
222 template<class Arg>
223 explicit tc_optional_base ( in_place_init_t, Arg&& arg )
224 :
225 m_initialized(false)
226 {
227 construct(in_place_init, boost::forward<Arg>(arg));
228 }
229
230 explicit tc_optional_base ( in_place_init_t )
231 :
232 m_initialized(false), m_storage() {}
233
234 template<class Arg>
235 explicit tc_optional_base ( in_place_init_if_t, bool cond, Arg&& arg )
236 :
237 m_initialized(false)
238 {
239 if ( cond )
240 construct(in_place_init, boost::forward<Arg>(arg));
241 }
242
243 explicit tc_optional_base ( in_place_init_if_t, bool cond )
244 :
245 m_initialized(false)
246 {
247 if ( cond )
248 construct(in_place_init);
249 }
250
251#else
252
253 template<class Arg>
254 void construct ( in_place_init_t, const Arg& arg )
255 {
256 m_storage = value_type( arg );
257 m_initialized = true ;
258 }
259
260 template<class Arg>
261 void construct ( in_place_init_t, Arg& arg )
262 {
263 m_storage = value_type( arg );
264 m_initialized = true ;
265 }
266
267 void construct ( in_place_init_t )
268 {
269 m_storage = value_type();
270 m_initialized = true ;
271 }
272
273 template<class Arg>
274 void emplace_assign ( const Arg& arg )
275 {
276 construct(in_place_init, arg);
277 }
278
279 template<class Arg>
280 void emplace_assign ( Arg& arg )
281 {
282 construct(in_place_init, arg);
283 }
284
285 void emplace_assign ()
286 {
287 construct(in_place_init);
288 }
289
290 template<class Arg>
291 explicit tc_optional_base ( in_place_init_t, const Arg& arg )
292 : m_initialized(false)
293 {
294 construct(in_place_init, arg);
295 }
296
297 template<class Arg>
298 explicit tc_optional_base ( in_place_init_t, Arg& arg )
299 : m_initialized(false)
300 {
301 construct(in_place_init, arg);
302 }
303
304 explicit tc_optional_base ( in_place_init_t )
305 : m_initialized(false)
306 {
307 construct(in_place_init);
308 }
309
310 template<class Arg>
311 explicit tc_optional_base ( in_place_init_if_t, bool cond, const Arg& arg )
312 : m_initialized(false)
313 {
314 if ( cond )
315 construct(in_place_init, arg);
316 }
317
318 template<class Arg>
319 explicit tc_optional_base ( in_place_init_if_t, bool cond, Arg& arg )
320 : m_initialized(false)
321 {
322 if ( cond )
323 construct(in_place_init, arg);
324 }
325
326 explicit tc_optional_base ( in_place_init_if_t, bool cond )
327 : m_initialized(false)
328 {
329 if ( cond )
330 construct(in_place_init);
331 }
332#endif
333
334#ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT
335
336#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
337 // Constructs in-place using the given factory
338 template<class Expr>
339 void construct ( Expr&& factory, in_place_factory_base const* )
340 {
341 boost_optional_detail::construct<value_type>(factory, boost::addressof(m_storage));
342 m_initialized = true ;
343 }
344
345 // Constructs in-place using the given typed factory
346 template<class Expr>
347 void construct ( Expr&& factory, typed_in_place_factory_base const* )
348 {
349 factory.apply(boost::addressof(m_storage)) ;
350 m_initialized = true ;
351 }
352
353 template<class Expr>
354 void assign_expr_to_initialized ( Expr&& factory, in_place_factory_base const* tag )
355 {
356 destroy();
357 construct(factory,tag);
358 }
359
360 // Constructs in-place using the given typed factory
361 template<class Expr>
362 void assign_expr_to_initialized ( Expr&& factory, typed_in_place_factory_base const* tag )
363 {
364 destroy();
365 construct(factory,tag);
366 }
367
368#else
369 // Constructs in-place using the given factory
370 template<class Expr>
371 void construct ( Expr const& factory, in_place_factory_base const* )
372 {
373 boost_optional_detail::construct<value_type>(factory, boost::addressof(m_storage));
374 m_initialized = true ;
375 }
376
377 // Constructs in-place using the given typed factory
378 template<class Expr>
379 void construct ( Expr const& factory, typed_in_place_factory_base const* )
380 {
381 factory.apply(boost::addressof(m_storage)) ;
382 m_initialized = true ;
383 }
384
385 template<class Expr>
386 void assign_expr_to_initialized ( Expr const& factory, in_place_factory_base const* tag )
387 {
388 destroy();
389 construct(factory,tag);
390 }
391
392 // Constructs in-place using the given typed factory
393 template<class Expr>
394 void assign_expr_to_initialized ( Expr const& factory, typed_in_place_factory_base const* tag )
395 {
396 destroy();
397 construct(factory,tag);
398 }
399#endif
400
401#endif
402
403#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
404 // Constructs using any expression implicitly convertible to the single argument
405 // of a one-argument T constructor.
406 // Converting constructions of optional<T> from optional<U> uses this function with
407 // 'Expr' being of type 'U' and relying on a converting constructor of T from U.
408 template<class Expr>
409 void construct ( Expr&& expr, void const* )
410 {
411 m_storage = value_type(boost::forward<Expr>(expr)) ;
412 m_initialized = true ;
413 }
414
415 // Assigns using a form any expression implicitly convertible to the single argument
416 // of a T's assignment operator.
417 // Converting assignments of optional<T> from optional<U> uses this function with
418 // 'Expr' being of type 'U' and relying on a converting assignment of T from U.
419 template<class Expr>
420 void assign_expr_to_initialized ( Expr&& expr, void const* )
421 {
422 assign_value( boost::forward<Expr>(expr) );
423 }
424#else
425 // Constructs using any expression implicitly convertible to the single argument
426 // of a one-argument T constructor.
427 // Converting constructions of optional<T> from optional<U> uses this function with
428 // 'Expr' being of type 'U' and relying on a converting constructor of T from U.
429 template<class Expr>
430 void construct ( Expr const& expr, void const* )
431 {
432 m_storage = value_type(expr) ;
433 m_initialized = true ;
434 }
435
436 // Assigns using a form any expression implicitly convertible to the single argument
437 // of a T's assignment operator.
438 // Converting assignments of optional<T> from optional<U> uses this function with
439 // 'Expr' being of type 'U' and relying on a converting assignment of T from U.
440 template<class Expr>
441 void assign_expr_to_initialized ( Expr const& expr, void const* )
442 {
443 assign_value(expr);
444 }
445
446#endif
447
448#ifdef BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION
449 // BCB5.64 (and probably lower versions) workaround.
450 // The in-place factories are supported by means of catch-all constructors
451 // and assignment operators (the functions are parameterized in terms of
452 // an arbitrary 'Expr' type)
453 // This compiler incorrectly resolves the overload set and sinks optional<T> and optional<U>
454 // to the 'Expr'-taking functions even though explicit overloads are present for them.
455 // Thus, the following overload is needed to properly handle the case when the 'lhs'
456 // is another optional.
457 //
458 // For VC<=70 compilers this workaround doesn't work because the compiler issues and error
459 // instead of choosing the wrong overload
460 //
461#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
462 // Notice that 'Expr' will be optional<T> or optional<U> (but not tc_optional_base<..>)
463 template<class Expr>
464 void construct ( Expr&& expr, optional_tag const* )
465 {
466 if ( expr.is_initialized() )
467 {
468 // An exception can be thrown here.
469 // It it happens, THIS will be left uninitialized.
470 m_storage = value_type(boost::move(expr.get())) ;
471 m_initialized = true ;
472 }
473 }
474#else
475 // Notice that 'Expr' will be optional<T> or optional<U> (but not tc_optional_base<..>)
476 template<class Expr>
477 void construct ( Expr const& expr, optional_tag const* )
478 {
479 if ( expr.is_initialized() )
480 {
481 // An exception can be thrown here.
482 // It it happens, THIS will be left uninitialized.
483 m_storage = value_type(expr.get()) ;
484 m_initialized = true ;
485 }
486 }
487#endif
488#endif // defined BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION
489
490 void assign_value ( argument_type val ) { m_storage = val; }
491#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
492 void assign_value ( rval_reference_type val ) { m_storage = static_cast<rval_reference_type>(val); }
493#endif
494
495 void destroy()
496 {
497 m_initialized = false;
498 }
499
500 reference_const_type get_impl() const { return m_storage ; }
501 reference_type get_impl() { return m_storage ; }
502
503 pointer_const_type get_ptr_impl() const { return boost::addressof(m_storage); }
504 pointer_type get_ptr_impl() { return boost::addressof(m_storage); }
505
506 private :
507
508 bool m_initialized ;
509 T m_storage ;
510} ;
511