any.hpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. ////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2017 Realm Inc.
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. //
  17. ////////////////////////////////////////////////////////////////////////////
  18. #ifndef REALM_UTIL_ANY_HPP
  19. #define REALM_UTIL_ANY_HPP
  20. #include <memory>
  21. #include <stdexcept>
  22. #include <type_traits>
  23. #include <typeinfo>
  24. #include <realm/util/backtrace.hpp>
  25. namespace realm {
  26. namespace util {
  27. using bad_cast = std::bad_cast;
  28. // A naive implementation of C++17's std::any
  29. // This does not perform the small-object optimization or make any particular
  30. // attempt at being performant
  31. class Any final {
  32. public:
  33. // Constructors
  34. Any() = default;
  35. Any(Any&&) noexcept = default;
  36. ~Any() = default;
  37. Any& operator=(Any&&) noexcept = default;
  38. Any(Any const& rhs)
  39. : m_value(rhs.m_value ? rhs.m_value->copy() : nullptr)
  40. {
  41. }
  42. template<typename T, typename = typename std::enable_if<!std::is_same<typename std::decay<T>::type, Any>::value>::type>
  43. Any(T&& value)
  44. : m_value(std::make_unique<Value<typename std::decay<T>::type>>(std::forward<T>(value)))
  45. {
  46. }
  47. Any& operator=(Any const& rhs)
  48. {
  49. m_value = rhs.m_value ? rhs.m_value->copy() : nullptr;
  50. return *this;
  51. }
  52. template<typename T, typename = typename std::enable_if<!std::is_same<typename std::decay<T>::type, Any>::value>::type>
  53. Any& operator=(T&& value)
  54. {
  55. m_value = std::make_unique<Value<typename std::decay<T>::type>>(std::forward<T>(value));
  56. return *this;
  57. }
  58. // Modifiers
  59. void reset() noexcept { m_value.reset(); }
  60. void swap(Any& rhs) noexcept { std::swap(m_value, rhs.m_value); }
  61. // Observers
  62. bool has_value() const noexcept { return m_value != nullptr; }
  63. std::type_info const& type() const noexcept { return m_value ? m_value->type() : typeid(void); }
  64. private:
  65. struct ValueBase {
  66. virtual ~ValueBase() noexcept { }
  67. virtual std::type_info const& type() const noexcept = 0;
  68. virtual std::unique_ptr<ValueBase> copy() const = 0;
  69. };
  70. template<typename T>
  71. struct Value : ValueBase {
  72. T value;
  73. template<typename U> Value(U&& v) : value(std::forward<U>(v)) { }
  74. std::type_info const& type() const noexcept override { return typeid(T); }
  75. std::unique_ptr<ValueBase> copy() const override
  76. {
  77. return std::make_unique<Value<T>>(value);
  78. }
  79. };
  80. std::unique_ptr<ValueBase> m_value;
  81. template<typename T>
  82. friend const T* any_cast(const Any* operand) noexcept;
  83. template<typename T>
  84. friend T* any_cast(Any* operand) noexcept;
  85. template<typename T>
  86. const T* cast() const noexcept
  87. {
  88. return &static_cast<Value<T>*>(m_value.get())->value;
  89. }
  90. template<typename T>
  91. T* cast() noexcept
  92. {
  93. return &static_cast<Value<T>*>(m_value.get())->value;
  94. }
  95. };
  96. template<typename T>
  97. T any_cast(Any const& value)
  98. {
  99. auto ptr = any_cast<typename std::add_const<typename std::remove_reference<T>::type>::type>(&value);
  100. if (!ptr)
  101. throw bad_cast();
  102. return *ptr;
  103. }
  104. template<typename T>
  105. T any_cast(Any& value)
  106. {
  107. auto ptr = any_cast<typename std::remove_reference<T>::type>(&value);
  108. if (!ptr)
  109. throw bad_cast();
  110. return *ptr;
  111. }
  112. template<typename T>
  113. T any_cast(Any&& value)
  114. {
  115. auto ptr = any_cast<typename std::remove_reference<T>::type>(&value);
  116. if (!ptr)
  117. throw bad_cast();
  118. return std::move(*ptr);
  119. }
  120. template<typename T>
  121. T* any_cast(Any* value) noexcept
  122. {
  123. return value && value->type() == typeid(T) ? value->cast<T>() : nullptr;
  124. }
  125. template<typename T>
  126. const T* any_cast(const Any* value) noexcept
  127. {
  128. return value && value->type() == typeid(T) ? value->cast<T>() : nullptr;
  129. }
  130. } // namespace util
  131. } // namespace realm
  132. namespace std {
  133. inline void swap(realm::util::Any& lhs, realm::util::Any& rhs) noexcept
  134. {
  135. lhs.swap(rhs);
  136. }
  137. } // namespace std
  138. #endif // REALM_UTIL_ANY_HPP