xref: /openbsd-src/gnu/llvm/compiler-rt/lib/scudo/standalone/vector.h (revision 810390e339a5425391477d5d41c78d7cab2424ac)
13cab2bb3Spatrick //===-- vector.h ------------------------------------------------*- C++ -*-===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick 
93cab2bb3Spatrick #ifndef SCUDO_VECTOR_H_
103cab2bb3Spatrick #define SCUDO_VECTOR_H_
113cab2bb3Spatrick 
123cab2bb3Spatrick #include "common.h"
133cab2bb3Spatrick 
143cab2bb3Spatrick #include <string.h>
153cab2bb3Spatrick 
163cab2bb3Spatrick namespace scudo {
173cab2bb3Spatrick 
183cab2bb3Spatrick // A low-level vector based on map. May incur a significant memory overhead for
193cab2bb3Spatrick // small vectors. The current implementation supports only POD types.
203cab2bb3Spatrick template <typename T> class VectorNoCtor {
213cab2bb3Spatrick public:
22*810390e3Srobert   constexpr void init(uptr InitialCapacity = 0) {
23*810390e3Srobert     Data = &LocalData[0];
24d89ec533Spatrick     CapacityBytes = sizeof(LocalData);
25*810390e3Srobert     if (InitialCapacity > capacity())
263cab2bb3Spatrick       reserve(InitialCapacity);
273cab2bb3Spatrick   }
destroy()283cab2bb3Spatrick   void destroy() {
29*810390e3Srobert     if (Data != &LocalData[0])
30*810390e3Srobert       unmap(Data, CapacityBytes, 0, &MapData);
313cab2bb3Spatrick   }
323cab2bb3Spatrick   T &operator[](uptr I) {
333cab2bb3Spatrick     DCHECK_LT(I, Size);
343cab2bb3Spatrick     return Data[I];
353cab2bb3Spatrick   }
363cab2bb3Spatrick   const T &operator[](uptr I) const {
373cab2bb3Spatrick     DCHECK_LT(I, Size);
383cab2bb3Spatrick     return Data[I];
393cab2bb3Spatrick   }
push_back(const T & Element)403cab2bb3Spatrick   void push_back(const T &Element) {
413cab2bb3Spatrick     DCHECK_LE(Size, capacity());
423cab2bb3Spatrick     if (Size == capacity()) {
433cab2bb3Spatrick       const uptr NewCapacity = roundUpToPowerOfTwo(Size + 1);
443cab2bb3Spatrick       reallocate(NewCapacity);
453cab2bb3Spatrick     }
463cab2bb3Spatrick     memcpy(&Data[Size++], &Element, sizeof(T));
473cab2bb3Spatrick   }
back()483cab2bb3Spatrick   T &back() {
493cab2bb3Spatrick     DCHECK_GT(Size, 0);
503cab2bb3Spatrick     return Data[Size - 1];
513cab2bb3Spatrick   }
pop_back()523cab2bb3Spatrick   void pop_back() {
533cab2bb3Spatrick     DCHECK_GT(Size, 0);
543cab2bb3Spatrick     Size--;
553cab2bb3Spatrick   }
size()563cab2bb3Spatrick   uptr size() const { return Size; }
data()573cab2bb3Spatrick   const T *data() const { return Data; }
data()583cab2bb3Spatrick   T *data() { return Data; }
capacity()59*810390e3Srobert   constexpr uptr capacity() const { return CapacityBytes / sizeof(T); }
reserve(uptr NewSize)603cab2bb3Spatrick   void reserve(uptr NewSize) {
613cab2bb3Spatrick     // Never downsize internal buffer.
623cab2bb3Spatrick     if (NewSize > capacity())
633cab2bb3Spatrick       reallocate(NewSize);
643cab2bb3Spatrick   }
resize(uptr NewSize)653cab2bb3Spatrick   void resize(uptr NewSize) {
663cab2bb3Spatrick     if (NewSize > Size) {
673cab2bb3Spatrick       reserve(NewSize);
683cab2bb3Spatrick       memset(&Data[Size], 0, sizeof(T) * (NewSize - Size));
693cab2bb3Spatrick     }
703cab2bb3Spatrick     Size = NewSize;
713cab2bb3Spatrick   }
723cab2bb3Spatrick 
clear()733cab2bb3Spatrick   void clear() { Size = 0; }
empty()743cab2bb3Spatrick   bool empty() const { return size() == 0; }
753cab2bb3Spatrick 
begin()763cab2bb3Spatrick   const T *begin() const { return data(); }
begin()773cab2bb3Spatrick   T *begin() { return data(); }
end()783cab2bb3Spatrick   const T *end() const { return data() + size(); }
end()793cab2bb3Spatrick   T *end() { return data() + size(); }
803cab2bb3Spatrick 
813cab2bb3Spatrick private:
reallocate(uptr NewCapacity)823cab2bb3Spatrick   void reallocate(uptr NewCapacity) {
833cab2bb3Spatrick     DCHECK_GT(NewCapacity, 0);
843cab2bb3Spatrick     DCHECK_LE(Size, NewCapacity);
85d89ec533Spatrick     NewCapacity = roundUpTo(NewCapacity * sizeof(T), getPageSizeCached());
86*810390e3Srobert     T *NewData = reinterpret_cast<T *>(
87*810390e3Srobert         map(nullptr, NewCapacity, "scudo:vector", 0, &MapData));
883cab2bb3Spatrick     memcpy(NewData, Data, Size * sizeof(T));
89d89ec533Spatrick     destroy();
903cab2bb3Spatrick     Data = NewData;
91d89ec533Spatrick     CapacityBytes = NewCapacity;
923cab2bb3Spatrick   }
933cab2bb3Spatrick 
94d89ec533Spatrick   T *Data = nullptr;
95*810390e3Srobert   T LocalData[256 / sizeof(T)] = {};
96d89ec533Spatrick   uptr CapacityBytes = 0;
97d89ec533Spatrick   uptr Size = 0;
98*810390e3Srobert   [[no_unique_address]] MapPlatformData MapData = {};
993cab2bb3Spatrick };
1003cab2bb3Spatrick 
1013cab2bb3Spatrick template <typename T> class Vector : public VectorNoCtor<T> {
1023cab2bb3Spatrick public:
Vector()103*810390e3Srobert   constexpr Vector() { VectorNoCtor<T>::init(); }
Vector(uptr Count)1043cab2bb3Spatrick   explicit Vector(uptr Count) {
1053cab2bb3Spatrick     VectorNoCtor<T>::init(Count);
1063cab2bb3Spatrick     this->resize(Count);
1073cab2bb3Spatrick   }
~Vector()1083cab2bb3Spatrick   ~Vector() { VectorNoCtor<T>::destroy(); }
1093cab2bb3Spatrick   // Disallow copies and moves.
1103cab2bb3Spatrick   Vector(const Vector &) = delete;
1113cab2bb3Spatrick   Vector &operator=(const Vector &) = delete;
1123cab2bb3Spatrick   Vector(Vector &&) = delete;
1133cab2bb3Spatrick   Vector &operator=(Vector &&) = delete;
1143cab2bb3Spatrick };
1153cab2bb3Spatrick 
1163cab2bb3Spatrick } // namespace scudo
1173cab2bb3Spatrick 
1183cab2bb3Spatrick #endif // SCUDO_VECTOR_H_
119