diff --git a/CMakeLists.txt b/CMakeLists.txt index a7ad98b..4391ec6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.5) include(cmake/color.cmake) -set(BLT_VERSION 0.14.15) +set(BLT_VERSION 0.15.0) set(BLT_TEST_VERSION 0.0.1) set(BLT_TARGET BLT) diff --git a/include/blt/std/any.h b/include/blt/std/any.h new file mode 100644 index 0000000..a626fc5 --- /dev/null +++ b/include/blt/std/any.h @@ -0,0 +1,199 @@ +#pragma once +/* + * Copyright (C) 2024 Brett Terpstra + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#ifndef BLT_ANY_H +#define BLT_ANY_H + +#include +#include + +namespace blt::unsafe +{ + class any_t_union + { + private: + static constexpr auto SIZE = sizeof(std::any); + + union variant_t + { + constexpr variant_t() + {} + + blt::u8 data[SIZE]{}; + std::any any; + + ~variant_t() + {} + }; + + variant_t variant; + bool has_any = false; + public: + any_t_union() = default; + + any_t_union(const any_t_union& copy) + { + if (copy.has_any) + { + variant.any = copy.variant.any; + has_any = true; + } else + { + std::memcpy(variant.data, copy.variant.data, SIZE); + } + } + + any_t_union(any_t_union&& move) noexcept + { + if (move.has_any) + { + variant.any = std::move(move.variant.any); + has_any = true; + } else + { + std::memcpy(variant.data, move.variant.data, SIZE); + } + } + + ~any_t_union() + { + if (has_any) + variant.any.~any(); + } + + template + any_t_union(T t) + { + if constexpr (sizeof(T) <= SIZE && std::is_trivially_copyable_v) + { + std::memcpy(variant.data, &t, sizeof(t)); + } else + { + variant.any = t; + has_any = true; + } + } + + any_t_union& operator=(const any_t_union& copy) + { + if (has_any) + variant.any.~any(); + if (copy.has_any) + { + std::memset(variant.data, 0, SIZE); + variant.any = copy.variant.any; + has_any = true; + } else + { + std::memcpy(variant.data, copy.variant.data, SIZE); + has_any = false; + } + return *this; + } + + any_t_union& operator=(any_t_union&& move) noexcept + { + if (has_any) + variant.any.~any(); + if (move.has_any) + { + std::memset(variant.data, 0, SIZE); + variant.any = std::move(move.variant.any); + has_any = true; + } else + { + std::memcpy(variant.data, move.variant.data, SIZE); + has_any = false; + } + return *this; + } + + template + any_t_union& operator=(T t) + { + if (has_any) + variant.any.~any(); + if constexpr (sizeof(T) <= SIZE && std::is_trivially_copyable_v) + { + std::memcpy(variant.data, &t, sizeof(t)); + has_any = false; + } else + { + std::memset(variant.data, 0, SIZE); + variant.any = std::move(t); + has_any = true; + } + return *this; + } + + template + T any_cast() + { + if constexpr (sizeof(T) <= SIZE && std::is_trivially_copyable_v) + { + if (!has_any) + { + T t; + std::memcpy(&t, variant.data, sizeof(T)); + return t; + } + } + return std::any_cast(variant.any); + } + }; + + template + class any_t_base + { + private: + blt::u8 data[SIZE]{}; + public: + any_t_base() = default; + + template + any_t_base(T t) + { + static_assert(std::is_trivially_copyable_v && "Type must be byte copyable"); + static_assert(sizeof(T) <= SIZE && "Size must be less than or equal to internal buffer"); + std::memcpy(data, &t, sizeof(t)); + } + + template + any_t_base& operator=(T t) + { + static_assert(std::is_trivially_copyable_v && "Type must be byte copyable"); + static_assert(sizeof(T) <= SIZE && "Size must be less than or equal to internal buffer"); + std::memcpy(data, &t, sizeof(t)); + } + + template + T any_cast() + { + static_assert(std::is_trivially_copyable_v && "Type must be byte copyable"); + static_assert(sizeof(T) <= SIZE && "Size must be less than or equal to internal buffer"); + T t; + std::memcpy(&t, data, sizeof(T)); + return t; + } + }; + + using any_t = any_t_base<8>; +} + +#endif //BLT_ANY_H