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