any.hpp
Go to the documentation of this file.
1 //
2 // Copyright (c) 2016-2018 Martin Moene
3 //
4 // https://github.com/martinmoene/any-lite
5 //
6 // Distributed under the Boost Software License, Version 1.0.
7 // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 
9 #pragma once
10 
11 #ifndef NONSTD_ANY_LITE_HPP
12 #define NONSTD_ANY_LITE_HPP
13 
14 #define any_lite_MAJOR 0
15 #define any_lite_MINOR 1
16 #define any_lite_PATCH 0
17 
18 #define any_lite_VERSION any_STRINGIFY(any_lite_MAJOR) "." any_STRINGIFY(any_lite_MINOR) "." any_STRINGIFY(any_lite_PATCH)
19 
20 #define any_STRINGIFY( x ) any_STRINGIFY_( x )
21 #define any_STRINGIFY_( x ) #x
22 
23 // any-lite configuration:
24 
25 #define any_ANY_DEFAULT 0
26 #define any_ANY_NONSTD 1
27 #define any_ANY_STD 2
28 
29 #if !defined( any_CONFIG_SELECT_ANY )
30 # define any_CONFIG_SELECT_ANY ( any_HAVE_STD_ANY ? any_ANY_STD : any_ANY_NONSTD )
31 #endif
32 
33 // Control presence of exception handling (try and auto discover):
34 
35 #ifndef any_CONFIG_NO_EXCEPTIONS
36 # if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
37 # define any_CONFIG_NO_EXCEPTIONS 0
38 # else
39 # define any_CONFIG_NO_EXCEPTIONS 1
40 # endif
41 #endif
42 
43 // C++ language version detection (C++20 is speculative):
44 // Note: VC14.0/1900 (VS2015) lacks too much from C++14.
45 
46 #ifndef any_CPLUSPLUS
47 # if defined(_MSVC_LANG ) && !defined(__clang__)
48 # define any_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG )
49 # else
50 # define any_CPLUSPLUS __cplusplus
51 # endif
52 #endif
53 
54 #define any_CPP98_OR_GREATER ( any_CPLUSPLUS >= 199711L )
55 #define any_CPP11_OR_GREATER ( any_CPLUSPLUS >= 201103L )
56 #define any_CPP14_OR_GREATER ( any_CPLUSPLUS >= 201402L )
57 #define any_CPP17_OR_GREATER ( any_CPLUSPLUS >= 201703L )
58 #define any_CPP20_OR_GREATER ( any_CPLUSPLUS >= 202000L )
59 
60 // Use C++17 std::any if available and requested:
61 
62 #if any_CPP17_OR_GREATER && defined(__has_include )
63 # if __has_include( <any> )
64 # define any_HAVE_STD_ANY 1
65 # else
66 # define any_HAVE_STD_ANY 0
67 # endif
68 #else
69 # define any_HAVE_STD_ANY 0
70 #endif
71 
72 #define any_USES_STD_ANY ( (any_CONFIG_SELECT_ANY == any_ANY_STD) || ((any_CONFIG_SELECT_ANY == any_ANY_DEFAULT) && any_HAVE_STD_ANY) )
73 
74 //
75 // in_place: code duplicated in any-lite, expected-lite, optional-lite, value-ptr-lite, variant-lite:
76 //
77 
78 #ifndef nonstd_lite_HAVE_IN_PLACE_TYPES
79 #define nonstd_lite_HAVE_IN_PLACE_TYPES 1
80 
81 // C++17 std::in_place in <utility>:
82 
83 #if any_CPP17_OR_GREATER
84 
85 #include <utility>
86 
87 namespace nonstd {
88 
89 using std::in_place;
90 using std::in_place_type;
92 using std::in_place_t;
93 using std::in_place_type_t;
94 using std::in_place_index_t;
95 
96 #define nonstd_lite_in_place_t( T) std::in_place_t
97 #define nonstd_lite_in_place_type_t( T) std::in_place_type_t<T>
98 #define nonstd_lite_in_place_index_t(K) std::in_place_index_t<K>
99 
100 #define nonstd_lite_in_place( T) std::in_place_t{}
101 #define nonstd_lite_in_place_type( T) std::in_place_type_t<T>{}
102 #define nonstd_lite_in_place_index(K) std::in_place_index_t<K>{}
103 
104 } // namespace nonstd
105 
106 #else // any_CPP17_OR_GREATER
107 
108 #include <cstddef>
109 
110 namespace nonstd {
111 namespace detail {
112 
113 template< class T >
115 
116 template< std::size_t K >
118 
119 } // namespace detail
120 
121 struct in_place_t {};
122 
123 template< class T >
125 {
126  return in_place_t();
127 }
128 
129 template< std::size_t K >
131 {
132  return in_place_t();
133 }
134 
135 template< class T >
137 {
138  return in_place_t();
139 }
140 
141 template< std::size_t K >
143 {
144  return in_place_t();
145 }
146 
147 // mimic templated typedef:
148 
149 #define nonstd_lite_in_place_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag<T> )
150 #define nonstd_lite_in_place_type_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag<T> )
151 #define nonstd_lite_in_place_index_t(K) nonstd::in_place_t(&)( nonstd::detail::in_place_index_tag<K> )
152 
153 #define nonstd_lite_in_place( T) nonstd::in_place_type<T>
154 #define nonstd_lite_in_place_type( T) nonstd::in_place_type<T>
155 #define nonstd_lite_in_place_index(K) nonstd::in_place_index<K>
156 
157 } // namespace nonstd
158 
159 #endif // any_CPP17_OR_GREATER
160 #endif // nonstd_lite_HAVE_IN_PLACE_TYPES
161 
162 //
163 // Using std::any:
164 //
165 
166 #if any_USES_STD_ANY
167 
168 #include <any>
169 #include <utility>
170 
171 namespace nonstd {
172 
173  using std::any;
174  using std::any_cast;
175  using std::make_any;
176  using std::swap;
177  using std::bad_any_cast;
178 }
179 
180 #else // any_USES_STD_ANY
181 
182 #include <utility>
183 
184 // Compiler versions:
185 //
186 // MSVC++ 6.0 _MSC_VER == 1200 (Visual Studio 6.0)
187 // MSVC++ 7.0 _MSC_VER == 1300 (Visual Studio .NET 2002)
188 // MSVC++ 7.1 _MSC_VER == 1310 (Visual Studio .NET 2003)
189 // MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005)
190 // MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008)
191 // MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010)
192 // MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012)
193 // MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013)
194 // MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015)
195 // MSVC++ 14.1 _MSC_VER >= 1910 (Visual Studio 2017)
196 
197 #if defined(_MSC_VER ) && !defined(__clang__)
198 # define any_COMPILER_MSVC_VER (_MSC_VER )
199 # define any_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) )
200 #else
201 # define any_COMPILER_MSVC_VER 0
202 # define any_COMPILER_MSVC_VERSION 0
203 #endif
204 
205 #define any_COMPILER_VERSION( major, minor, patch ) ( 10 * ( 10 * (major) + (minor) ) + (patch) )
206 
207 #if defined(__clang__)
208 # define any_COMPILER_CLANG_VERSION any_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__)
209 #else
210 # define any_COMPILER_CLANG_VERSION 0
211 #endif
212 
213 #if defined(__GNUC__) && !defined(__clang__)
214 # define any_COMPILER_GNUC_VERSION any_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
215 #else
216 # define any_COMPILER_GNUC_VERSION 0
217 #endif
218 
219 // half-open range [lo..hi):
220 //#define any_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) )
221 
222 // Presence of language and library features:
223 
224 #define any_HAVE( feature ) ( any_HAVE_##feature )
225 
226 #ifdef _HAS_CPP0X
227 # define any_HAS_CPP0X _HAS_CPP0X
228 #else
229 # define any_HAS_CPP0X 0
230 #endif
231 
232 #define any_CPP11_90 (any_CPP11_OR_GREATER || any_COMPILER_MSVC_VER >= 1500)
233 #define any_CPP11_100 (any_CPP11_OR_GREATER || any_COMPILER_MSVC_VER >= 1600)
234 #define any_CPP11_120 (any_CPP11_OR_GREATER || any_COMPILER_MSVC_VER >= 1800)
235 #define any_CPP11_140 (any_CPP11_OR_GREATER || any_COMPILER_MSVC_VER >= 1900)
236 
237 #define any_CPP14_000 (any_CPP14_OR_GREATER)
238 #define any_CPP17_000 (any_CPP17_OR_GREATER)
239 
240 // Presence of C++11 language features:
241 
242 #define any_HAVE_CONSTEXPR_11 any_CPP11_140
243 #define any_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG \
244  any_CPP11_120
245 #define any_HAVE_INITIALIZER_LIST any_CPP11_120
246 #define any_HAVE_NOEXCEPT any_CPP11_140
247 #define any_HAVE_NULLPTR any_CPP11_100
248 #define any_HAVE_TYPE_TRAITS any_CPP11_90
249 #define any_HAVE_STATIC_ASSERT any_CPP11_100
250 #define any_HAVE_ADD_CONST any_CPP11_90
251 #define any_HAVE_REMOVE_REFERENCE any_CPP11_90
252 
253 #define any_HAVE_TR1_ADD_CONST (!! any_COMPILER_GNUC_VERSION )
254 #define any_HAVE_TR1_REMOVE_REFERENCE (!! any_COMPILER_GNUC_VERSION )
255 #define any_HAVE_TR1_TYPE_TRAITS (!! any_COMPILER_GNUC_VERSION )
256 
257 // Presence of C++14 language features:
258 
259 #define any_HAVE_CONSTEXPR_14 any_CPP14_000
260 
261 // Presence of C++17 language features:
262 
263 #define any_HAVE_NODISCARD any_CPP17_000
264 
265 // Presence of C++ language features:
266 
267 #if any_HAVE_CONSTEXPR_11
268 # define any_constexpr constexpr
269 #else
270 # define any_constexpr /*constexpr*/
271 #endif
272 
273 #if any_HAVE_CONSTEXPR_14
274 # define any_constexpr14 constexpr
275 #else
276 # define any_constexpr14 /*constexpr*/
277 #endif
278 
279 #if any_HAVE_NOEXCEPT
280 # define any_noexcept noexcept
281 #else
282 # define any_noexcept /*noexcept*/
283 #endif
284 
285 #if any_HAVE_NULLPTR
286 # define any_nullptr nullptr
287 #else
288 # define any_nullptr NULL
289 #endif
290 
291 #if any_HAVE_NODISCARD
292 # define any_nodiscard [[nodiscard]]
293 #else
294 # define any_nodiscard /*[[nodiscard]]*/
295 #endif
296 
297 // additional includes:
298 
299 #if any_CONFIG_NO_EXCEPTIONS
300 # include <cassert>
301 #else
302 # include <typeinfo>
303 #endif
304 
305 #if ! any_HAVE_NULLPTR
306 # include <cstddef>
307 #endif
308 
309 #if any_HAVE_INITIALIZER_LIST
310 # include <initializer_list>
311 #endif
312 
313 #if any_HAVE_TYPE_TRAITS
314 # include <type_traits>
315 #elif any_HAVE_TR1_TYPE_TRAITS
316 # include <tr1/type_traits>
317 #endif
318 
319 // Method enabling
320 
321 #if any_CPP11_OR_GREATER
322 
323 #define any_REQUIRES_0(...) \
324  template< bool B = (__VA_ARGS__), typename std::enable_if<B, int>::type = 0 >
325 
326 #define any_REQUIRES_T(...) \
327  , typename = typename std::enable_if< (__VA_ARGS__), nonstd::any_lite::detail::enabler >::type
328 
329 #define any_REQUIRES_R(R, ...) \
330  typename std::enable_if<__VA_ARGS__, R>::type
331 
332 #define any_REQUIRES_A(...) \
333  , typename std::enable_if<__VA_ARGS__, void*>::type = nullptr
334 
335 #endif
336 
337 //
338 // any:
339 //
340 
341 namespace nonstd { namespace any_lite {
342 
343 // C++11 emulation:
344 
345 namespace std11 {
346 
347 #if any_HAVE_ADD_CONST
348 
349 using std::add_const;
350 
351 #elif any_HAVE_TR1_ADD_CONST
352 
353 using std::tr1::add_const;
354 
355 #else
356 
357 template< class T > struct add_const { typedef const T type; };
358 
359 #endif // any_HAVE_ADD_CONST
360 
361 #if any_HAVE_REMOVE_REFERENCE
362 
363 using std::remove_reference;
364 
365 #elif any_HAVE_TR1_REMOVE_REFERENCE
366 
367 using std::tr1::remove_reference;
368 
369 #else
370 
371 template< class T > struct remove_reference { typedef T type; };
372 template< class T > struct remove_reference<T&> { typedef T type; };
373 
374 #endif // any_HAVE_REMOVE_REFERENCE
375 
376 } // namespace std11
377 
378 namespace detail {
379 
380 // for any_REQUIRES_T
381 
382 /*enum*/ class enabler{};
383 
384 } // namespace detail
385 
386 #if ! any_CONFIG_NO_EXCEPTIONS
387 
388 class bad_any_cast : public std::bad_cast
389 {
390 public:
391 #if any_CPP11_OR_GREATER
392  virtual const char* what() const any_noexcept
393 #else
394  virtual const char* what() const throw()
395 #endif
396  {
397  return "any-lite: bad any_cast";
398  }
399 };
400 
401 #endif // any_CONFIG_NO_EXCEPTIONS
402 
403 class any
404 {
405 public:
407  : content( any_nullptr )
408  {}
409 
410  any( any const & other )
411  : content( other.content ? other.content->clone() : any_nullptr )
412  {}
413 
414 #if any_CPP11_OR_GREATER
415 
416  any( any && other ) any_noexcept
417  : content( std::move( other.content ) )
418  {
419  other.content = any_nullptr;
420  }
421 
422  template<
423  class ValueType, class T = typename std::decay<ValueType>::type
424  any_REQUIRES_T( ! std::is_same<T, any>::value )
425  >
426  any( ValueType && value ) any_noexcept
427  : content( new holder<T>( std::move( value ) ) )
428  {}
429 
430  template<
431  class T, class... Args
432  any_REQUIRES_T( std::is_constructible<T, Args&&...>::value )
433  >
434  explicit any( nonstd_lite_in_place_type_t(T), Args&&... args )
435  : content( new holder<T>( T( std::forward<Args>(args)... ) ) )
436  {}
437 
438  template<
439  class T, class U, class... Args
440  any_REQUIRES_T( std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value )
441  >
442  explicit any( nonstd_lite_in_place_type_t(T), std::initializer_list<U> il, Args&&... args )
443  : content( new holder<T>( T( il, std::forward<Args>(args)... ) ) )
444  {}
445 
446 #else
447 
448  template< class ValueType >
449  any( ValueType const & value )
450  : content( new holder<ValueType>( value ) )
451  {}
452 
453 #endif // any_CPP11_OR_GREATER
454 
456  {
457  reset();
458  }
459 
460  any & operator=( any const & other )
461  {
462  any( other ).swap( *this );
463  return *this;
464  }
465 
466 #if any_CPP11_OR_GREATER
467 
468  any & operator=( any && other ) any_noexcept
469  {
470  any( std::move( other ) ).swap( *this );
471  return *this;
472  }
473 
474  template<
475  class ValueType, class T = typename std::decay<ValueType>::type
476  any_REQUIRES_T( ! std::is_same<T, any>::value )
477  >
478  any & operator=( ValueType && value )
479  {
480  any( std::move( value ) ).swap( *this );
481  return *this;
482  }
483 
484  template< class T, class... Args >
485  void emplace( Args && ... args )
486  {
487  any( T( std::forward<Args>(args)... ) ).swap( *this );
488  }
489 
490  template<
491  class T, class U, class... Args
492  any_REQUIRES_T( std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value )
493  >
494  void emplace( std::initializer_list<U> il, Args&&... args )
495  {
496  any( T( il, std::forward<Args>(args)... ) ).swap( *this );
497  }
498 
499 #else
500 
501  template< class ValueType >
502  any & operator=( ValueType const & value )
503  {
504  any( value ).swap( *this );
505  return *this;
506  }
507 
508 #endif // any_CPP11_OR_GREATER
509 
511  {
512  delete content; content = any_nullptr;
513  }
514 
515  void swap( any & other ) any_noexcept
516  {
517  std::swap( content, other.content );
518  }
519 
520  bool has_value() const any_noexcept
521  {
522  return content != any_nullptr;
523  }
524 
525  const std::type_info & type() const any_noexcept
526  {
527  return has_value() ? content->type() : typeid( void );
528  }
529 
530  //
531  // non-standard:
532  //
533 
534  template< class ValueType >
535  const ValueType * to_ptr() const
536  {
537  return &( static_cast<holder<ValueType> *>( content )->held );
538  }
539 
540  template< class ValueType >
541  ValueType * to_ptr()
542  {
543  return &( static_cast<holder<ValueType> *>( content )->held );
544  }
545 
546 private:
547  class placeholder
548  {
549  public:
550  virtual ~placeholder()
551  {
552  }
553 
554  virtual std::type_info const & type() const = 0;
555 
556  virtual placeholder * clone() const = 0;
557  };
558 
559  template< typename ValueType >
560  class holder : public placeholder
561  {
562  public:
563  holder( ValueType const & value )
564  : held( value )
565  {}
566 
567 #if any_CPP11_OR_GREATER
568  holder( ValueType && value )
569  : held( std::move( value ) )
570  {}
571 #endif
572 
573  virtual std::type_info const & type() const
574  {
575  return typeid( ValueType );
576  }
577 
578  virtual placeholder * clone() const
579  {
580  return new holder( held );
581  }
582 
583  ValueType held;
584  };
585 
586  placeholder * content;
587 };
588 
589 inline void swap( any & x, any & y ) any_noexcept
590 {
591  x.swap( y );
592 }
593 
594 #if any_CPP11_OR_GREATER
595 
596 template< class T, class ...Args >
597 inline any make_any( Args&& ...args )
598 {
599  return any( nonstd_lite_in_place_type(T), std::forward<Args>(args)...);
600 }
601 
602 template< class T, class U, class ...Args >
603 inline any make_any( std::initializer_list<U> il, Args&& ...args )
604 {
605  return any( nonstd_lite_in_place_type(T), il, std::forward<Args>(args)...);
606 }
607 
608 #endif // any_CPP11_OR_GREATER
609 
610 template<
611  class ValueType
612 #if any_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG
613 // any_REQUIRES_T(...) Allow for VC120 (VS2013):
614  , typename = typename std::enable_if< (std::is_reference<ValueType>::value || std::is_copy_constructible<ValueType>::value), nonstd::any_lite::detail::enabler >::type
615 #endif
616 >
617 any_nodiscard inline ValueType any_cast( any const & operand )
618 {
619  const ValueType * result = any_cast< typename std11::add_const< typename std11::remove_reference<ValueType>::type >::type >( &operand );
620 
621 #if any_CONFIG_NO_EXCEPTIONS
622  assert( result );
623 #else
624  if ( ! result )
625  {
626  throw bad_any_cast();
627  }
628 #endif
629 
630  return *result;
631 }
632 
633 template<
634  class ValueType
635 #if any_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG
636 // any_REQUIRES_T(...) Allow for VC120 (VS2013):
637  , typename = typename std::enable_if< (std::is_reference<ValueType>::value || std::is_copy_constructible<ValueType>::value), nonstd::any_lite::detail::enabler >::type
638 #endif
639 >
640 any_nodiscard inline ValueType any_cast( any & operand )
641 {
642  const ValueType * result = any_cast< typename std11::remove_reference<ValueType>::type >( &operand );
643 
644 #if any_CONFIG_NO_EXCEPTIONS
645  assert( result );
646 #else
647  if ( ! result )
648  {
649  throw bad_any_cast();
650  }
651 #endif
652 
653  return *result;
654 }
655 
656 #if any_CPP11_OR_GREATER
657 
658 template<
659  class ValueType
660 #if any_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG
661  any_REQUIRES_T( std::is_reference<ValueType>::value || std::is_copy_constructible<ValueType>::value )
662 #endif
663 >
664 any_nodiscard inline ValueType any_cast( any && operand )
665 {
666  const ValueType * result = any_cast< typename std11::remove_reference<ValueType>::type >( &operand );
667 
668 #if any_CONFIG_NO_EXCEPTIONS
669  assert( result );
670 #else
671  if ( ! result )
672  {
673  throw bad_any_cast();
674  }
675 #endif
676 
677  return *result;
678 }
679 
680 #endif // any_CPP11_OR_GREATER
681 
682 template< class ValueType >
683 any_nodiscard inline ValueType const * any_cast( any const * operand ) any_noexcept
684 {
685  return operand != any_nullptr && operand->type() == typeid(ValueType) ? operand->to_ptr<ValueType>() : any_nullptr;
686 }
687 
688 template<class ValueType >
689 any_nodiscard inline ValueType * any_cast( any * operand ) any_noexcept
690 {
691  return operand != any_nullptr && operand->type() == typeid(ValueType) ? operand->to_ptr<ValueType>() : any_nullptr;
692 }
693 
694 } // namespace any_lite
695 
696 using namespace any_lite;
697 
698 } // namespace nonstd
699 
700 #endif // any_USES_STD_ANY
701 
702 #endif // NONSTD_ANY_LITE_HPP
const ValueType * to_ptr() const
Definition: any.hpp:535
const std::type_info & type() const
Definition: any.hpp:525
#define nonstd_lite_in_place_type(T)
Definition: any.hpp:154
in_place_t in_place(detail::in_place_index_tag< K >=detail::in_place_index_tag< K >())
Definition: any.hpp:130
any(ValueType const &value)
Definition: any.hpp:449
ValueType * any_cast(any *operand)
Definition: any.hpp:689
#define any_nodiscard
Definition: any.hpp:294
in_place_t in_place_index(detail::in_place_index_tag< K >=detail::in_place_index_tag< K >())
Definition: any.hpp:142
void swap(any &other)
Definition: any.hpp:515
#define any_noexcept
Definition: any.hpp:282
#define nonstd_lite_in_place_type_t(T)
Definition: any.hpp:150
bool has_value() const
Definition: any.hpp:520
any(any const &other)
Definition: any.hpp:410
#define any_constexpr
Definition: any.hpp:270
Definition: any.hpp:110
any & operator=(any const &other)
Definition: any.hpp:460
ValueType * to_ptr()
Definition: any.hpp:541
#define any_nullptr
Definition: any.hpp:288
in_place_t in_place_type(detail::in_place_type_tag< T >=detail::in_place_type_tag< T >())
Definition: any.hpp:136
void swap(any &x, any &y)
Definition: any.hpp:589
any & operator=(ValueType const &value)
Definition: any.hpp:502
in_place_t in_place(detail::in_place_type_tag< T >=detail::in_place_type_tag< T >())
Definition: any.hpp:124