Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #pragma once
- #include <cstddef>
- #include <cstring>
- #include <typeinfo>
- #include <new>
- #include <utility>
- template<std::size_t STORAGE_SIZE> class Any {
- typedef void (*CopyFunc)(void *dst, const void *src);
- typedef void (*MoveFunc)(void *dst, void *src);
- typedef void(*DestroyFunc)(void *val);
- struct Operations {
- const std::type_info &typeInfo;
- std::size_t size;
- std::size_t align;
- CopyFunc copy;
- MoveFunc move;
- DestroyFunc destroy;
- };
- 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);
- }
- })(),
- .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();
- });
- }
- })()
- };
- std::size_t m_storage[(STORAGE_SIZE + sizeof(std::size_t) - 1) / sizeof(std::size_t)];
- void *m_heapStorage = nullptr;
- const Operations *m_operations = &OPERATIONS<void>;
- public:
- Any() = default;
- template<typename T> Any(const T &value) {
- if constexpr (sizeof(T) > sizeof(m_storage) || alignof(T) > alignof(std::size_t)) {
- m_heapStorage = new T(value);
- } else {
- new (m_storage) T(value);
- }
- m_operations = &OPERATIONS<T>;
- }
- template<typename T> Any(T &&value) noexcept {
- if constexpr (sizeof(T) > sizeof(m_storage) || alignof(T) > alignof(std::size_t)) {
- m_heapStorage = new T(std::move(value));
- } else {
- new (m_storage) T(std::move(value));
- }
- m_operations = &OPERATIONS<T>;
- }
- template<std::size_t N> Any(const Any<N> &value) {
- if (value.m_heapStorage || value.m_operations->size > sizeof(m_storage)) {
- m_heapStorage = new (std::align_val_t(value.m_operations->align)) char[value.m_operations->size];
- if (value.m_operations) {
- value.m_operations->copy(m_heapStorage, value.m_heapStorage ? value.m_heapStorage : value.m_storage);
- } else {
- std::memcpy(
- m_heapStorage,
- value.m_heapStorage ? value.m_heapStorage : value.m_storage,
- value.m_operations->size
- );
- }
- } else {
- if (value.m_operations->copy) {
- value.m_operations->copy(m_storage, value.m_storage);
- } else {
- std::memcpy(m_storage, value.m_storage, value.m_operations->size);
- }
- }
- m_operations = value.m_operations;
- }
- template<std::size_t N> Any(Any<N> &&value) noexcept {
- 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 = new (std::align_val_t(value.m_operations->align)) char[value.m_operations->size];
- }
- if (m_operations->move) {
- m_operations->move(m_heapStorage ? m_heapStorage : m_storage, value.m_storage);
- } else {
- std::memcpy(m_heapStorage ? m_heapStorage : m_storage, value.m_storage, value.m_operations->size);
- }
- }
- }
- ~Any() {
- if (m_operations->destroy) {
- m_operations->destroy(m_heapStorage ? m_heapStorage : m_storage);
- }
- if (m_heapStorage) {
- delete static_cast<char*>(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*>(m_heapStorage ? m_heapStorage : m_storage);
- } else {
- return nullptr;
- }
- }
- template<typename T> [[nodiscard]] T *get() {
- if (m_operations->typeInfo == typeid(T)) {
- return reinterpret_cast<T*>(m_heapStorage ? m_heapStorage : m_storage);
- } else {
- return nullptr;
- }
- }
- void clear() {
- if (m_operations->destroy) {
- m_operations->destroy(m_heapStorage ? m_heapStorage : m_storage);
- }
- if (m_heapStorage) {
- delete static_cast<char*>(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 = 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 = new (std::align_val_t(value.m_operations->align)) char[value.m_operations->size];
- if (value.m_operations) {
- value.m_operations->copy(m_heapStorage, value.m_heapStorage ? value.m_heapStorage : value.m_storage);
- } else {
- std::memcpy(
- m_heapStorage,
- value.m_heapStorage ? value.m_heapStorage : value.m_storage,
- value.m_operations->size
- );
- }
- } else {
- if (value.m_operations->copy) {
- value.m_operations->copy(m_storage, value.m_storage);
- } else {
- std::memcpy(m_storage, value.m_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 = new (std::align_val_t(value.m_operations->align)) char[value.m_operations->size];
- }
- if (m_operations->move) {
- m_operations->move(m_heapStorage ? m_heapStorage : m_storage, value.m_storage);
- } else {
- std::memcpy(m_heapStorage ? m_heapStorage : m_storage, value.m_storage, value.m_operations->size);
- }
- }
- return *this;
- }
- template<typename T> Any &operator=(T &&value) noexcept {
- using TT = typename std::decay<T>::type;
- emplace<TT>(std::forward<T>(value));
- return *this;
- }
- };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement