// // Copyright (c) 2016-2018 Martin Moene // // https://github.com/martinmoene/any-lite // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #pragma once #ifndef NONSTD_ANY_LITE_HPP #define NONSTD_ANY_LITE_HPP #define any_lite_MAJOR 0 #define any_lite_MINOR 4 #define any_lite_PATCH 0 #define any_lite_VERSION \ any_STRINGIFY(any_lite_MAJOR) "." any_STRINGIFY( \ any_lite_MINOR) "." any_STRINGIFY(any_lite_PATCH) #define any_STRINGIFY(x) any_STRINGIFY_(x) #define any_STRINGIFY_(x) #x // any-lite configuration: #define any_ANY_DEFAULT 0 #define any_ANY_NONSTD 1 #define any_ANY_STD 2 // tweak header support: #ifdef __has_include #if __has_include() #include #endif #define any_HAVE_TWEAK_HEADER 1 #else #define any_HAVE_TWEAK_HEADER 0 //# pragma message("any.hpp: Note: Tweak header not supported.") #endif // any selection and configuration: #if !defined(any_CONFIG_SELECT_ANY) #define any_CONFIG_SELECT_ANY (any_HAVE_STD_ANY ? any_ANY_STD : any_ANY_NONSTD) #endif // Control presence of exception handling (try and auto discover): #ifndef any_CONFIG_NO_EXCEPTIONS #if defined(_MSC_VER) #include // for _HAS_EXCEPTIONS #endif #if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (_HAS_EXCEPTIONS) #define any_CONFIG_NO_EXCEPTIONS 0 #else #define any_CONFIG_NO_EXCEPTIONS 1 #endif #endif // C++ language version detection (C++23 is speculative): // Note: VC14.0/1900 (VS2015) lacks too much from C++14. #ifndef any_CPLUSPLUS #if defined(_MSVC_LANG) && !defined(__clang__) #define any_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG) #else #define any_CPLUSPLUS __cplusplus #endif #endif #define any_CPP98_OR_GREATER (any_CPLUSPLUS >= 199711L) #define any_CPP11_OR_GREATER (any_CPLUSPLUS >= 201103L) #define any_CPP14_OR_GREATER (any_CPLUSPLUS >= 201402L) #define any_CPP17_OR_GREATER (any_CPLUSPLUS >= 201703L) #define any_CPP20_OR_GREATER (any_CPLUSPLUS >= 202002L) #define any_CPP23_OR_GREATER (any_CPLUSPLUS >= 202300L) // Use C++17 std::any if available and requested: #if any_CPP17_OR_GREATER && defined(__has_include) #if __has_include( ) #define any_HAVE_STD_ANY 1 #else #define any_HAVE_STD_ANY 0 #endif #else #define any_HAVE_STD_ANY 0 #endif #define any_USES_STD_ANY \ ((any_CONFIG_SELECT_ANY == any_ANY_STD) \ || ((any_CONFIG_SELECT_ANY == any_ANY_DEFAULT) && any_HAVE_STD_ANY)) // // in_place: code duplicated in any-lite, expected-lite, optional-lite, value-ptr-lite, variant-lite: // #ifndef nonstd_lite_HAVE_IN_PLACE_TYPES #define nonstd_lite_HAVE_IN_PLACE_TYPES 1 // C++17 std::in_place in : #if any_CPP17_OR_GREATER #include namespace nonstd { using std::in_place; using std::in_place_index; using std::in_place_index_t; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; #define nonstd_lite_in_place_t(T) std::in_place_t #define nonstd_lite_in_place_type_t(T) std::in_place_type_t #define nonstd_lite_in_place_index_t(K) std::in_place_index_t #define nonstd_lite_in_place(T) \ std::in_place_t {} #define nonstd_lite_in_place_type(T) \ std::in_place_type_t {} #define nonstd_lite_in_place_index(K) \ std::in_place_index_t {} }// namespace nonstd #else// any_CPP17_OR_GREATER #include namespace nonstd { namespace detail { template struct in_place_type_tag {}; template struct in_place_index_tag {}; }// namespace detail struct in_place_t {}; template inline in_place_t in_place(detail::in_place_type_tag = detail::in_place_type_tag()) { return in_place_t(); } template inline in_place_t in_place(detail::in_place_index_tag = detail::in_place_index_tag()) { return in_place_t(); } template inline in_place_t in_place_type(detail::in_place_type_tag = detail::in_place_type_tag()) { return in_place_t(); } template inline in_place_t in_place_index(detail::in_place_index_tag = detail::in_place_index_tag()) { return in_place_t(); } // mimic templated typedef: #define nonstd_lite_in_place_t(T) \ nonstd::in_place_t (&)(nonstd::detail::in_place_type_tag) #define nonstd_lite_in_place_type_t(T) \ nonstd::in_place_t (&)(nonstd::detail::in_place_type_tag) #define nonstd_lite_in_place_index_t(K) \ nonstd::in_place_t (&)(nonstd::detail::in_place_index_tag) #define nonstd_lite_in_place(T) nonstd::in_place_type #define nonstd_lite_in_place_type(T) nonstd::in_place_type #define nonstd_lite_in_place_index(K) nonstd::in_place_index }// namespace nonstd #endif// any_CPP17_OR_GREATER #endif// nonstd_lite_HAVE_IN_PLACE_TYPES // // Using std::any: // #if any_USES_STD_ANY #include #include namespace nonstd { using std::any; using std::any_cast; using std::bad_any_cast; using std::make_any; using std::swap; }// namespace nonstd #else// any_USES_STD_ANY #if !any_CPP11_OR_GREATER #include // std::swap() #endif #include // Compiler versions: // // MSVC++ 6.0 _MSC_VER == 1200 any_COMPILER_MSVC_VERSION == 60 (Visual Studio 6.0) // MSVC++ 7.0 _MSC_VER == 1300 any_COMPILER_MSVC_VERSION == 70 (Visual Studio .NET 2002) // MSVC++ 7.1 _MSC_VER == 1310 any_COMPILER_MSVC_VERSION == 71 (Visual Studio .NET 2003) // MSVC++ 8.0 _MSC_VER == 1400 any_COMPILER_MSVC_VERSION == 80 (Visual Studio 2005) // MSVC++ 9.0 _MSC_VER == 1500 any_COMPILER_MSVC_VERSION == 90 (Visual Studio 2008) // MSVC++ 10.0 _MSC_VER == 1600 any_COMPILER_MSVC_VERSION == 100 (Visual Studio 2010) // MSVC++ 11.0 _MSC_VER == 1700 any_COMPILER_MSVC_VERSION == 110 (Visual Studio 2012) // MSVC++ 12.0 _MSC_VER == 1800 any_COMPILER_MSVC_VERSION == 120 (Visual Studio 2013) // MSVC++ 14.0 _MSC_VER == 1900 any_COMPILER_MSVC_VERSION == 140 (Visual Studio 2015) // MSVC++ 14.1 _MSC_VER >= 1910 any_COMPILER_MSVC_VERSION == 141 (Visual Studio 2017) // MSVC++ 14.2 _MSC_VER >= 1920 any_COMPILER_MSVC_VERSION == 142 (Visual Studio 2019) #if defined(_MSC_VER) && !defined(__clang__) #define any_COMPILER_MSVC_VER (_MSC_VER) #define any_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * (5 + (_MSC_VER < 1900))) #else #define any_COMPILER_MSVC_VER 0 #define any_COMPILER_MSVC_VERSION 0 #endif #define any_COMPILER_VERSION(major, minor, patch) \ (10 * (10 * (major) + (minor)) + (patch)) #if defined(__clang__) #define any_COMPILER_CLANG_VERSION \ any_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__) #else #define any_COMPILER_CLANG_VERSION 0 #endif #if defined(__GNUC__) && !defined(__clang__) #define any_COMPILER_GNUC_VERSION \ any_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) #else #define any_COMPILER_GNUC_VERSION 0 #endif // half-open range [lo..hi): //#define any_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) ) // Presence of language and library features: #define any_HAVE(feature) (any_HAVE_##feature) #ifdef _HAS_CPP0X #define any_HAS_CPP0X _HAS_CPP0X #else #define any_HAS_CPP0X 0 #endif #define any_CPP11_90 (any_CPP11_OR_GREATER || any_COMPILER_MSVC_VER >= 1500) #define any_CPP11_100 (any_CPP11_OR_GREATER || any_COMPILER_MSVC_VER >= 1600) #define any_CPP11_120 (any_CPP11_OR_GREATER || any_COMPILER_MSVC_VER >= 1800) #define any_CPP11_140 (any_CPP11_OR_GREATER || any_COMPILER_MSVC_VER >= 1900) #define any_CPP14_000 (any_CPP14_OR_GREATER) #define any_CPP17_000 (any_CPP17_OR_GREATER) // Presence of C++11 language features: #define any_HAVE_CONSTEXPR_11 any_CPP11_140 #define any_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG any_CPP11_120 #define any_HAVE_INITIALIZER_LIST any_CPP11_120 #define any_HAVE_NOEXCEPT any_CPP11_140 #define any_HAVE_NULLPTR any_CPP11_100 #define any_HAVE_TYPE_TRAITS any_CPP11_90 #define any_HAVE_STATIC_ASSERT any_CPP11_100 #define any_HAVE_ADD_CONST any_CPP11_90 #define any_HAVE_OVERRIDE any_CPP11_90 #define any_HAVE_REMOVE_REFERENCE any_CPP11_90 #define any_HAVE_TR1_ADD_CONST (!!any_COMPILER_GNUC_VERSION) #define any_HAVE_TR1_REMOVE_REFERENCE (!!any_COMPILER_GNUC_VERSION) #define any_HAVE_TR1_TYPE_TRAITS (!!any_COMPILER_GNUC_VERSION) // Presence of C++14 language features: #define any_HAVE_CONSTEXPR_14 any_CPP14_000 // Presence of C++17 language features: #define any_HAVE_NODISCARD any_CPP17_000 // Presence of C++ language features: #if any_HAVE_CONSTEXPR_11 #define any_constexpr constexpr #else #define any_constexpr /*constexpr*/ #endif #if any_HAVE_CONSTEXPR_14 #define any_constexpr14 constexpr #else #define any_constexpr14 /*constexpr*/ #endif #if any_HAVE_NOEXCEPT #define any_noexcept noexcept #else #define any_noexcept /*noexcept*/ #endif #if any_HAVE_NULLPTR #define any_nullptr nullptr #else #define any_nullptr NULL #endif #if any_HAVE_NODISCARD #define any_nodiscard [[nodiscard]] #else #define any_nodiscard /*[[nodiscard]]*/ #endif #if any_HAVE_OVERRIDE #define any_override override #else #define any_override /*override*/ #endif // additional includes: #if any_CONFIG_NO_EXCEPTIONS #include #else #include #endif #if !any_HAVE_NULLPTR #include #endif #if any_HAVE_INITIALIZER_LIST #include #endif #if any_HAVE_TYPE_TRAITS #include #elif any_HAVE_TR1_TYPE_TRAITS #include #endif // Method enabling #if any_CPP11_OR_GREATER #define any_REQUIRES_0(...) \ template::type = 0> #define any_REQUIRES_T(...) \ , typename std::enable_if<(__VA_ARGS__), int>::type = 0 #define any_REQUIRES_R(R, ...) typename std::enable_if<__VA_ARGS__, R>::type #define any_REQUIRES_A(...) \ , typename std::enable_if<__VA_ARGS__, void *>::type = nullptr #endif // // any: // namespace nonstd { namespace any_lite { // C++11 emulation: namespace std11 { #if any_HAVE_ADD_CONST using std::add_const; #elif any_HAVE_TR1_ADD_CONST using std::tr1::add_const; #else template struct add_const { typedef const T type; }; #endif// any_HAVE_ADD_CONST #if any_HAVE_REMOVE_REFERENCE using std::remove_reference; #elif any_HAVE_TR1_REMOVE_REFERENCE using std::tr1::remove_reference; #else template struct remove_reference { typedef T type; }; template struct remove_reference { typedef T type; }; #endif// any_HAVE_REMOVE_REFERENCE }// namespace std11 namespace detail { // for any_REQUIRES_T /*enum*/ class enabler {}; }// namespace detail #if !any_CONFIG_NO_EXCEPTIONS class bad_any_cast : public std::bad_cast { public: #if any_CPP11_OR_GREATER virtual const char *what() const any_noexcept any_override #else virtual const char *what() const throw() #endif { return "any-lite: bad any_cast"; } }; #endif// any_CONFIG_NO_EXCEPTIONS class any { public: any_constexpr any() any_noexcept : content(any_nullptr) {} any(any const &other) : content(other.content ? other.content->clone() : any_nullptr) {} #if any_CPP11_OR_GREATER any(any &&other) any_noexcept : content(std::move(other.content)) { other.content = any_nullptr; } template::type any_REQUIRES_T( !std::is_same::value)> any(ValueType &&value) any_noexcept : content(new holder(std::forward(value))) {} template::value)> explicit any(nonstd_lite_in_place_type_t(T), Args &&...args) : content(new holder(T(std::forward(args)...))) {} template &, Args &&...>::value)> explicit any(nonstd_lite_in_place_type_t(T), std::initializer_list il, Args &&...args) : content(new holder(T(il, std::forward(args)...))) {} #else template any(ValueType const &value) : content(new holder(value)) {} #endif// any_CPP11_OR_GREATER ~any() { reset(); } any &operator=(any const &other) { any(other).swap(*this); return *this; } #if any_CPP11_OR_GREATER any &operator=(any &&other) any_noexcept { any(std::move(other)).swap(*this); return *this; } template::type any_REQUIRES_T( !std::is_same::value)> any &operator=(T &&value) { any(std::move(value)).swap(*this); return *this; } template void emplace(Args &&...args) { any(T(std::forward(args)...)).swap(*this); } template &, Args &&...>::value)> void emplace(std::initializer_list il, Args &&...args) { any(T(il, std::forward(args)...)).swap(*this); } #else template any &operator=(ValueType const &value) { any(value).swap(*this); return *this; } #endif// any_CPP11_OR_GREATER void reset() any_noexcept { delete content; content = any_nullptr; } void swap(any &other) any_noexcept { std::swap(content, other.content); } bool has_value() const any_noexcept { return content != any_nullptr; } const std::type_info &type() const any_noexcept { return has_value() ? content->type() : typeid(void); } // // non-standard: // template const ValueType *to_ptr() const { return &(static_cast *>(content)->held); } template ValueType *to_ptr() { return &(static_cast *>(content)->held); } private: class placeholder { public: virtual ~placeholder() {} virtual std::type_info const &type() const = 0; virtual placeholder *clone() const = 0; }; template class holder : public placeholder { public: holder(ValueType const &value) : held(value) {} #if any_CPP11_OR_GREATER holder(ValueType &&value) : held(std::move(value)) {} #endif virtual std::type_info const &type() const any_override { return typeid(ValueType); } virtual placeholder *clone() const any_override { return new holder(held); } ValueType held; }; placeholder *content; }; inline void swap(any &x, any &y) any_noexcept { x.swap(y); } #if any_CPP11_OR_GREATER template inline any make_any(Args &&...args) { return any(nonstd_lite_in_place_type(T), std::forward(args)...); } template inline any make_any(std::initializer_list il, Args &&...args) { return any(nonstd_lite_in_place_type(T), il, std::forward(args)...); } #endif// any_CPP11_OR_GREATER template::value || std::is_copy_constructible::value), nonstd::any_lite::detail::enabler>::type #endif > any_nodiscard inline ValueType any_cast(any const &operand) { const ValueType *result = any_cast::type>::type>(&operand); #if any_CONFIG_NO_EXCEPTIONS assert(result); #else if (!result) { throw bad_any_cast(); } #endif return *result; } template::value || std::is_copy_constructible::value), nonstd::any_lite::detail::enabler>::type #endif > any_nodiscard inline ValueType any_cast(any &operand) { const ValueType *result = any_cast::type>(&operand); #if any_CONFIG_NO_EXCEPTIONS assert(result); #else if (!result) { throw bad_any_cast(); } #endif return *result; } #if any_CPP11_OR_GREATER template::value || std::is_copy_constructible::value) #endif > any_nodiscard inline ValueType any_cast(any &&operand) { const ValueType *result = any_cast::type>(&operand); #if any_CONFIG_NO_EXCEPTIONS assert(result); #else if (!result) { throw bad_any_cast(); } #endif return *result; } #endif// any_CPP11_OR_GREATER template any_nodiscard inline ValueType const * any_cast(any const *operand) any_noexcept { return operand != any_nullptr && operand->type() == typeid(ValueType) ? operand->to_ptr() : any_nullptr; } template any_nodiscard inline ValueType * any_cast(any *operand) any_noexcept { return operand != any_nullptr && operand->type() == typeid(ValueType) ? operand->to_ptr() : any_nullptr; } }// namespace any_lite using namespace any_lite; }// namespace nonstd namespace ulib { using namespace nonstd::any_lite; } #endif// any_USES_STD_ANY #endif// NONSTD_ANY_LITE_HPP