| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- // Copyright 2019 Google LLC
- //
- // 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
- //
- // https://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 dap_any_h
- #define dap_any_h
- #include "typeinfo.h"
- #include <assert.h>
- #include <stdint.h>
- namespace dap {
- template <typename T>
- struct TypeOf;
- class Deserializer;
- class Serializer;
- // any provides a type-safe container for values of any of dap type (boolean,
- // integer, number, array, variant, any, null, dap-structs).
- class any {
- public:
- // constructors
- inline any() = default;
- inline any(const any& other) noexcept;
- inline any(any&& other) noexcept;
- template <typename T>
- inline any(const T& val);
- // destructors
- inline ~any();
- // replaces the contained value with a null.
- inline void reset();
- // assignment
- inline any& operator=(const any& rhs);
- inline any& operator=(any&& rhs) noexcept;
- template <typename T>
- inline any& operator=(const T& val);
- inline any& operator=(const std::nullptr_t& val);
- // get() returns the contained value of the type T.
- // If the any does not contain a value of type T, then get() will assert.
- template <typename T>
- inline T& get() const;
- // is() returns true iff the contained value is of type T.
- template <typename T>
- inline bool is() const;
- private:
- friend class Deserializer;
- friend class Serializer;
- static inline void* alignUp(void* val, size_t alignment);
- inline void alloc(size_t size, size_t align);
- inline void free();
- inline bool isInBuffer(void* ptr) const;
- void* value = nullptr;
- const TypeInfo* type = nullptr;
- void* heap = nullptr; // heap allocation
- uint8_t buffer[32]; // or internal allocation
- };
- inline any::~any() {
- reset();
- }
- template <typename T>
- inline any::any(const T& val) {
- *this = val;
- }
- any::any(const any& other) noexcept : type(other.type) {
- if (other.value != nullptr) {
- alloc(type->size(), type->alignment());
- type->copyConstruct(value, other.value);
- }
- }
- any::any(any&& other) noexcept : type(other.type) {
- if (other.isInBuffer(other.value)) {
- alloc(type->size(), type->alignment());
- type->copyConstruct(value, other.value);
- } else {
- value = other.value;
- }
- other.value = nullptr;
- other.type = nullptr;
- }
- void any::reset() {
- if (value != nullptr) {
- type->destruct(value);
- free();
- }
- value = nullptr;
- type = nullptr;
- }
- any& any::operator=(const any& rhs) {
- reset();
- type = rhs.type;
- if (rhs.value != nullptr) {
- alloc(type->size(), type->alignment());
- type->copyConstruct(value, rhs.value);
- }
- return *this;
- }
- any& any::operator=(any&& rhs) noexcept {
- reset();
- type = rhs.type;
- if (rhs.isInBuffer(rhs.value)) {
- alloc(type->size(), type->alignment());
- type->copyConstruct(value, rhs.value);
- } else {
- value = rhs.value;
- }
- rhs.value = nullptr;
- rhs.type = nullptr;
- return *this;
- }
- template <typename T>
- any& any::operator=(const T& val) {
- if (!is<T>()) {
- reset();
- type = TypeOf<T>::type();
- alloc(type->size(), type->alignment());
- type->copyConstruct(value, &val);
- } else {
- #ifdef __clang_analyzer__
- assert(value != nullptr);
- #endif
- *reinterpret_cast<T*>(value) = val;
- }
- return *this;
- }
- any& any::operator=(const std::nullptr_t&) {
- reset();
- return *this;
- }
- template <typename T>
- T& any::get() const {
- static_assert(!std::is_same<T, std::nullptr_t>::value,
- "Cannot get nullptr from 'any'.");
- assert(is<T>());
- return *reinterpret_cast<T*>(value);
- }
- template <typename T>
- bool any::is() const {
- return type == TypeOf<T>::type();
- }
- template <>
- inline bool any::is<std::nullptr_t>() const {
- return value == nullptr;
- }
- void* any::alignUp(void* val, size_t alignment) {
- auto ptr = reinterpret_cast<uintptr_t>(val);
- return reinterpret_cast<void*>(alignment *
- ((ptr + alignment - 1) / alignment));
- }
- void any::alloc(size_t size, size_t align) {
- assert(value == nullptr);
- value = alignUp(buffer, align);
- if (isInBuffer(reinterpret_cast<uint8_t*>(value) + size - 1)) {
- return;
- }
- heap = new uint8_t[size + align];
- value = alignUp(heap, align);
- }
- void any::free() {
- assert(value != nullptr);
- if (heap != nullptr) {
- delete[] reinterpret_cast<uint8_t*>(heap);
- heap = nullptr;
- }
- value = nullptr;
- }
- bool any::isInBuffer(void* ptr) const {
- auto addr = reinterpret_cast<uintptr_t>(ptr);
- return addr >= reinterpret_cast<uintptr_t>(buffer) &&
- addr < reinterpret_cast<uintptr_t>(buffer + sizeof(buffer));
- }
- } // namespace dap
- #endif // dap_any_h
|