Skip to content

Instantly share code, notes, and snippets.

@schaumb
Created April 20, 2022 16:05
Show Gist options
  • Save schaumb/01aa44263df0d752b0617f39d9365c6d to your computer and use it in GitHub Desktop.
Save schaumb/01aa44263df0d752b0617f39d9365c6d to your computer and use it in GitHub Desktop.
make_temporary_for_overwrite, make_function_scoped_for_overwrite
#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