Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #pragma once
- #include <cstddef>
- #include <cstring>
- #include <typeinfo>
- #include <utility>
- struct Any_tag {
- };
- template<std::size_t STORAGE_SIZE> class Any: Any_tag {
- typedef void *(*AllocFunc)();
- typedef void (*CopyFunc)(void *dst, const void *src);
- typedef void (*MoveFunc)(void *dst, void *src);
- typedef void (*DestroyFunc)(void *val);
- typedef void (*FreeFunc)(void *val);
- struct Operations {
- const std::type_info &typeInfo;
- std::size_t size;
- std::size_t align;
- AllocFunc alloc;
- CopyFunc copy;
- MoveFunc move;
- DestroyFunc destroy;
- FreeFunc free;
- };
- template<typename T> static inline constexpr Operations OPERATIONS = {
- .typeInfo = typeid(T),
- .size = ([]() {
- if constexpr (std::is_same_v<T, void>) {
- return 0;
- } else {
- return sizeof(T);
- }
- })(),
- .align = ([]() {
- if constexpr (std::is_same_v<T, void>) {
- return 0;
- } else {
- return alignof(T);
- }
- })(),
- .alloc = []() -> void* {
- if constexpr (std::is_same_v<T, void>) {
- return nullptr;
- } else {
- return new std::aligned_storage<sizeof(T), alignof(T)>;
- }
- },
- .copy = ([]() {
- if constexpr (std::is_same_v<T, void> || std::is_trivially_copy_constructible_v<T>) {
- return nullptr;
- } else {
- return static_cast<CopyFunc>([](void *dst, const void *src) {
- new (dst) T(*reinterpret_cast<const T*>(src));
- });
- }
- })(),
- .move = ([]() {
- if constexpr (std::is_same_v<T, void> || std::is_trivially_move_constructible_v<T>) {
- return nullptr;
- } else {
- return static_cast<MoveFunc>([](void *dst, void *src) {
- new (dst) T(std::move(*reinterpret_cast<T*>(src)));
- });
- }
- })(),
- .destroy = ([]() {
- if constexpr (std::is_same_v<T, void> || std::is_trivially_destructible_v<T>) {
- return nullptr;
- } else {
- return static_cast<DestroyFunc>([](void *arg) {
- (reinterpret_cast<T*>(arg))->~T();
- });
- }
- })(),
- .free = [](void *arg) {
- if constexpr (!std::is_same_v<T, void>) {
- delete reinterpret_cast<T*>(arg);
- }
- }
- };
- std::size_t m_storage[(STORAGE_SIZE + sizeof(std::size_t) - 1) / sizeof(std::size_t)];
- char *m_heapStorage = nullptr;
- const Operations *m_operations = &OPERATIONS<void>;
- template<std::size_t N> friend class Any;
- [[nodiscard]] const void *storage() const {
- return m_heapStorage ? m_heapStorage : reinterpret_cast<const char*>(m_storage);
- }
- [[nodiscard]] void *storage() {
- return m_heapStorage ? m_heapStorage : reinterpret_cast<char*>(m_storage);
- }
- public:
- Any() = default;
- template<std::size_t N> Any(const Any<N> &value) {
- if (value.m_heapStorage || value.m_operations->size > sizeof(m_storage)) {
- m_heapStorage = reinterpret_cast<char*>(value.m_operations->alloc());
- }
- if (value.m_operations->copy) {
- value.m_operations->copy(storage(), value.storage());
- } else {
- std::memcpy(storage(), value.storage(), value.m_operations->size);
- }
- m_operations = reinterpret_cast<const Operations*>(value.m_operations);
- }
- template<std::size_t N> Any(Any<N> &&value) noexcept {
- m_operations = reinterpret_cast<const Operations*>(value.m_operations);
- if (value.m_heapStorage) {
- m_heapStorage = value.m_heapStorage;
- value.m_heapStorage = nullptr;
- value.m_operations = &OPERATIONS<void>;
- } else {
- if (value.m_operations->size > STORAGE_SIZE) {
- m_heapStorage = reinterpret_cast<char*>(value.m_operations->alloc());
- }
- if (m_operations->move) {
- m_operations->move(storage(), value.storage());
- } else {
- std::memcpy(storage(), value.storage(), value.m_operations->size);
- }
- }
- }
- template<typename T> Any(T &&value) requires (!std::is_base_of_v<Any_tag, typename std::remove_reference<T>::type>) {
- using TT = typename std::remove_reference<T>::type;
- if constexpr (sizeof(TT) > sizeof(m_storage) || alignof(TT) > alignof(std::size_t)) {
- m_heapStorage = reinterpret_cast<char*>(new TT(std::forward<T>(value)));
- } else {
- new (m_storage) TT(std::forward<T>(value));
- }
- m_operations = &OPERATIONS<TT>;
- }
- ~Any() {
- if (!m_heapStorage) {
- if (m_operations->destroy) {
- m_operations->destroy(storage());
- }
- } else {
- m_operations->free(m_heapStorage);
- }
- }
- [[nodiscard]] const std::type_info &type() const {
- return m_operations->typeInfo;
- }
- [[nodiscard]] std::size_t size() const {
- return m_operations->size;
- }
- [[nodiscard]] std::size_t align() const {
- return m_operations->align;
- }
- [[nodiscard]] bool isHeapAllocated() const {
- return m_heapStorage != nullptr;
- }
- template<typename T> [[nodiscard]] const T *get() const {
- if (m_operations->typeInfo == typeid(T)) {
- return reinterpret_cast<const T*>(storage());
- } else {
- return nullptr;
- }
- }
- template<typename T> [[nodiscard]] T *get() {
- if (m_operations->typeInfo == typeid(T)) {
- return reinterpret_cast<T*>(storage());
- } else {
- return nullptr;
- }
- }
- void clear() {
- if (!m_heapStorage) {
- if (m_operations->destroy) {
- m_operations->destroy(storage());
- }
- } else {
- m_operations->free(m_heapStorage);
- m_heapStorage = nullptr;
- }
- m_operations = &OPERATIONS<void>;
- }
- template<typename T, typename... Args> void emplace(Args &&...args) {
- clear();
- if constexpr (sizeof(T) > sizeof(m_storage) || alignof(T) > alignof(std::size_t)) {
- m_heapStorage = reinterpret_cast<char*>(new T(std::forward<Args...>(args)...));
- } else {
- new (m_storage) T(std::forward<Args...>(args)...);
- }
- m_operations = &OPERATIONS<T>;
- }
- template<std::size_t N> Any<STORAGE_SIZE> &operator=(const Any<N> &value) {
- clear();
- if (value.m_heapStorage || value.m_operations->size > sizeof(m_storage)) {
- m_heapStorage = value.m_operations->alloc();
- }
- if (value.m_operations) {
- value.m_operations->copy(storage(), value.storage());
- } else {
- std::memcpy(storage(), value.storage(), value.m_operations->size);
- }
- m_operations = value.m_operations;
- return *this;
- }
- template<std::size_t N> Any<STORAGE_SIZE> &operator=(Any<N> &&value) noexcept {
- clear();
- m_operations = value.m_operations;
- if (value.m_heapStorage) {
- m_heapStorage = value.m_heapStorage;
- value.m_heapStorage = nullptr;
- value.m_operations = &OPERATIONS<void>;
- } else {
- if (value.m_operations->size > STORAGE_SIZE) {
- m_heapStorage = value.m_operations->alloc();
- }
- if (m_operations->move) {
- m_operations->move(storage(), value.storage());
- } else {
- std::memcpy(storage(), value.storage(), value.m_operations->size);
- }
- }
- return *this;
- }
- template<typename T> Any &operator=(T &&value) {
- using TT = typename std::remove_reference<T>::type;
- emplace<TT>(std::forward<T>(value));
- return *this;
- }
- };
Advertisement
Add Comment
Please, Sign In to add comment