//////////////////////////////////////////////////////////////////////////// // // Copyright 2017 Realm Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //////////////////////////////////////////////////////////////////////////// #ifndef REALM_UTIL_ANY_HPP #define REALM_UTIL_ANY_HPP #include #include #include #include #include namespace realm { namespace util { using bad_cast = std::bad_cast; // A naive implementation of C++17's std::any // This does not perform the small-object optimization or make any particular // attempt at being performant class Any final { public: // Constructors Any() = default; Any(Any&&) noexcept = default; ~Any() = default; Any& operator=(Any&&) noexcept = default; Any(Any const& rhs) : m_value(rhs.m_value ? rhs.m_value->copy() : nullptr) { } template::type, Any>::value>::type> Any(T&& value) : m_value(std::make_unique::type>>(std::forward(value))) { } Any& operator=(Any const& rhs) { m_value = rhs.m_value ? rhs.m_value->copy() : nullptr; return *this; } template::type, Any>::value>::type> Any& operator=(T&& value) { m_value = std::make_unique::type>>(std::forward(value)); return *this; } // Modifiers void reset() noexcept { m_value.reset(); } void swap(Any& rhs) noexcept { std::swap(m_value, rhs.m_value); } // Observers bool has_value() const noexcept { return m_value != nullptr; } std::type_info const& type() const noexcept { return m_value ? m_value->type() : typeid(void); } private: struct ValueBase { virtual ~ValueBase() noexcept { } virtual std::type_info const& type() const noexcept = 0; virtual std::unique_ptr copy() const = 0; }; template struct Value : ValueBase { T value; template Value(U&& v) : value(std::forward(v)) { } std::type_info const& type() const noexcept override { return typeid(T); } std::unique_ptr copy() const override { return std::make_unique>(value); } }; std::unique_ptr m_value; template friend const T* any_cast(const Any* operand) noexcept; template friend T* any_cast(Any* operand) noexcept; template const T* cast() const noexcept { return &static_cast*>(m_value.get())->value; } template T* cast() noexcept { return &static_cast*>(m_value.get())->value; } }; template T any_cast(Any const& value) { auto ptr = any_cast::type>::type>(&value); if (!ptr) throw bad_cast(); return *ptr; } template T any_cast(Any& value) { auto ptr = any_cast::type>(&value); if (!ptr) throw bad_cast(); return *ptr; } template T any_cast(Any&& value) { auto ptr = any_cast::type>(&value); if (!ptr) throw bad_cast(); return std::move(*ptr); } template T* any_cast(Any* value) noexcept { return value && value->type() == typeid(T) ? value->cast() : nullptr; } template const T* any_cast(const Any* value) noexcept { return value && value->type() == typeid(T) ? value->cast() : nullptr; } } // namespace util } // namespace realm namespace std { inline void swap(realm::util::Any& lhs, realm::util::Any& rhs) noexcept { lhs.swap(rhs); } } // namespace std #endif // REALM_UTIL_ANY_HPP