/** * * \section COPYRIGHT * * Copyright 2013-2021 Software Radio Systems Limited * * By using this file, you agree to the terms and conditions set * forth in the LICENSE file which can be found at the top level of * the distribution. * */ #ifndef SRSLOG_DETAIL_SUPPORT_ANY_H #define SRSLOG_DETAIL_SUPPORT_ANY_H #include #include namespace srslog { namespace detail { /// Tag for in place construction of the any class. template struct in_place_type_t { explicit in_place_type_t() = default; }; /// Type trait to detect if T is a in_place_type_t tag. template struct is_in_place_type_t : std::false_type {}; template struct is_in_place_type_t > : std::true_type {}; /// This is a very minimalist and non compliant implementation of std::any which /// is included in C++17. /// From the standard: "The class any describes a type-safe container for single /// values of any type". class any { public: //: TODO: Clang 3.8 does not compile when default constructing a const object // due to DR253. Declare the defaulted constructor out of the class. any(); /// Disallow copies for simplicity. any(const any& other) = delete; any& operator=(const any& other) = delete; /// Constructs an object of type decayed T with the provided argument. /// This constructor only participates in overload resolution when the decayed /// T meets all of the following conditions: /// a) is not of class any. /// b) is move constructible. /// c) is not an specialization of in_place_type_t. /// Otherwise the rest of special member functions are considered. template ::type, any>{} && std::is_move_constructible::type>{} && !is_in_place_type_t::type>{}, int>::type = 0> explicit any(T&& t) : storage(new storage_impl::type>(std::forward(t))) {} /// Constructs an object of type decayed T directly into the internal storage /// forwarding the provided arguments. /// This constructor only participates in overload resolution when the decayed /// T meets all of the following conditions: /// a) T(args...) is constructible. /// Otherwise the rest of special member functions are considered. template ::type, Args...>{}, int>::type = 0> explicit any(in_place_type_t, Args&&... args) : storage(new storage_impl::type>(std::forward(args)...)) {} any(any&& other) : storage(std::move(other.storage)) {} any& operator=(any&& other) { storage = std::move(other.storage); return *this; } /// Checks whether the object contains a value. bool has_value() const { return (storage != nullptr); } /// If not empty, destroys the contained object. void reset() { storage.reset(); } /// Swaps the content of two any objects. void swap(any& other) { using std::swap; swap(storage, other.storage); } private: template friend T* any_cast(any* operand); template friend const T* any_cast(const any* operand); /// Type erased interface for type identification purposes. struct type_interface { virtual ~type_interface() = default; virtual const void* type() const = 0; }; /// Concrete type implementation with data storage. template struct storage_impl : public type_interface { template explicit storage_impl(Args&&... args) : data(std::forward(args)...) {} storage_impl(const storage_impl& other) = delete; storage_impl& operator=(const storage_impl& other) = delete; const void* type() const override { return &type_tag::tag; } T data; }; /// Discriminant tag for type identification. template struct type_tag { static const char tag; }; private: std::unique_ptr storage; }; //: TODO: declared out of line, see TODO above. inline any::any() = default; /// Constructs an any object containing an object of type T, passing the /// provided arguments to T's constructor. template inline any make_any(Args&&... args) { return any(in_place_type_t{}, std::forward(args)...); } /// When the requested T matches that of the contents of operand, a pointer to /// the value contained by operand is returned, otherwise returns a nullptr. /// Non-const overload. template inline T* any_cast(any* operand) { if (!operand || !operand->storage) return nullptr; using U = typename std::remove_cv::type>::type; if (operand->storage->type() != &any::type_tag::tag) return nullptr; return &static_cast*>(operand->storage.get())->data; } /// When the requested T matches that of the contents of operand, a pointer to /// the value contained by operand is returned, otherwise returns a nullptr. /// Const overload. template inline const T* any_cast(const any* operand) { if (!operand || !operand->storage) return nullptr; using U = typename std::remove_cv::type>::type; if (operand->storage->type() != &any::type_tag::tag) return nullptr; return &static_cast*>(operand->storage.get())->data; } inline void swap(any& lhs, any& rhs) { lhs.swap(rhs); } template const char any::type_tag::tag = 0; } // namespace detail } // namespace srslog #endif // SRSLOG_DETAIL_SUPPORT_ANY_H