blob: a4abea0e883d5fc966d9b92b3226c8f3bf2c9e7f (
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
|
#pragma once
#include <type_traits>
#include <utility>
namespace mbgl {
namespace util {
class peer {
public:
peer() = default;
peer(const peer&) = delete;
peer(peer&& other)
: vtable(other.vtable)
{
if (vtable) {
vtable->move(other.storage, storage);
}
other.vtable = nullptr;
}
template <class T>
peer(T&& value) {
using _Vt = std::decay_t<T>;
vtable = get_vtable<_Vt>();
new (&storage) _Vt(std::forward<T>(value));
}
~peer() {
reset();
}
peer& operator=(peer&& rhs) {
peer(std::move(rhs)).swap(*this);
return *this;
}
void reset() {
if (vtable) {
vtable->destroy(storage);
vtable = nullptr;
}
}
void swap(peer& rhs) {
if (this == &rhs) {
return;
} else {
peer tmp(std::move(rhs));
rhs.vtable = vtable;
if (rhs.vtable) {
rhs.vtable->move(storage, rhs.storage);
}
vtable = tmp.vtable;
if (vtable) {
vtable->move(tmp.storage, storage);
}
}
}
bool has_value() const {
return vtable != nullptr;
}
template <class T>
T& get() {
return reinterpret_cast<T&>(storage);
}
template <class T>
T&& take() {
reset();
return std::move(get<T>());
}
private:
using storage_t = std::aligned_storage_t<2*sizeof(void*), alignof(void*)>;
struct vtable {
virtual ~vtable() = default;
virtual void move(storage_t&, storage_t&) = 0;
virtual void destroy(storage_t&) = 0;
};
template <class T>
struct vtable_impl : public vtable {
static_assert(sizeof(T) <= sizeof(storage_t), "peer object is too big");
void move(storage_t& src, storage_t& dst) override {
new (&dst) T(std::move(reinterpret_cast<T&>(src)));
destroy(src);
}
void destroy(storage_t& s) override {
reinterpret_cast<T&>(s).~T();
}
};
template <class T>
static vtable* get_vtable() {
static vtable_impl<T> vtable;
return &vtable;
}
vtable* vtable = nullptr;
storage_t storage;
};
} // namespace util
} // namespace mbgl
|