summaryrefslogtreecommitdiff
path: root/asl/types/maybe_uninit.hpp
blob: 3b2f75596feb6514145da16364932e12b218a585 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// Copyright 2025 Steven Le Rouzic
//
// SPDX-License-Identifier: BSD-3-Clause

#pragma once

#include "asl/base/meta.hpp"
#include "asl/base/utility.hpp"
#include "asl/memory/memory.hpp"

namespace asl
{

template<is_object T>
union maybe_uninit
{
private:
    T m_value;

public:
    constexpr maybe_uninit() requires trivially_default_constructible<T> = default;
    constexpr maybe_uninit() requires (!trivially_default_constructible<T>) {} // NOLINT

    explicit constexpr maybe_uninit(in_place_t, auto&&... args)
        requires constructible_from<T, decltype(args)...>
        : m_value{std::forward<decltype(args)>(args)...}
    {}

    constexpr maybe_uninit(const maybe_uninit&) requires trivially_copy_constructible<T> = default;
    constexpr maybe_uninit(const maybe_uninit&) requires (!trivially_copy_constructible<T>) {} // NOLINT

    constexpr maybe_uninit(maybe_uninit&&) requires trivially_move_constructible<T> = default;
    constexpr maybe_uninit(maybe_uninit&&) requires (!trivially_move_constructible<T>) {} // NOLINT

    constexpr maybe_uninit& operator=(const maybe_uninit&) requires trivially_copy_assignable<T> = default;
    constexpr maybe_uninit& operator=(const maybe_uninit&) requires (!trivially_copy_assignable<T>) { return *this; } // NOLINT

    constexpr maybe_uninit& operator=(maybe_uninit&&) requires trivially_move_assignable<T> = default;
    constexpr maybe_uninit& operator=(maybe_uninit&&) requires (!trivially_move_assignable<T>) { return *this; } // NOLINT

    constexpr ~maybe_uninit() requires trivially_destructible<T> = default;
    constexpr ~maybe_uninit() requires (!trivially_destructible<T>) {} // NOLINT

    // @Safety Value must not have been initialized yet
    constexpr void construct_unsafe(auto&&... args)
        requires constructible_from<T, decltype(args)...>
    {
        construct_at<T>(&m_value, std::forward<decltype(args)>(args)...);
    }

    // @Safety Value must have been initialized
    constexpr void assign_unsafe(auto&& value)
        requires assignable_from<T&, decltype(value)>
    {
        m_value = std::forward<decltype(value)>(value);
    }

    // @Safety Value must have been initialized
    constexpr void destroy_unsafe()
    {
        if constexpr (!trivially_destructible<T>)
        {
            destroy(&m_value);
        }
    }

    // @Safety Value must have been initialized
    constexpr auto&& as_init_unsafe(this auto&& self)
    {
        return std::forward<decltype(self)>(self).m_value;
    }
};

} // namespace asl