Advertisement
Guest User

any.h

a guest
Nov 15th, 2022
146
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.08 KB | None | 0 0
  1. #pragma once
  2.  
  3. #include <cstddef>
  4. #include <cstring>
  5. #include <typeinfo>
  6. #include <new>
  7. #include <utility>
  8.  
  9. template<std::size_t STORAGE_SIZE> class Any {
  10.     typedef void (*CopyFunc)(void *dst, const void *src);
  11.     typedef void (*MoveFunc)(void *dst, void *src);
  12.     typedef void(*DestroyFunc)(void *val);
  13.    
  14.     struct Operations {
  15.         const std::type_info &typeInfo;
  16.         std::size_t size;
  17.         std::size_t align;
  18.         CopyFunc copy;
  19.         MoveFunc move;
  20.         DestroyFunc destroy;
  21.     };
  22.    
  23.     template<typename T> static inline constexpr Operations OPERATIONS = {
  24.             .typeInfo = typeid(T),
  25.             .size = ([]() {
  26.                 if constexpr (std::is_same_v<T, void>) {
  27.                     return 0;
  28.                 } else {
  29.                     return sizeof(T);
  30.                 }
  31.             })(),
  32.             .align = ([]() {
  33.                 if constexpr (std::is_same_v<T, void>) {
  34.                     return 0;
  35.                 } else {
  36.                     return alignof(T);
  37.                 }
  38.             })(),
  39.             .copy = ([]() {
  40.                 if constexpr (std::is_same_v<T, void> || std::is_trivially_copy_constructible_v<T>) {
  41.                     return nullptr;
  42.                 } else {
  43.                     return static_cast<CopyFunc>([](void *dst, const void *src) {
  44.                         new (dst) T(*reinterpret_cast<const T*>(src));
  45.                     });
  46.                 }
  47.             })(),
  48.             .move = ([]() {
  49.                 if constexpr (std::is_same_v<T, void> || std::is_trivially_move_constructible_v<T>) {
  50.                     return nullptr;
  51.                 } else {
  52.                     return static_cast<MoveFunc>([](void *dst, void *src) {
  53.                         new (dst) T(std::move(*reinterpret_cast<T*>(src)));
  54.                     });
  55.                 }
  56.             })(),
  57.             .destroy = ([]() {
  58.                 if constexpr (std::is_same_v<T, void> || std::is_trivially_destructible_v<T>) {
  59.                     return nullptr;
  60.                 } else {
  61.                     return static_cast<DestroyFunc>([](void *arg) {
  62.                         reinterpret_cast<T*>(arg)->~T();
  63.                     });
  64.                 }
  65.             })()
  66.     };
  67.    
  68.     std::size_t m_storage[(STORAGE_SIZE + sizeof(std::size_t) - 1) / sizeof(std::size_t)];
  69.     void *m_heapStorage = nullptr;
  70.     const Operations *m_operations = &OPERATIONS<void>;
  71.  
  72. public:
  73.     Any() = default;
  74.    
  75.     template<typename T> Any(const T &value) {
  76.         if constexpr (sizeof(T) > sizeof(m_storage) || alignof(T) > alignof(std::size_t)) {
  77.             m_heapStorage = new T(value);
  78.         } else {
  79.             new (m_storage) T(value);
  80.         }
  81.         m_operations = &OPERATIONS<T>;
  82.     }
  83.    
  84.     template<typename T> Any(T &&value) noexcept {
  85.         if constexpr (sizeof(T) > sizeof(m_storage) || alignof(T) > alignof(std::size_t)) {
  86.             m_heapStorage = new T(std::move(value));
  87.         } else {
  88.             new (m_storage) T(std::move(value));
  89.         }
  90.         m_operations = &OPERATIONS<T>;
  91.     }
  92.    
  93.     template<std::size_t N> Any(const Any<N> &value) {
  94.         if (value.m_heapStorage || value.m_operations->size > sizeof(m_storage)) {
  95.             m_heapStorage = new (std::align_val_t(value.m_operations->align)) char[value.m_operations->size];
  96.             if (value.m_operations) {
  97.                 value.m_operations->copy(m_heapStorage, value.m_heapStorage ? value.m_heapStorage : value.m_storage);
  98.             } else {
  99.                 std::memcpy(
  100.                         m_heapStorage,
  101.                         value.m_heapStorage ? value.m_heapStorage : value.m_storage,
  102.                         value.m_operations->size
  103.                 );
  104.             }
  105.         } else {
  106.             if (value.m_operations->copy) {
  107.                 value.m_operations->copy(m_storage, value.m_storage);
  108.             } else {
  109.                 std::memcpy(m_storage, value.m_storage, value.m_operations->size);
  110.             }
  111.         }
  112.         m_operations = value.m_operations;
  113.     }
  114.    
  115.     template<std::size_t N> Any(Any<N> &&value) noexcept {
  116.         m_operations = value.m_operations;
  117.         if (value.m_heapStorage) {
  118.             m_heapStorage = value.m_heapStorage;
  119.             value.m_heapStorage = nullptr;
  120.             value.m_operations = &OPERATIONS<void>;
  121.         } else {
  122.             if (value.m_operations->size > STORAGE_SIZE) {
  123.                 m_heapStorage = new (std::align_val_t(value.m_operations->align)) char[value.m_operations->size];
  124.             }
  125.             if (m_operations->move) {
  126.                 m_operations->move(m_heapStorage ? m_heapStorage : m_storage, value.m_storage);
  127.             } else {
  128.                 std::memcpy(m_heapStorage ? m_heapStorage : m_storage, value.m_storage, value.m_operations->size);
  129.             }
  130.         }
  131.     }
  132.    
  133.     ~Any() {
  134.         if (m_operations->destroy) {
  135.             m_operations->destroy(m_heapStorage ? m_heapStorage : m_storage);
  136.         }
  137.         if (m_heapStorage) {
  138.             delete static_cast<char*>(m_heapStorage);
  139.         }
  140.     }
  141.    
  142.     [[nodiscard]] const std::type_info &type() const {
  143.         return m_operations->typeInfo;
  144.     }
  145.    
  146.     [[nodiscard]] std::size_t size() const {
  147.         return m_operations->size;
  148.     }
  149.    
  150.     [[nodiscard]] std::size_t align() const {
  151.         return m_operations->align;
  152.     }
  153.    
  154.     [[nodiscard]] bool isHeapAllocated() const {
  155.         return m_heapStorage != nullptr;
  156.     }
  157.    
  158.     template<typename T> [[nodiscard]] const T *get() const {
  159.         if (m_operations->typeInfo == typeid(T)) {
  160.             return reinterpret_cast<const T*>(m_heapStorage ? m_heapStorage : m_storage);
  161.         } else {
  162.             return nullptr;
  163.         }
  164.     }
  165.    
  166.     template<typename T> [[nodiscard]] T *get() {
  167.         if (m_operations->typeInfo == typeid(T)) {
  168.             return reinterpret_cast<T*>(m_heapStorage ? m_heapStorage : m_storage);
  169.         } else {
  170.             return nullptr;
  171.         }
  172.     }
  173.    
  174.     void clear() {
  175.         if (m_operations->destroy) {
  176.             m_operations->destroy(m_heapStorage ? m_heapStorage : m_storage);
  177.         }
  178.         if (m_heapStorage) {
  179.             delete static_cast<char*>(m_heapStorage);
  180.             m_heapStorage = nullptr;
  181.         }
  182.         m_operations = &OPERATIONS<void>;
  183.     }
  184.    
  185.     template<typename T, typename... Args> void emplace(Args &&...args) {
  186.         clear();
  187.         if constexpr (sizeof(T) > sizeof(m_storage) || alignof(T) > alignof(std::size_t)) {
  188.             m_heapStorage = new T(std::forward<Args...>(args)...);
  189.         } else {
  190.             new (m_storage) T(std::forward<Args...>(args)...);
  191.         }
  192.         m_operations = &OPERATIONS<T>;
  193.     }
  194.    
  195.     template<std::size_t N> Any<STORAGE_SIZE> &operator=(const Any<N> &value) {
  196.         clear();
  197.         if (value.m_heapStorage || value.m_operations->size > sizeof(m_storage)) {
  198.             m_heapStorage = new (std::align_val_t(value.m_operations->align)) char[value.m_operations->size];
  199.             if (value.m_operations) {
  200.                 value.m_operations->copy(m_heapStorage, value.m_heapStorage ? value.m_heapStorage : value.m_storage);
  201.             } else {
  202.                 std::memcpy(
  203.                         m_heapStorage,
  204.                         value.m_heapStorage ? value.m_heapStorage : value.m_storage,
  205.                         value.m_operations->size
  206.                 );
  207.             }
  208.         } else {
  209.             if (value.m_operations->copy) {
  210.                 value.m_operations->copy(m_storage, value.m_storage);
  211.             } else {
  212.                 std::memcpy(m_storage, value.m_storage, value.m_operations->size);
  213.             }
  214.         }
  215.         m_operations = value.m_operations;
  216.         return *this;
  217.     }
  218.    
  219.     template<std::size_t N> Any<STORAGE_SIZE> &operator=(Any<N> &&value) noexcept {
  220.         clear();
  221.         m_operations = value.m_operations;
  222.         if (value.m_heapStorage) {
  223.             m_heapStorage = value.m_heapStorage;
  224.             value.m_heapStorage = nullptr;
  225.             value.m_operations = &OPERATIONS<void>;
  226.         } else {
  227.             if (value.m_operations->size > STORAGE_SIZE) {
  228.                 m_heapStorage = new (std::align_val_t(value.m_operations->align)) char[value.m_operations->size];
  229.             }
  230.             if (m_operations->move) {
  231.                 m_operations->move(m_heapStorage ? m_heapStorage : m_storage, value.m_storage);
  232.             } else {
  233.                 std::memcpy(m_heapStorage ? m_heapStorage : m_storage, value.m_storage, value.m_operations->size);
  234.             }
  235.         }
  236.         return *this;
  237.     }
  238.    
  239.     template<typename T> Any &operator=(T &&value) noexcept {
  240.         using TT = typename std::decay<T>::type;
  241.         emplace<TT>(std::forward<T>(value));
  242.         return *this;
  243.     }
  244. };
  245.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement