Started `util::maybe_uninit<T>`.

Added `assume_init()`, added explicit creation via explicitly named static methods move and in-place object construction

Fortune for libexopt's current commit: Future blessing − 末吉
boxed_is_boxed_value
Avril 2 years ago
parent 399ba10c25
commit d4e45000bd
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -100,4 +100,97 @@ namespace exopt { namespace util [[gnu::visibility("internal")]] {
} }
__builtin_unreachable(); __builtin_unreachable();
} }
// Returns an anonymous union with inavtive field: `T value` and active field `assume init` (no unique address).
template<typename T> requires(!std::is_reference_v<T>)
constexpr auto uninit() noexcept {
union UI {
struct assume{};
T value;
[[no_unique_address]] assume init{};
};
return UI{};
}
template<typename T> requires(!std::is_reference_v<T>)
struct alignas(T) maybe_uninit {
using uninit = std::array<unsigned char, sizeof(T)>;
constexpr maybe_uninit() noexcept {}
constexpr maybe_uninit(const maybe_uninit& c) noexcept
: m_uninit(c.m_uninit) {}
constexpr maybe_uninit(maybe_uninit&& m) noexcept
: m_uninit(std::move(m.m_uninit)) {}
constexpr maybe_uninit& operator=(maybe_uninit const& c) noexcept
{ m_uninit = c.m_uninit; return *this; }
constexpr maybe_uninit& operator=(maybe_uninit&& c) noexcept
{ m_uninit = std::move(c.m_uninit); return *this; }
constexpr T& operator=(T&& value) noexcept {
m_init = std::move(value);
}
constexpr T& operator=(T const& copy) noexcept {
m_init = maybe_uninit{copy};
}
constexpr T& assume_init() & noexcept = delete;
constexpr T&& assume_init() && noexcept { return std::move(m_init); }
constexpr T const& assume_init() const& noexcept { return m_init; }
constexpr T const&& assume_init() const&& noexcept { return m_init; }
constexpr uninit& data() &noexcept { return m_uninit; }
constexpr uninit&& data() &&noexcept { return std::move(m_uninit); }
constexpr uninit const& data() const&noexcept { return m_uninit; }
constexpr uninit const&& data() const&& noexcept { return std::move(m_uninit); }
constexpr T* get() noexcept { return std::addressof(m_init); }
constexpr const T* get() const noexcept { return std::addressof(m_init); }
//TODO: accessors, `assume_init_*()`, etc.
constexpr ~maybe_uninit() noexcept {}
constexpr void assume_init_drop() noexcept(std::is_nothrow_destructible_v<T>)
{ m_init.~T(); }
constexpr maybe_uninit<T> init(T&& value) noexcept(std::is_nothrow_move_constructible_v<T>)
{ return maybe_uninit<T>{std::move(value), EXPLICIT_INIT_TAG<EXPLICIT_INIT_MOVE>{}}; }
template<typename... Args> requires(std::is_constructible_v<T, Args...>)
constexpr maybe_uninit<T> init_in_place(Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args...>)
{ return maybe_uninit<T>{EXPLICIT_INIT_TAG<EXPLICIT_INIT_IN_PLACE>{}, std::forward<Args>(args)...}; }
private:
enum EXPLICIT_INIT_TYPE {
EXPLICIT_INIT_IN_PLACE,
EXPLICIT_INIT_MOVE,
};
template<EXPLICIT_INIT_TYPE>
struct EXPLICIT_INIT_TAG {};
constexpr maybe_uninit(T&& value, EXPLICIT_INIT_TAG<EXPLICIT_INIT_MOVE>) noexcept(std::is_nothrow_move_constructible_v<T>)
: m_init{std::move(value)} {}
template<typename... Args> requires(std::is_constructible_v<T, Args...>)
constexpr maybe_uninit(EXPLICIT_INIT_TAG<EXPLICIT_INIT_IN_PLACE> _a, Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args...>)
: m_init{std::forward<Args>(args)...} { (void) _a; }
union {
T m_init;
[[no_unique_address]] alignas(T) uninit m_uninit{};
};
};
namespace {
constexpr std::string_view ui_test() noexcept {
auto ui = uninit<std::string_view>();
maybe_uninit<std::string_view> mi;
ui.init.~assume();
ui.value = std::string_view{"Hello"};
return std::move(ui.value);
}
static_assert(ui_test()[0] == 'H', "Bad uninit<T>()");
}
} } } }

Loading…
Cancel
Save