1 //===-- vector.h ------------------------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #ifndef SCUDO_VECTOR_H_
10 #define SCUDO_VECTOR_H_
18 // A low-level vector based on map. It stores the contents inline up to a fixed
19 // capacity, or in an external memory buffer if it grows bigger than that. May
20 // incur a significant memory overhead for small vectors. The current
21 // implementation supports only POD types.
23 // NOTE: This class is not meant to be used directly, use Vector<T> instead.
24 template <typename T
, size_t StaticNumEntries
> class VectorNoCtor
{
26 T
&operator[](uptr I
) {
30 const T
&operator[](uptr I
) const {
34 void push_back(const T
&Element
) {
35 DCHECK_LE(Size
, capacity());
36 if (Size
== capacity()) {
37 const uptr NewCapacity
= roundUpPowerOfTwo(Size
+ 1);
38 if (!reallocate(NewCapacity
)) {
42 memcpy(&Data
[Size
++], &Element
, sizeof(T
));
46 return Data
[Size
- 1];
52 uptr
size() const { return Size
; }
53 const T
*data() const { return Data
; }
54 T
*data() { return Data
; }
55 constexpr uptr
capacity() const { return CapacityBytes
/ sizeof(T
); }
56 bool reserve(uptr NewSize
) {
57 // Never downsize internal buffer.
58 if (NewSize
> capacity())
59 return reallocate(NewSize
);
62 void resize(uptr NewSize
) {
64 if (!reserve(NewSize
)) {
67 memset(&Data
[Size
], 0, sizeof(T
) * (NewSize
- Size
));
72 void clear() { Size
= 0; }
73 bool empty() const { return size() == 0; }
75 const T
*begin() const { return data(); }
76 T
*begin() { return data(); }
77 const T
*end() const { return data() + size(); }
78 T
*end() { return data() + size(); }
81 constexpr void init(uptr InitialCapacity
= 0) {
83 CapacityBytes
= sizeof(LocalData
);
84 if (InitialCapacity
> capacity())
85 reserve(InitialCapacity
);
88 if (Data
!= &LocalData
[0])
89 ExternalBuffer
.unmap();
93 bool reallocate(uptr NewCapacity
) {
94 DCHECK_GT(NewCapacity
, 0);
95 DCHECK_LE(Size
, NewCapacity
);
97 MemMapT NewExternalBuffer
;
98 NewCapacity
= roundUp(NewCapacity
* sizeof(T
), getPageSizeCached());
99 if (!NewExternalBuffer
.map(/*Addr=*/0U, NewCapacity
, "scudo:vector",
103 T
*NewExternalData
= reinterpret_cast<T
*>(NewExternalBuffer
.getBase());
105 memcpy(NewExternalData
, Data
, Size
* sizeof(T
));
108 Data
= NewExternalData
;
109 CapacityBytes
= NewCapacity
;
110 ExternalBuffer
= NewExternalBuffer
;
115 uptr CapacityBytes
= 0;
118 T LocalData
[StaticNumEntries
] = {};
119 MemMapT ExternalBuffer
;
122 template <typename T
, size_t StaticNumEntries
>
123 class Vector
: public VectorNoCtor
<T
, StaticNumEntries
> {
125 static_assert(StaticNumEntries
> 0U,
126 "Vector must have a non-zero number of static entries.");
127 constexpr Vector() { VectorNoCtor
<T
, StaticNumEntries
>::init(); }
128 explicit Vector(uptr Count
) {
129 VectorNoCtor
<T
, StaticNumEntries
>::init(Count
);
132 ~Vector() { VectorNoCtor
<T
, StaticNumEntries
>::destroy(); }
133 // Disallow copies and moves.
134 Vector(const Vector
&) = delete;
135 Vector
&operator=(const Vector
&) = delete;
136 Vector(Vector
&&) = delete;
137 Vector
&operator=(Vector
&&) = delete;
142 #endif // SCUDO_VECTOR_H_