Initial drop of cppdap
This commit is contained in:
182
include/dap/any.h
Normal file
182
include/dap/any.h
Normal file
@@ -0,0 +1,182 @@
|
||||
// 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>
|
||||
|
||||
namespace dap {
|
||||
|
||||
template <typename T>
|
||||
struct TypeOf;
|
||||
|
||||
// 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);
|
||||
|
||||
// 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:
|
||||
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 : value(other.value), type(other.type) {
|
||||
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 {
|
||||
value = rhs.value;
|
||||
type = rhs.type;
|
||||
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 {
|
||||
*reinterpret_cast<T*>(value) = val;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& any::get() const {
|
||||
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
|
||||
Reference in New Issue
Block a user