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

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

namespace asl
{

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

public:
    constexpr void* uninit_ptr() const { return m_storage; }

    // @Safety Pointer must only be accessed when in initialized state.
    constexpr const T* init_ptr(unsafe) const { return reinterpret_cast<const T*>(m_storage); }
    constexpr       T* init_ptr(unsafe)       { return reinterpret_cast<      T*>(m_storage); }

    // @Safety Reference must only be accessed when in initialized state.
    constexpr const T& as_init(unsafe) const { return *reinterpret_cast<const T*>(m_storage); }
    constexpr       T& as_init(unsafe)       { return *reinterpret_cast<      T*>(m_storage); }

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

    // @Safety Must be called only when in initialized state.
    inline void uninit(unsafe)
    {
        if constexpr (!trivially_destructible<T>)
        {
            init_ptr(unsafe("Caller has checked init state"))->~T();
        }
    }
};

} // namespace asl