-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconst_array.cpp
More file actions
125 lines (88 loc) · 3 KB
/
const_array.cpp
File metadata and controls
125 lines (88 loc) · 3 KB
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
// -*- compile-command: "CXXFLAGS=-std=c++14 make const_array" -*-
#include <memory>
#include <iostream>
template<class T> struct base;
template<class T, std::size_t N=0> struct derived;
template<class T>
using ref = std::shared_ptr<T>;
template<class ... Cases>
struct overload: Cases... {
using Cases::operator()...;
overload(Cases...cases): Cases(cases)... { }
};
template<class T>
struct base {
const std::size_t size;
const T data[0];
const T* begin() const { return data; }
const T* end() const { return data + size; }
private:
template<std::size_t ... M, class Func, class ... Args>
void visit(std::index_sequence<M...>, const Func& func, Args&&...args) const {
using thunk_type = void(*) (const base*, const Func&, Args&&...);
static const thunk_type table[] = {[](const base* self, const Func& func, Args&&...args) {
return func(static_cast<const derived<T, M>*>(self), std::forward<Args>(args)...);
}...};
return table[size](this, func, std::forward<Args>(args)...);
}
static constexpr std::size_t default_size = 32;
public:
template<std::size_t M=default_size, class ... Cases>
friend void match(const ref<base>& self, const Cases&... cases) {
return self->visit(std::make_index_sequence<M>{}, overload<Cases...>(cases...));
}
template<std::size_t M=default_size>
friend ref<base> push(const ref<base>& self, const T& value) {
ref<base> res;
match(self, [&](auto self) {
res = self->push(value, std::make_index_sequence<self->static_size>{});
});
return res;
}
template<std::size_t M=default_size>
friend ref<base> pop(const ref<base>& self) {
ref<base> res;
match(self, [&](auto self) {
static_assert(self->static_size > 0, "empty array");
res = self->pop(std::make_index_sequence<self->static_size - 1>{});
}, [](const derived<T>* self) {
throw std::runtime_error("empty array");
});
return res;
}
};
template<class T, std::size_t N>
struct derived: base<T> {
static constexpr std::size_t static_size = N;
const T storage[N];
template<class...Args>
derived(Args&&...args): base<T>{N}, storage{std::forward<Args>(args)...} { }
template<std::size_t ... Ms>
ref<base<T>> push(const T& value, std::index_sequence<Ms...>) const {
return std::make_shared<derived<T, N + 1>>(storage[Ms]..., value);
}
template<std::size_t ... Ms>
ref<base<T>> pop(std::index_sequence<Ms...>) const {
static_assert(N > 0, "empty array");
return std::make_shared<derived<T, N - 1>>(storage[Ms]...);
}
};
int main(int, char**) {
using type = double;
auto d = std::make_shared<derived<type>>();
ref<base<type>> b = d;
std::cout << d->data << ", " << d->storage << std::endl;
match(b, [](auto self) {
std::clog << sizeof(self->storage) / sizeof(type) << std::endl;
});
auto p = push(b, 2.0);
for(auto i: *p) {
std::cout << i << ", ";
}
std::cout << std::endl;
auto q = pop(p);
for(auto i: *q) {
std::cout << i << ", ";
}
return 0;
}