summaryrefslogtreecommitdiff
path: root/asl/ptr.hpp
blob: 9065e7439d88edfd86ba932c009414721bd3504a (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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#pragma once

#include "asl/integers.hpp"
#include "asl/meta.hpp"
#include "asl/utility.hpp"

namespace asl
{

// @Todo Shitty span, improve this
template<is_object T, isize_t kLen>
struct span
{
    static constexpr bool kDynamic = kLen < 0;

    using size_type = select_t<kDynamic, isize_t, empty>;

    constexpr span(T* begin, isize_t len) requires kDynamic
        : m_begin{begin}
        , m_len{len}
    {}

    constexpr span(T* begin) requires (!kDynamic)
        : m_begin{begin}
        , m_len{}
    {}
    
    T* m_begin;
    ASL_NO_UNIQUE_ADDRESS size_type m_len;
};

namespace ptr_internal
{

template<is_void T>
struct void_metadata
{
    using metadata = empty;
    using pointee = T;

    constexpr auto deref(pointee* ptr) { return ptr; }
};

template<is_array T>
struct array_metadata {};

template<is_object T>
struct array_metadata<T[]>
{
    using metadata = isize_t;
    using pointee = T;

    constexpr auto deref(pointee* ptr)
    {
        return span<pointee, -1>(ptr, m_len);
    }

    isize_t m_len;
};

template<is_object T, isize_t N>
struct array_metadata<T[N]>
{
    using metadata = empty;
    using pointee = T[N];

    constexpr auto deref(pointee* ptr)
    {
        return span<T, N>(static_cast<T*>(*ptr));
    }
};

template<is_object T>
struct object_metadata
{
    using metadata = empty;
    using pointee = T;

    constexpr auto deref(pointee* ptr) { return ptr; }
};

template<is_func T>
struct func_metadata
{
    using metadata = empty;
    using pointee = tame_t<T>* const;

    constexpr auto deref(pointee* ptr) { return *ptr; }
};

template<is_ref T>
struct ref_metadata
{
    using metadata = empty;
    using pointee = un_ref_t<T>* const;

    constexpr auto deref(pointee* ptr) { return *ptr; }
};

template<is_void   T> void_metadata<T>   select_ptr_metadata(types<T>);
template<is_array  T> array_metadata<T>  select_ptr_metadata(types<T>);
template<is_object T> object_metadata<T> select_ptr_metadata(types<T>) requires (!is_array<T>);
template<is_func   T> func_metadata<T>   select_ptr_metadata(types<T>);
template<is_ref    T> ref_metadata<T>    select_ptr_metadata(types<T>);

template<typename T>
using metadata = decltype(select_ptr_metadata(types<T>{}));

} // namespace ptr_internal

template<typename T>
concept ptr_metadata = requires (T metadata, typename T::pointee* ptr)
{
    is_object<typename T::metadata>;
    is_object<typename T::pointee>;

    { metadata.deref(ptr) };
};

template<typename T>
class ptr
{
    using meta = ptr_internal::metadata<T>;
    static_assert(ptr_metadata<meta>);

    meta::pointee* m_ptr;
    ASL_NO_UNIQUE_ADDRESS meta m_meta;
    
public:
    
};

} // namespace asl