Created
April 20, 2022 16:05
-
-
Save schaumb/01aa44263df0d752b0617f39d9365c6d to your computer and use it in GitHub Desktop.
make_temporary_for_overwrite, make_function_scoped_for_overwrite
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <type_traits> | |
#if __has_include(<alloca.h>) | |
#include <alloca.h> | |
#else | |
#define alloca _alloca | |
#endif | |
namespace bxlx { | |
namespace detail { | |
template <typename T, typename = void> | |
[[maybe_unused]] constexpr static bool is_complete_v = false; | |
template <typename T> | |
[[maybe_unused]] constexpr static bool is_complete_v<T, std::enable_if_t<(sizeof(T) > 0)>> = true; | |
template<typename T, typename U = std::conditional_t<std::is_array_v<T>, T[1], T>> | |
class Wrapper; | |
template<typename T> | |
class Ptr; | |
template<typename T> | |
constexpr std::enable_if_t<is_complete_v<T>, T*> make_temporary_for_overwrite(detail::Wrapper<T>&& v = detail::Wrapper<T>()); | |
template<typename T, typename U = std::conditional_t<std::is_array_v<T>, T[1], T>> | |
std::enable_if_t<is_complete_v<T> && std::is_trivially_destructible_v<T>, T*> make_function_scoped_for_overwrite(Ptr<T>&& p); | |
template<typename V> | |
constexpr static void destroy_at(V* p) { | |
if constexpr (std::is_array_v<V>) | |
for (auto &elem : *p) | |
::bxlx::detail::destroy_at(std::addressof(elem)); | |
else | |
p->~V(); | |
} | |
template<typename T, typename U> | |
class Wrapper { | |
constexpr inline Wrapper() noexcept = default; | |
alignas(alignof(U)) unsigned char v[sizeof(U)]; | |
constexpr inline T* createNGet() { | |
return ::new (v) U; | |
} | |
friend constexpr inline std::enable_if_t<is_complete_v<T>, T*> make_temporary_for_overwrite<T>(detail::Wrapper<T>&&); | |
~Wrapper() { | |
auto p = std::launder(reinterpret_cast<T*>(v)); | |
::bxlx::detail::destroy_at(p); | |
::operator delete(p, v); | |
} | |
}; | |
template<typename T> | |
constexpr inline std::enable_if_t<is_complete_v<T>, T*> make_temporary_for_overwrite(detail::Wrapper<T>&& v) { | |
return v.createNGet(); | |
} | |
template<typename T> | |
constexpr std::enable_if_t<!is_complete_v<T>, T*> make_temporary_for_overwrite() = delete; | |
template<typename T> | |
class Ptr { | |
constexpr explicit inline Ptr(T* val) noexcept : val(val) {} | |
T* val; | |
template<typename U> | |
friend inline std::enable_if_t<is_complete_v<U> && std::is_trivially_destructible_v<U>, U*> make_function_scoped_for_overwrite(Ptr<U>&&); | |
}; | |
template<typename T, typename U> | |
inline std::enable_if_t<is_complete_v<T> && std::is_trivially_destructible_v<T>, T*> make_function_scoped_for_overwrite( | |
Ptr<T>&& p = Ptr<T>{new (alloca(sizeof(Wrapper<U>))) U} | |
) { | |
return p.val; | |
} | |
template<typename T> | |
constexpr std::enable_if_t<!std::is_trivially_destructible_v<T> || !is_complete_v<T>, T*> make_function_scoped_for_overwrite() = delete; | |
} // detail | |
using detail::make_temporary_for_overwrite; | |
using detail::make_function_scoped_for_overwrite; | |
} // bxlx |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment