forked from msinilo/rdestl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fixed_vector.h
166 lines (153 loc) · 4.66 KB
/
fixed_vector.h
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
#ifndef RDESTL_FIXED_VECTOR_H
#define RDESTL_FIXED_VECTOR_H
#include "alignment.h"
#include "vector.h"
#define RDESTL_RECORD_WATERMARKS 0
// @TODO Wont work on 64-bit!
namespace rde
{
//=============================================================================
template<typename T, class TAllocator, size_t TCapacity, bool TGrowOnOverflow>
struct fixed_vector_storage
{
explicit fixed_vector_storage(const TAllocator& allocator)
: m_begin((T*)&m_data[0]),
m_end(m_begin),
m_capacityEnd(m_begin + TCapacity),
m_allocator(allocator)
#if RDESTL_RECORD_WATERMARKS
, m_max_size(0)
#endif
{
}
explicit fixed_vector_storage(e_noinitialize)
{
}
// @note Cant shrink
void reallocate(base_vector::size_type newCapacity, base_vector::size_type oldSize)
{
if (!TGrowOnOverflow)
{
RDE_ASSERT(!"fixed_vector cannot grow");
// @TODO: do something more spectacular here... do NOT throw exception, tho :)
// ...like fireworks, perhaps? ~SK()
}
T* newBegin = static_cast<T*>(m_allocator.allocate(newCapacity * sizeof(T)));
const base_vector::size_type newSize = oldSize < newCapacity ? oldSize : newCapacity;
// Copy old data if needed.
if (m_begin)
{
rde::copy_construct_n(m_begin, newSize, newBegin);
destroy(m_begin, oldSize);
}
m_begin = newBegin;
m_end = m_begin + newSize;
m_capacityEnd = m_begin + newCapacity;
record_high_watermark();
RDE_ASSERT(invariant());
}
// Reallocates memory, doesnt copy contents of old buffer.
void reallocate_discard_old(base_vector::size_type newCapacity)
{
if (newCapacity > base_vector::size_type(m_capacityEnd - m_begin))
{
if (!TGrowOnOverflow)
{
RDE_ASSERT(!"fixed_vector cannot grow");
}
T* newBegin = static_cast<T*>(m_allocator.allocate(newCapacity * sizeof(T)));
const base_vector::size_type currSize((size_t)(m_end - m_begin));
if (m_begin)
destroy(m_begin, currSize);
m_begin = newBegin;
m_end = m_begin + currSize;
record_high_watermark();
m_capacityEnd = m_begin + newCapacity;
}
RDE_ASSERT(invariant());
}
RDE_FORCEINLINE void destroy(T* ptr, base_vector::size_type n)
{
rde::destruct_n(ptr, n);
if ((etype_t*)ptr != &m_data[0])
m_allocator.deallocate(ptr, n * sizeof(T));
}
bool invariant() const
{
return m_end >= m_begin;
}
RDE_FORCEINLINE void record_high_watermark()
{
#if RDESTL_RECORD_WATERMARKS
const base_vector::size_type curr_size((size_t)(m_end - m_begin));
if (curr_size > m_max_size)
m_max_size = curr_size;
#endif
}
base_vector::size_type get_high_watermark() const
{
#if RDESTL_RECORD_WATERMARKS
return m_max_size;
#else
return TCapacity; // ???
#endif
}
typedef typename aligned_as<T>::res etype_t;
T* m_begin;
T* m_end;
// Not T[], because we need uninitialized memory.
etype_t m_data[(TCapacity * sizeof(T)) / sizeof(etype_t)];
T* m_capacityEnd;
TAllocator m_allocator;
#if RDESTL_RECORD_WATERMARKS
base_vector::size_type m_max_size;
#endif
};
//=============================================================================
template<typename T, size_t TCapacity, bool TGrowOnOverflow, class TAllocator = rde::allocator>
class fixed_vector: public vector<T, TAllocator, fixed_vector_storage<T, TAllocator, TCapacity, TGrowOnOverflow>>
{
typedef vector<T, TAllocator,
fixed_vector_storage<T, TAllocator, TCapacity, TGrowOnOverflow>
> base_vector;
typedef TAllocator allocator_type;
typedef typename base_vector::size_type size_type;
typedef T value_type;
public:
explicit fixed_vector(const allocator_type& allocator = allocator_type())
: base_vector(allocator)
{
/**/
}
explicit fixed_vector(size_type initialSize, const allocator_type& allocator = allocator_type())
: base_vector(initialSize, allocator)
{
/**/
}
fixed_vector(const T* first, const T* last, const allocator_type& allocator = allocator_type())
: base_vector(first, last, allocator)
{
/**/
}
// @note: allocator is not copied from rhs.
// @note: will not perform default constructor for newly created objects.
fixed_vector(const fixed_vector& rhs, const allocator_type& allocator = allocator_type())
: base_vector(rhs, allocator)
{
/**/
}
explicit fixed_vector(e_noinitialize n)
: base_vector(n)
{
/**/
}
fixed_vector& operator=(const fixed_vector& rhs)
{
if (&rhs != this)
base_vector::copy(rhs);
return *this;
}
};
} // namespace rde
//-----------------------------------------------------------------------------
#endif // #ifndef RDESTL_FIXED_VECTOR_H