summaryrefslogtreecommitdiff
path: root/asl/maybe_uninit.hpp
blob: 0ab09eee6c2a053b5684647e23bc326d2be4b386 (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
#pragma once

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

namespace asl
{

template<is_object T>
class maybe_uninit
{
    union
    {
        alignas(align_of<T>) char m_storage[size_of<T>];
        T m_value;
    };

public:
    constexpr maybe_uninit() {} // NOLINT(*-member-init)
    
    maybe_uninit(const maybe_uninit&) = delete;
    maybe_uninit(maybe_uninit&&) = delete;

    maybe_uninit& operator=(const maybe_uninit&) = delete;
    maybe_uninit& operator=(maybe_uninit&&) = delete;
    
    constexpr ~maybe_uninit() = default;
    constexpr ~maybe_uninit() requires (!trivially_destructible<T>) {}
    
    constexpr void*       uninit_ptr() && = delete;
    constexpr const void* uninit_ptr() const& { return m_storage; }
    constexpr void*       uninit_ptr() &      { return m_storage; }

    // @Safety Pointer must only be accessed when in initialized state.
    constexpr       T* init_ptr_unsafe() && = delete;
    constexpr const T* init_ptr_unsafe() const& { return &m_value; }
    constexpr       T* init_ptr_unsafe() &      { return &m_value; }

    // @Safety Reference must only be accessed when in initialized state.
    constexpr       T&& as_init_unsafe() &&     { return ASL_MOVE(m_value); }
    constexpr const T&  as_init_unsafe() const& { return m_value; }
    constexpr       T&  as_init_unsafe() &      { return m_value; }

    // @Safety Must be called only when in uninitialized state.
    template<typename... Args>
    constexpr void init_unsafe(Args&&... args) &
    {
        new(uninit_ptr()) T(ASL_FWD(args)...);
    }

    // @Safety Must be called only when in initialized state.
    constexpr void uninit_unsafe() &
    {
        if constexpr (!trivially_destructible<T>)
        {
            init_ptr_unsafe()->~T();
        }
    }
};

} // namespace asl