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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
|
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_FIXEDTUPLEVECTOR_H
#define EASTL_FIXEDTUPLEVECTOR_H
#include <EASTL/bonus/tuple_vector.h>
#include <EASTL/internal/fixed_pool.h>
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
#endif
namespace eastl
{
/// EASTL_FIXED_TUPLE_VECTOR_DEFAULT_NAME
///
/// Defines a default container name in the absence of a user-provided name.
/// In the case of fixed-size containers, the allocator name always refers
/// to overflow allocations.
///
#ifndef EASTL_FIXED_TUPLE_VECTOR_DEFAULT_NAME
#define EASTL_FIXED_TUPLE_VECTOR_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_tuple_vector" // Unless the user overrides something, this is "EASTL fixed_vector".
#endif
/// EASTL_FIXED_TUPLE_VECTOR_DEFAULT_ALLOCATOR
///
#ifndef EASTL_FIXED_TUPLE_VECTOR_DEFAULT_ALLOCATOR
#define EASTL_FIXED_TUPLE_VECTOR_DEFAULT_ALLOCATOR overflow_allocator_type(EASTL_FIXED_TUPLE_VECTOR_DEFAULT_NAME)
#endif
// External interface of fixed_tuple_vector
template <size_t nodeCount, bool bEnableOverflow, typename... Ts>
class fixed_tuple_vector : public TupleVecInternal::TupleVecImpl<fixed_vector_allocator<
TupleVecInternal::TupleRecurser<Ts...>::GetTotalAllocationSize(nodeCount, 0), 1,
TupleVecInternal::TupleRecurser<Ts...>::GetTotalAlignment(), 0,
bEnableOverflow, EASTLAllocatorType>, make_index_sequence<sizeof...(Ts)>, Ts...>
{
public:
typedef fixed_vector_allocator<
TupleVecInternal::TupleRecurser<Ts...>::GetTotalAllocationSize(nodeCount, 0), 1,
TupleVecInternal::TupleRecurser<Ts...>::GetTotalAlignment(), 0,
bEnableOverflow, EASTLAllocatorType> fixed_allocator_type;
typedef aligned_buffer<fixed_allocator_type::kNodesSize, fixed_allocator_type::kNodeAlignment> aligned_buffer_type;
typedef fixed_tuple_vector<nodeCount, bEnableOverflow, Ts...> this_type;
typedef EASTLAllocatorType overflow_allocator_type;
typedef TupleVecInternal::TupleVecImpl<fixed_allocator_type, make_index_sequence<sizeof...(Ts)>, Ts...> base_type;
typedef typename base_type::size_type size_type;
private:
aligned_buffer_type mBuffer;
public:
fixed_tuple_vector()
: base_type(fixed_allocator_type(mBuffer.buffer), mBuffer.buffer, nodeCount, fixed_allocator_type::kNodeSize)
{ }
fixed_tuple_vector(const overflow_allocator_type& allocator)
: base_type(fixed_allocator_type(mBuffer.buffer, allocator), mBuffer.buffer, nodeCount, fixed_allocator_type::kNodeSize)
{ }
fixed_tuple_vector(this_type&& x)
: base_type(fixed_allocator_type(mBuffer.buffer), mBuffer.buffer, nodeCount, fixed_allocator_type::kNodeSize)
{
base_type::get_allocator().copy_overflow_allocator(x.get_allocator());
base_type::DoInitFromIterator(make_move_iterator(x.begin()), make_move_iterator(x.end()));
x.clear();
}
fixed_tuple_vector(this_type&& x, const overflow_allocator_type& allocator)
: base_type(fixed_allocator_type(mBuffer.buffer, allocator), mBuffer.buffer, nodeCount, fixed_allocator_type::kNodeSize)
{
base_type::DoInitFromIterator(make_move_iterator(x.begin()), make_move_iterator(x.end()));
x.clear();
}
fixed_tuple_vector(const this_type& x)
: base_type(fixed_allocator_type(mBuffer.buffer), mBuffer.buffer, nodeCount, fixed_allocator_type::kNodeSize)
{
base_type::get_allocator().copy_overflow_allocator(x.get_allocator());
base_type::DoInitFromIterator(x.begin(), x.end());
}
fixed_tuple_vector(const this_type& x, const overflow_allocator_type& allocator)
: base_type(fixed_allocator_type(mBuffer.buffer, allocator), mBuffer.buffer, nodeCount, fixed_allocator_type::kNodeSize)
{
base_type::DoInitFromIterator(x.begin(), x.end());
}
template <typename MoveIterBase>
fixed_tuple_vector(move_iterator<MoveIterBase> begin, move_iterator<MoveIterBase> end, const overflow_allocator_type& allocator = EASTL_FIXED_TUPLE_VECTOR_DEFAULT_ALLOCATOR)
: base_type(fixed_allocator_type(mBuffer.buffer, allocator), mBuffer.buffer, nodeCount, fixed_allocator_type::kNodeSize)
{
base_type::DoInitFromIterator(begin, end);
}
template <typename Iterator>
fixed_tuple_vector(Iterator begin, Iterator end, const overflow_allocator_type& allocator = EASTL_FIXED_TUPLE_VECTOR_DEFAULT_ALLOCATOR)
: base_type(fixed_allocator_type(mBuffer.buffer, allocator), mBuffer.buffer, nodeCount, fixed_allocator_type::kNodeSize)
{
base_type::DoInitFromIterator(begin, end);
}
fixed_tuple_vector(size_type n, const overflow_allocator_type& allocator = EASTL_FIXED_TUPLE_VECTOR_DEFAULT_ALLOCATOR)
: base_type(fixed_allocator_type(mBuffer.buffer, allocator), mBuffer.buffer, nodeCount, fixed_allocator_type::kNodeSize)
{
base_type::DoInitDefaultFill(n);
}
fixed_tuple_vector(size_type n, const Ts&... args)
: base_type(fixed_allocator_type(mBuffer.buffer), mBuffer.buffer, nodeCount, fixed_allocator_type::kNodeSize)
{
base_type::DoInitFillArgs(n, args...);
}
fixed_tuple_vector(size_type n, const Ts&... args, const overflow_allocator_type& allocator)
: base_type(fixed_allocator_type(mBuffer.buffer, allocator), mBuffer.buffer, nodeCount, fixed_allocator_type::kNodeSize)
{
base_type::DoInitFillArgs(n, args...);
}
fixed_tuple_vector(size_type n,
typename base_type::const_reference_tuple tup,
const overflow_allocator_type& allocator = EASTL_FIXED_TUPLE_VECTOR_DEFAULT_ALLOCATOR)
: base_type(fixed_allocator_type(mBuffer.buffer, allocator), mBuffer.buffer, nodeCount, fixed_allocator_type::kNodeSize)
{
base_type::DoInitFillTuple(n, tup);
}
fixed_tuple_vector(const typename base_type::value_tuple* first, const typename base_type::value_tuple* last,
const overflow_allocator_type& allocator = EASTL_FIXED_TUPLE_VECTOR_DEFAULT_ALLOCATOR)
: base_type(fixed_allocator_type(mBuffer.buffer, allocator), mBuffer.buffer, nodeCount, fixed_allocator_type::kNodeSize)
{
base_type::DoInitFromTupleArray(first, last);
}
fixed_tuple_vector(std::initializer_list<typename base_type::value_tuple> iList,
const overflow_allocator_type& allocator = EASTL_FIXED_TUPLE_VECTOR_DEFAULT_ALLOCATOR)
: base_type(fixed_allocator_type(mBuffer.buffer, allocator), mBuffer.buffer, nodeCount, fixed_allocator_type::kNodeSize)
{
base_type::DoInitFromTupleArray(iList.begin(), iList.end());
}
this_type& operator=(const this_type& other)
{
base_type::operator=(other);
return *this;
}
this_type& operator=(this_type&& other)
{
base_type::clear();
// OK to call DoInitFromIterator in a non-ctor scenario because clear() reset everything, more-or-less
base_type::DoInitFromIterator(make_move_iterator(other.begin()), make_move_iterator(other.end()));
other.clear();
return *this;
}
this_type& operator=(std::initializer_list<typename base_type::value_tuple> iList)
{
base_type::operator=(iList);
return *this;
}
void swap(this_type& x)
{
// If both containers are using the heap instead of local memory
// then we can do a fast pointer swap instead of content swap.
if ((has_overflowed() && x.has_overflowed()) && (get_overflow_allocator() == x.get_overflow_allocator()))
{
base_type::swap(x);
}
else
{
// Fixed containers use a special swap that can deal with excessively large buffers.
eastl::fixed_swap(*this, x);
}
}
// Returns the max fixed size, which is the user-supplied nodeCount parameter.
size_type max_size() const { return nodeCount; }
// Returns true if the fixed space has been fully allocated. Note that if overflow is enabled,
// the container size can be greater than nodeCount but full() could return true because the
// fixed space may have a recently freed slot.
bool full() const { return (base_type::mNumElements >= nodeCount) || ((void*)base_type::mpData != (void*)mBuffer.buffer); }
// Returns true if the allocations spilled over into the overflow allocator. Meaningful
// only if overflow is enabled.
bool has_overflowed() const { return ((void*)base_type::mpData != (void*)mBuffer.buffer); }
// Returns the value of the bEnableOverflow template parameter.
bool can_overflow() const { return bEnableOverflow; }
const overflow_allocator_type& get_overflow_allocator() const { return base_type::get_allocator().get_overflow_allocator(); }
};
template <size_t nodeCount, bool bEnableOverflow, typename... Ts>
inline void swap(fixed_tuple_vector<nodeCount, bEnableOverflow, Ts...>& a,
fixed_tuple_vector<nodeCount, bEnableOverflow, Ts...>& b)
{
a.swap(b);
}
} // namespace eastl
#endif // EASTL_TUPLEVECTOR_H
|