forked from hep-cce2/root_serialization
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathProxyVector.h
More file actions
148 lines (111 loc) · 3.98 KB
/
ProxyVector.h
File metadata and controls
148 lines (111 loc) · 3.98 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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#if !defined(ProxyVector_h)
#define ProxyVector_h
/*---------------------------------------
The ProxyVector class is intended to look like a contiguous container
holding base classes by value. The elements of a given ProxyVector are
all the same actual type (which inherit from the given base class).
The actual underlying implementation uses the Pimpl idiom via the use of
ProxyVectorImpBase and ProxyVectorImp. The elements are stored in the
ProxyVectorImp via std::vector<> holding the concrete class by value.
Using ProxyVector instead of a std::vector<std::unique_ptr<Base>> allows
for better memory cache locality as each successive element of the container
is guaranteed to be next to each other in memory. Also requiring all the
elements to be of the same type means virtual function lookups should be
cached on the first element request and be reused for each subsequent call
when looping over all elements.
---------------------------------------*/
namespace cce::tf {
namespace implementation {
//Base implementation
template<typename P, typename... ARGS>
class ProxyVectorImpBase {
public:
ProxyVectorImpBase() = default;
virtual ~ProxyVectorImpBase() = default;
virtual void reserve(std::size_t) = 0;
virtual P& emplace_back(ARGS... args) = 0;
virtual std::size_t size() const = 0;
virtual P const& operator[](std::size_t index) const = 0;
virtual P& operator[](std::size_t index) = 0;
struct ConstIter {
ProxyVectorImpBase<P, ARGS...> const* container_ = nullptr;
std::size_t index_ = 0;
P const& operator*() const {
return container_->operator[](index_);
}
ConstIter& operator++() { ++index_; return *this;}
bool operator==(ConstIter const& iOther) const {
return index_ == iOther.index_;
}
bool operator!=(ConstIter const& iOther) const {
return index_ != iOther.index_;
}
};
ConstIter begin() const { return {this, 0}; }
ConstIter end() const {return {this, size()}; }
};
//An explicit implementation
template<typename T, typename PROXY, typename... ARGS>
class ProxyVectorImp final: public ProxyVectorImpBase<PROXY, ARGS...> {
public:
ProxyVectorImp() = default;
void reserve(std::size_t iSize) {
storage_.reserve(iSize);
}
T& emplace_back(ARGS... iArgs ) {
return storage_.emplace_back(std::forward<ARGS>(iArgs)...);
}
std::size_t size() const { return storage_.size();}
T const& operator[](std::size_t index) const {
return storage_[index];
}
T& operator[](std::size_t index) {
return storage_[index];
}
private:
std::vector<T> storage_;
};
}
//User facing class
template<typename P, typename... ARGS>
class ProxyVector {
public:
ProxyVector() = default;
~ProxyVector() = default;
ProxyVector& operator=(ProxyVector&&) = default;
ProxyVector(ProxyVector&&) = default;
void reserve(std::size_t iSize) { imp_->reserve(iSize);}
P& emplace_back(ARGS... iargs) { return imp_->emplace_back(std::forward<ARGS>(iargs)...);}
std::size_t size() const {return imp_->size();}
P const& operator[](std::size_t index) const {
return imp_->operator[](index);
}
P& operator[](std::size_t index) {
return imp_->operator[](index);
}
struct ConstIter {
ProxyVector<P, ARGS...> const* container_ = nullptr;
std::size_t index_ = 0;
P const& operator*() const {
return container_->operator[](index_);
}
ConstIter& operator++() { ++index_; return *this;}
bool operator==(ConstIter const& iOther) const {
return index_ == iOther.index_;
}
bool operator!=(ConstIter const& iOther) const {
return index_ != iOther.index_;
}
};
ConstIter begin() const { return {this, 0}; }
ConstIter end() const {return {this, size()}; }
template<typename T>
static ProxyVector<P, ARGS...> make() {
return ProxyVector<P, ARGS...>( std::make_unique<implementation::ProxyVectorImp<T, P, ARGS...>>() );
}
private:
ProxyVector( std::unique_ptr<implementation::ProxyVectorImpBase<P, ARGS...>> iImp): imp_(std::move(iImp)) {}
std::unique_ptr<implementation::ProxyVectorImpBase<P, ARGS...>> imp_;
};
}
#endif