1
0

any.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. // Copyright 2019 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // https://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #ifndef dap_any_h
  15. #define dap_any_h
  16. #include "typeinfo.h"
  17. #include <assert.h>
  18. #include <stdint.h>
  19. namespace dap {
  20. template <typename T>
  21. struct TypeOf;
  22. class Deserializer;
  23. class Serializer;
  24. // any provides a type-safe container for values of any of dap type (boolean,
  25. // integer, number, array, variant, any, null, dap-structs).
  26. class any {
  27. public:
  28. // constructors
  29. inline any() = default;
  30. inline any(const any& other) noexcept;
  31. inline any(any&& other) noexcept;
  32. template <typename T>
  33. inline any(const T& val);
  34. // destructors
  35. inline ~any();
  36. // replaces the contained value with a null.
  37. inline void reset();
  38. // assignment
  39. inline any& operator=(const any& rhs);
  40. inline any& operator=(any&& rhs) noexcept;
  41. template <typename T>
  42. inline any& operator=(const T& val);
  43. inline any& operator=(const std::nullptr_t& val);
  44. // get() returns the contained value of the type T.
  45. // If the any does not contain a value of type T, then get() will assert.
  46. template <typename T>
  47. inline T& get() const;
  48. // is() returns true iff the contained value is of type T.
  49. template <typename T>
  50. inline bool is() const;
  51. private:
  52. friend class Deserializer;
  53. friend class Serializer;
  54. static inline void* alignUp(void* val, size_t alignment);
  55. inline void alloc(size_t size, size_t align);
  56. inline void free();
  57. inline bool isInBuffer(void* ptr) const;
  58. void* value = nullptr;
  59. const TypeInfo* type = nullptr;
  60. void* heap = nullptr; // heap allocation
  61. uint8_t buffer[32]; // or internal allocation
  62. };
  63. inline any::~any() {
  64. reset();
  65. }
  66. template <typename T>
  67. inline any::any(const T& val) {
  68. *this = val;
  69. }
  70. any::any(const any& other) noexcept : type(other.type) {
  71. if (other.value != nullptr) {
  72. alloc(type->size(), type->alignment());
  73. type->copyConstruct(value, other.value);
  74. }
  75. }
  76. any::any(any&& other) noexcept : type(other.type) {
  77. if (other.isInBuffer(other.value)) {
  78. alloc(type->size(), type->alignment());
  79. type->copyConstruct(value, other.value);
  80. } else {
  81. value = other.value;
  82. }
  83. other.value = nullptr;
  84. other.type = nullptr;
  85. }
  86. void any::reset() {
  87. if (value != nullptr) {
  88. type->destruct(value);
  89. free();
  90. }
  91. value = nullptr;
  92. type = nullptr;
  93. }
  94. any& any::operator=(const any& rhs) {
  95. reset();
  96. type = rhs.type;
  97. if (rhs.value != nullptr) {
  98. alloc(type->size(), type->alignment());
  99. type->copyConstruct(value, rhs.value);
  100. }
  101. return *this;
  102. }
  103. any& any::operator=(any&& rhs) noexcept {
  104. reset();
  105. type = rhs.type;
  106. if (rhs.isInBuffer(rhs.value)) {
  107. alloc(type->size(), type->alignment());
  108. type->copyConstruct(value, rhs.value);
  109. } else {
  110. value = rhs.value;
  111. }
  112. rhs.value = nullptr;
  113. rhs.type = nullptr;
  114. return *this;
  115. }
  116. template <typename T>
  117. any& any::operator=(const T& val) {
  118. if (!is<T>()) {
  119. reset();
  120. type = TypeOf<T>::type();
  121. alloc(type->size(), type->alignment());
  122. type->copyConstruct(value, &val);
  123. } else {
  124. #ifdef __clang_analyzer__
  125. assert(value != nullptr);
  126. #endif
  127. *reinterpret_cast<T*>(value) = val;
  128. }
  129. return *this;
  130. }
  131. any& any::operator=(const std::nullptr_t&) {
  132. reset();
  133. return *this;
  134. }
  135. template <typename T>
  136. T& any::get() const {
  137. static_assert(!std::is_same<T, std::nullptr_t>::value,
  138. "Cannot get nullptr from 'any'.");
  139. assert(is<T>());
  140. return *reinterpret_cast<T*>(value);
  141. }
  142. template <typename T>
  143. bool any::is() const {
  144. return type == TypeOf<T>::type();
  145. }
  146. template <>
  147. inline bool any::is<std::nullptr_t>() const {
  148. return value == nullptr;
  149. }
  150. void* any::alignUp(void* val, size_t alignment) {
  151. auto ptr = reinterpret_cast<uintptr_t>(val);
  152. return reinterpret_cast<void*>(alignment *
  153. ((ptr + alignment - 1) / alignment));
  154. }
  155. void any::alloc(size_t size, size_t align) {
  156. assert(value == nullptr);
  157. value = alignUp(buffer, align);
  158. if (isInBuffer(reinterpret_cast<uint8_t*>(value) + size - 1)) {
  159. return;
  160. }
  161. heap = new uint8_t[size + align];
  162. value = alignUp(heap, align);
  163. }
  164. void any::free() {
  165. assert(value != nullptr);
  166. if (heap != nullptr) {
  167. delete[] reinterpret_cast<uint8_t*>(heap);
  168. heap = nullptr;
  169. }
  170. value = nullptr;
  171. }
  172. bool any::isInBuffer(void* ptr) const {
  173. auto addr = reinterpret_cast<uintptr_t>(ptr);
  174. return addr >= reinterpret_cast<uintptr_t>(buffer) &&
  175. addr < reinterpret_cast<uintptr_t>(buffer + sizeof(buffer));
  176. }
  177. } // namespace dap
  178. #endif // dap_any_h