10b57cec5SDimitry Andric //===-- vector.h ------------------------------------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #ifndef SCUDO_VECTOR_H_ 100b57cec5SDimitry Andric #define SCUDO_VECTOR_H_ 110b57cec5SDimitry Andric 125f757f3fSDimitry Andric #include "mem_map.h" 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include <string.h> 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric namespace scudo { 170b57cec5SDimitry Andric 185f757f3fSDimitry Andric // A low-level vector based on map. It stores the contents inline up to a fixed 195f757f3fSDimitry Andric // capacity, or in an external memory buffer if it grows bigger than that. May 205f757f3fSDimitry Andric // incur a significant memory overhead for small vectors. The current 215f757f3fSDimitry Andric // implementation supports only POD types. 225f757f3fSDimitry Andric // 235f757f3fSDimitry Andric // NOTE: This class is not meant to be used directly, use Vector<T> instead. 24*0fca6ea1SDimitry Andric template <typename T, size_t StaticNumEntries> class VectorNoCtor { 250b57cec5SDimitry Andric public: 260b57cec5SDimitry Andric T &operator[](uptr I) { 270b57cec5SDimitry Andric DCHECK_LT(I, Size); 280b57cec5SDimitry Andric return Data[I]; 290b57cec5SDimitry Andric } 300b57cec5SDimitry Andric const T &operator[](uptr I) const { 310b57cec5SDimitry Andric DCHECK_LT(I, Size); 320b57cec5SDimitry Andric return Data[I]; 330b57cec5SDimitry Andric } push_back(const T & Element)340b57cec5SDimitry Andric void push_back(const T &Element) { 350b57cec5SDimitry Andric DCHECK_LE(Size, capacity()); 360b57cec5SDimitry Andric if (Size == capacity()) { 3706c3fb27SDimitry Andric const uptr NewCapacity = roundUpPowerOfTwo(Size + 1); 38*0fca6ea1SDimitry Andric if (!reallocate(NewCapacity)) { 39*0fca6ea1SDimitry Andric return; 40*0fca6ea1SDimitry Andric } 410b57cec5SDimitry Andric } 420b57cec5SDimitry Andric memcpy(&Data[Size++], &Element, sizeof(T)); 430b57cec5SDimitry Andric } back()440b57cec5SDimitry Andric T &back() { 450b57cec5SDimitry Andric DCHECK_GT(Size, 0); 460b57cec5SDimitry Andric return Data[Size - 1]; 470b57cec5SDimitry Andric } pop_back()480b57cec5SDimitry Andric void pop_back() { 490b57cec5SDimitry Andric DCHECK_GT(Size, 0); 500b57cec5SDimitry Andric Size--; 510b57cec5SDimitry Andric } size()520b57cec5SDimitry Andric uptr size() const { return Size; } data()530b57cec5SDimitry Andric const T *data() const { return Data; } data()540b57cec5SDimitry Andric T *data() { return Data; } capacity()55349cc55cSDimitry Andric constexpr uptr capacity() const { return CapacityBytes / sizeof(T); } reserve(uptr NewSize)56*0fca6ea1SDimitry Andric bool reserve(uptr NewSize) { 570b57cec5SDimitry Andric // Never downsize internal buffer. 580b57cec5SDimitry Andric if (NewSize > capacity()) 59*0fca6ea1SDimitry Andric return reallocate(NewSize); 60*0fca6ea1SDimitry Andric return true; 610b57cec5SDimitry Andric } resize(uptr NewSize)620b57cec5SDimitry Andric void resize(uptr NewSize) { 630b57cec5SDimitry Andric if (NewSize > Size) { 64*0fca6ea1SDimitry Andric if (!reserve(NewSize)) { 65*0fca6ea1SDimitry Andric return; 66*0fca6ea1SDimitry Andric } 670b57cec5SDimitry Andric memset(&Data[Size], 0, sizeof(T) * (NewSize - Size)); 680b57cec5SDimitry Andric } 690b57cec5SDimitry Andric Size = NewSize; 700b57cec5SDimitry Andric } 710b57cec5SDimitry Andric clear()720b57cec5SDimitry Andric void clear() { Size = 0; } empty()730b57cec5SDimitry Andric bool empty() const { return size() == 0; } 740b57cec5SDimitry Andric begin()750b57cec5SDimitry Andric const T *begin() const { return data(); } begin()760b57cec5SDimitry Andric T *begin() { return data(); } end()770b57cec5SDimitry Andric const T *end() const { return data() + size(); } end()780b57cec5SDimitry Andric T *end() { return data() + size(); } 790b57cec5SDimitry Andric 805f757f3fSDimitry Andric protected: 815f757f3fSDimitry Andric constexpr void init(uptr InitialCapacity = 0) { 825f757f3fSDimitry Andric Data = &LocalData[0]; 835f757f3fSDimitry Andric CapacityBytes = sizeof(LocalData); 845f757f3fSDimitry Andric if (InitialCapacity > capacity()) 855f757f3fSDimitry Andric reserve(InitialCapacity); 865f757f3fSDimitry Andric } destroy()875f757f3fSDimitry Andric void destroy() { 885f757f3fSDimitry Andric if (Data != &LocalData[0]) 895f757f3fSDimitry Andric ExternalBuffer.unmap(ExternalBuffer.getBase(), 905f757f3fSDimitry Andric ExternalBuffer.getCapacity()); 915f757f3fSDimitry Andric } 925f757f3fSDimitry Andric 930b57cec5SDimitry Andric private: reallocate(uptr NewCapacity)94*0fca6ea1SDimitry Andric bool reallocate(uptr NewCapacity) { 950b57cec5SDimitry Andric DCHECK_GT(NewCapacity, 0); 960b57cec5SDimitry Andric DCHECK_LE(Size, NewCapacity); 975f757f3fSDimitry Andric 985f757f3fSDimitry Andric MemMapT NewExternalBuffer; 9906c3fb27SDimitry Andric NewCapacity = roundUp(NewCapacity * sizeof(T), getPageSizeCached()); 100*0fca6ea1SDimitry Andric if (!NewExternalBuffer.map(/*Addr=*/0U, NewCapacity, "scudo:vector", 101*0fca6ea1SDimitry Andric MAP_ALLOWNOMEM)) { 102*0fca6ea1SDimitry Andric return false; 103*0fca6ea1SDimitry Andric } 1045f757f3fSDimitry Andric T *NewExternalData = reinterpret_cast<T *>(NewExternalBuffer.getBase()); 1055f757f3fSDimitry Andric 1065f757f3fSDimitry Andric memcpy(NewExternalData, Data, Size * sizeof(T)); 107fe6060f1SDimitry Andric destroy(); 1085f757f3fSDimitry Andric 1095f757f3fSDimitry Andric Data = NewExternalData; 110fe6060f1SDimitry Andric CapacityBytes = NewCapacity; 1115f757f3fSDimitry Andric ExternalBuffer = NewExternalBuffer; 112*0fca6ea1SDimitry Andric return true; 1130b57cec5SDimitry Andric } 1140b57cec5SDimitry Andric 115fe6060f1SDimitry Andric T *Data = nullptr; 116fe6060f1SDimitry Andric uptr CapacityBytes = 0; 117fe6060f1SDimitry Andric uptr Size = 0; 1185f757f3fSDimitry Andric 119*0fca6ea1SDimitry Andric T LocalData[StaticNumEntries] = {}; 1205f757f3fSDimitry Andric MemMapT ExternalBuffer; 1210b57cec5SDimitry Andric }; 1220b57cec5SDimitry Andric 123*0fca6ea1SDimitry Andric template <typename T, size_t StaticNumEntries> 124*0fca6ea1SDimitry Andric class Vector : public VectorNoCtor<T, StaticNumEntries> { 1250b57cec5SDimitry Andric public: 126*0fca6ea1SDimitry Andric static_assert(StaticNumEntries > 0U, 127*0fca6ea1SDimitry Andric "Vector must have a non-zero number of static entries."); Vector()128*0fca6ea1SDimitry Andric constexpr Vector() { VectorNoCtor<T, StaticNumEntries>::init(); } Vector(uptr Count)1290b57cec5SDimitry Andric explicit Vector(uptr Count) { 130*0fca6ea1SDimitry Andric VectorNoCtor<T, StaticNumEntries>::init(Count); 1310b57cec5SDimitry Andric this->resize(Count); 1320b57cec5SDimitry Andric } ~Vector()133*0fca6ea1SDimitry Andric ~Vector() { VectorNoCtor<T, StaticNumEntries>::destroy(); } 1340b57cec5SDimitry Andric // Disallow copies and moves. 1350b57cec5SDimitry Andric Vector(const Vector &) = delete; 1360b57cec5SDimitry Andric Vector &operator=(const Vector &) = delete; 1370b57cec5SDimitry Andric Vector(Vector &&) = delete; 1380b57cec5SDimitry Andric Vector &operator=(Vector &&) = delete; 1390b57cec5SDimitry Andric }; 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric } // namespace scudo 1420b57cec5SDimitry Andric 1430b57cec5SDimitry Andric #endif // SCUDO_VECTOR_H_ 144