Path: blob/master/thirdparty/jolt_physics/Jolt/Core/Array.h
9906 views
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)1// SPDX-FileCopyrightText: 2024 Jorrit Rouwe2// SPDX-License-Identifier: MIT34#pragma once56#include <Jolt/Core/STLAllocator.h>7#include <Jolt/Core/HashCombine.h>89#ifdef JPH_USE_STD_VECTOR1011JPH_SUPPRESS_WARNINGS_STD_BEGIN12#include <vector>13JPH_SUPPRESS_WARNINGS_STD_END1415JPH_NAMESPACE_BEGIN1617template <class T, class Allocator = STLAllocator<T>> using Array = std::vector<T, Allocator>;1819JPH_NAMESPACE_END2021#else2223JPH_NAMESPACE_BEGIN2425/// Simple replacement for std::vector26///27/// Major differences:28/// - Memory is not initialized to zero (this was causing a lot of page faults when deserializing large MeshShapes / HeightFieldShapes)29/// - Iterators are simple pointers (for now)30/// - No exception safety31/// - No specialization like std::vector<bool> has32/// - Not all functions have been implemented33template <class T, class Allocator = STLAllocator<T>>34class [[nodiscard]] Array : private Allocator35{36public:37using value_type = T;38using allocator_type = Allocator;39using size_type = size_t;40using difference_type = typename Allocator::difference_type;41using pointer = T *;42using const_pointer = const T *;43using reference = T &;44using const_reference = const T &;4546using const_iterator = const T *;47using iterator = T *;4849/// An iterator that traverses the array in reverse order50class rev_it51{52public:53/// Constructor54rev_it() = default;55explicit rev_it(T *inValue) : mValue(inValue) { }5657/// Copying58rev_it(const rev_it &) = default;59rev_it & operator = (const rev_it &) = default;6061/// Comparison62bool operator == (const rev_it &inRHS) const { return mValue == inRHS.mValue; }63bool operator != (const rev_it &inRHS) const { return mValue != inRHS.mValue; }6465/// Arithmetics66rev_it & operator ++ () { --mValue; return *this; }67rev_it operator ++ (int) { return rev_it(mValue--); }68rev_it & operator -- () { ++mValue; return *this; }69rev_it operator -- (int) { return rev_it(mValue++); }7071rev_it operator + (int inValue) { return rev_it(mValue - inValue); }72rev_it operator - (int inValue) { return rev_it(mValue + inValue); }7374rev_it & operator += (int inValue) { mValue -= inValue; return *this; }75rev_it & operator -= (int inValue) { mValue += inValue; return *this; }7677/// Access78T & operator * () const { return *mValue; }79T & operator -> () const { return *mValue; }8081private:82T * mValue;83};8485/// A const iterator that traverses the array in reverse order86class crev_it87{88public:89/// Constructor90crev_it() = default;91explicit crev_it(const T *inValue) : mValue(inValue) { }9293/// Copying94crev_it(const crev_it &) = default;95explicit crev_it(const rev_it &inValue) : mValue(inValue.mValue) { }96crev_it & operator = (const crev_it &) = default;97crev_it & operator = (const rev_it &inRHS) { mValue = inRHS.mValue; return *this; }9899/// Comparison100bool operator == (const crev_it &inRHS) const { return mValue == inRHS.mValue; }101bool operator != (const crev_it &inRHS) const { return mValue != inRHS.mValue; }102103/// Arithmetics104crev_it & operator ++ () { --mValue; return *this; }105crev_it operator ++ (int) { return crev_it(mValue--); }106crev_it & operator -- () { ++mValue; return *this; }107crev_it operator -- (int) { return crev_it(mValue++); }108109crev_it operator + (int inValue) { return crev_it(mValue - inValue); }110crev_it operator - (int inValue) { return crev_it(mValue + inValue); }111112crev_it & operator += (int inValue) { mValue -= inValue; return *this; }113crev_it & operator -= (int inValue) { mValue += inValue; return *this; }114115/// Access116const T & operator * () const { return *mValue; }117const T & operator -> () const { return *mValue; }118119private:120const T * mValue;121};122123using reverse_iterator = rev_it;124using const_reverse_iterator = crev_it;125126private:127/// Move elements from one location to another128inline void move(pointer inDestination, pointer inSource, size_type inCount)129{130if constexpr (std::is_trivially_copyable<T>())131memmove(inDestination, inSource, inCount * sizeof(T));132else133{134if (inDestination < inSource)135{136for (T *destination_end = inDestination + inCount; inDestination < destination_end; ++inDestination, ++inSource)137{138new (inDestination) T(std::move(*inSource));139inSource->~T();140}141}142else143{144for (T *destination = inDestination + inCount - 1, *source = inSource + inCount - 1; destination >= inDestination; --destination, --source)145{146new (destination) T(std::move(*source));147source->~T();148}149}150}151}152153/// Reallocate the data block to inNewCapacity154inline void reallocate(size_type inNewCapacity)155{156JPH_ASSERT(inNewCapacity > 0 && inNewCapacity >= mSize);157158pointer ptr;159if constexpr (AllocatorHasReallocate<Allocator>::sValue)160{161// Reallocate data block162ptr = get_allocator().reallocate(mElements, mCapacity, inNewCapacity);163}164else165{166// Copy data to a new location167ptr = get_allocator().allocate(inNewCapacity);168if (mElements != nullptr)169{170move(ptr, mElements, mSize);171get_allocator().deallocate(mElements, mCapacity);172}173}174mElements = ptr;175mCapacity = inNewCapacity;176}177178/// Destruct elements [inStart, inEnd - 1]179inline void destruct(size_type inStart, size_type inEnd)180{181if constexpr (!std::is_trivially_destructible<T>())182if (inStart < inEnd)183for (T *element = mElements + inStart, *element_end = mElements + inEnd; element < element_end; ++element)184element->~T();185}186187public:188/// Reserve array space189inline void reserve(size_type inNewSize)190{191if (mCapacity < inNewSize)192reallocate(inNewSize);193}194195/// Resize array to new length196inline void resize(size_type inNewSize)197{198destruct(inNewSize, mSize);199reserve(inNewSize);200201if constexpr (!std::is_trivially_constructible<T>())202for (T *element = mElements + mSize, *element_end = mElements + inNewSize; element < element_end; ++element)203new (element) T;204mSize = inNewSize;205}206207/// Resize array to new length and initialize all elements with inValue208inline void resize(size_type inNewSize, const T &inValue)209{210JPH_ASSERT(&inValue < mElements || &inValue >= mElements + mSize, "Can't pass an element from the array to resize");211212destruct(inNewSize, mSize);213reserve(inNewSize);214215for (T *element = mElements + mSize, *element_end = mElements + inNewSize; element < element_end; ++element)216new (element) T(inValue);217mSize = inNewSize;218}219220/// Destruct all elements and set length to zero221inline void clear()222{223destruct(0, mSize);224mSize = 0;225}226227private:228/// Grow the array by at least inAmount elements229inline void grow(size_type inAmount = 1)230{231size_type min_size = mSize + inAmount;232if (min_size > mCapacity)233{234size_type new_capacity = max(min_size, mCapacity * 2);235reserve(new_capacity);236}237}238239/// Free memory240inline void free()241{242get_allocator().deallocate(mElements, mCapacity);243mElements = nullptr;244mCapacity = 0;245}246247/// Destroy all elements and free memory248inline void destroy()249{250if (mElements != nullptr)251{252clear();253free();254}255}256257public:258/// Replace the contents of this array with inBegin .. inEnd259template <class Iterator>260inline void assign(Iterator inBegin, Iterator inEnd)261{262clear();263reserve(size_type(std::distance(inBegin, inEnd)));264265for (Iterator element = inBegin; element != inEnd; ++element)266new (&mElements[mSize++]) T(*element);267}268269/// Replace the contents of this array with inList270inline void assign(std::initializer_list<T> inList)271{272clear();273reserve(size_type(inList.size()));274275for (const T &v : inList)276new (&mElements[mSize++]) T(v);277}278279/// Default constructor280Array() = default;281282/// Constructor with allocator283explicit inline Array(const Allocator &inAllocator) :284Allocator(inAllocator)285{286}287288/// Constructor with length289explicit inline Array(size_type inLength, const Allocator &inAllocator = { }) :290Allocator(inAllocator)291{292resize(inLength);293}294295/// Constructor with length and value296inline Array(size_type inLength, const T &inValue, const Allocator &inAllocator = { }) :297Allocator(inAllocator)298{299resize(inLength, inValue);300}301302/// Constructor from initializer list303inline Array(std::initializer_list<T> inList, const Allocator &inAllocator = { }) :304Allocator(inAllocator)305{306assign(inList);307}308309/// Constructor from iterator310inline Array(const_iterator inBegin, const_iterator inEnd, const Allocator &inAllocator = { }) :311Allocator(inAllocator)312{313assign(inBegin, inEnd);314}315316/// Copy constructor317inline Array(const Array<T, Allocator> &inRHS) :318Allocator(inRHS.get_allocator())319{320assign(inRHS.begin(), inRHS.end());321}322323/// Move constructor324inline Array(Array<T, Allocator> &&inRHS) noexcept :325Allocator(std::move(inRHS.get_allocator())),326mSize(inRHS.mSize),327mCapacity(inRHS.mCapacity),328mElements(inRHS.mElements)329{330inRHS.mSize = 0;331inRHS.mCapacity = 0;332inRHS.mElements = nullptr;333}334335/// Destruct all elements336inline ~Array()337{338destroy();339}340341/// Get the allocator342inline Allocator & get_allocator()343{344return *this;345}346347inline const Allocator &get_allocator() const348{349return *this;350}351352/// Add element to the back of the array353inline void push_back(const T &inValue)354{355JPH_ASSERT(&inValue < mElements || &inValue >= mElements + mSize, "Can't pass an element from the array to push_back");356357grow();358359T *element = mElements + mSize++;360new (element) T(inValue);361}362363inline void push_back(T &&inValue)364{365grow();366367T *element = mElements + mSize++;368new (element) T(std::move(inValue));369}370371/// Construct element at the back of the array372template <class... A>373inline T & emplace_back(A &&... inValue)374{375grow();376377T *element = mElements + mSize++;378new (element) T(std::forward<A>(inValue)...);379return *element;380}381382/// Remove element from the back of the array383inline void pop_back()384{385JPH_ASSERT(mSize > 0);386mElements[--mSize].~T();387}388389/// Returns true if there are no elements in the array390inline bool empty() const391{392return mSize == 0;393}394395/// Returns amount of elements in the array396inline size_type size() const397{398return mSize;399}400401/// Returns maximum amount of elements the array can hold402inline size_type capacity() const403{404return mCapacity;405}406407/// Reduce the capacity of the array to match its size408void shrink_to_fit()409{410if (mElements != nullptr)411{412if (mSize == 0)413free();414else if (mCapacity > mSize)415reallocate(mSize);416}417}418419/// Swap the contents of two arrays420void swap(Array<T, Allocator> &inRHS) noexcept421{422std::swap(get_allocator(), inRHS.get_allocator());423std::swap(mSize, inRHS.mSize);424std::swap(mCapacity, inRHS.mCapacity);425std::swap(mElements, inRHS.mElements);426}427428template <class Iterator>429void insert(const_iterator inPos, Iterator inBegin, Iterator inEnd)430{431size_type num_elements = size_type(std::distance(inBegin, inEnd));432if (num_elements > 0)433{434// After grow() inPos may be invalid435size_type first_element = inPos - mElements;436437grow(num_elements);438439T *element_begin = mElements + first_element;440T *element_end = element_begin + num_elements;441move(element_end, element_begin, mSize - first_element);442443for (T *element = element_begin; element < element_end; ++element, ++inBegin)444new (element) T(*inBegin);445446mSize += num_elements;447}448}449450void insert(const_iterator inPos, const T &inValue)451{452JPH_ASSERT(&inValue < mElements || &inValue >= mElements + mSize, "Can't pass an element from the array to insert");453454// After grow() inPos may be invalid455size_type first_element = inPos - mElements;456457grow();458459T *element = mElements + first_element;460move(element + 1, element, mSize - first_element);461462new (element) T(inValue);463mSize++;464}465466/// Remove one element from the array467iterator erase(const_iterator inIter)468{469size_type p = size_type(inIter - begin());470JPH_ASSERT(p < mSize);471mElements[p].~T();472if (p + 1 < mSize)473move(mElements + p, mElements + p + 1, mSize - p - 1);474--mSize;475return const_cast<iterator>(inIter);476}477478/// Remove multiple element from the array479iterator erase(const_iterator inBegin, const_iterator inEnd)480{481size_type p = size_type(inBegin - begin());482size_type n = size_type(inEnd - inBegin);483JPH_ASSERT(inEnd <= end());484destruct(p, p + n);485if (p + n < mSize)486move(mElements + p, mElements + p + n, mSize - p - n);487mSize -= n;488return const_cast<iterator>(inBegin);489}490491/// Iterators492inline const_iterator begin() const493{494return mElements;495}496497inline const_iterator end() const498{499return mElements + mSize;500}501502inline crev_it rbegin() const503{504return crev_it(mElements + mSize - 1);505}506507inline crev_it rend() const508{509return crev_it(mElements - 1);510}511512inline const_iterator cbegin() const513{514return begin();515}516517inline const_iterator cend() const518{519return end();520}521522inline crev_it crbegin() const523{524return rbegin();525}526527inline crev_it crend() const528{529return rend();530}531532inline iterator begin()533{534return mElements;535}536537inline iterator end()538{539return mElements + mSize;540}541542inline rev_it rbegin()543{544return rev_it(mElements + mSize - 1);545}546547inline rev_it rend()548{549return rev_it(mElements - 1);550}551552inline const T * data() const553{554return mElements;555}556557inline T * data()558{559return mElements;560}561562/// Access element563inline T & operator [] (size_type inIdx)564{565JPH_ASSERT(inIdx < mSize);566return mElements[inIdx];567}568569inline const T & operator [] (size_type inIdx) const570{571JPH_ASSERT(inIdx < mSize);572return mElements[inIdx];573}574575/// Access element576inline T & at(size_type inIdx)577{578JPH_ASSERT(inIdx < mSize);579return mElements[inIdx];580}581582inline const T & at(size_type inIdx) const583{584JPH_ASSERT(inIdx < mSize);585return mElements[inIdx];586}587588/// First element in the array589inline const T & front() const590{591JPH_ASSERT(mSize > 0);592return mElements[0];593}594595inline T & front()596{597JPH_ASSERT(mSize > 0);598return mElements[0];599}600601/// Last element in the array602inline const T & back() const603{604JPH_ASSERT(mSize > 0);605return mElements[mSize - 1];606}607608inline T & back()609{610JPH_ASSERT(mSize > 0);611return mElements[mSize - 1];612}613614/// Assignment operator615Array<T, Allocator> & operator = (const Array<T, Allocator> &inRHS)616{617if (static_cast<const void *>(this) != static_cast<const void *>(&inRHS))618assign(inRHS.begin(), inRHS.end());619620return *this;621}622623/// Assignment move operator624Array<T, Allocator> & operator = (Array<T, Allocator> &&inRHS) noexcept625{626if (static_cast<const void *>(this) != static_cast<const void *>(&inRHS))627{628destroy();629630get_allocator() = std::move(inRHS.get_allocator());631632mSize = inRHS.mSize;633mCapacity = inRHS.mCapacity;634mElements = inRHS.mElements;635636inRHS.mSize = 0;637inRHS.mCapacity = 0;638inRHS.mElements = nullptr;639}640641return *this;642}643644/// Assignment operator645Array<T, Allocator> & operator = (std::initializer_list<T> inRHS)646{647assign(inRHS);648649return *this;650}651652/// Comparing arrays653bool operator == (const Array<T, Allocator> &inRHS) const654{655if (mSize != inRHS.mSize)656return false;657for (size_type i = 0; i < mSize; ++i)658if (!(mElements[i] == inRHS.mElements[i]))659return false;660return true;661}662663bool operator != (const Array<T, Allocator> &inRHS) const664{665if (mSize != inRHS.mSize)666return true;667for (size_type i = 0; i < mSize; ++i)668if (mElements[i] != inRHS.mElements[i])669return true;670return false;671}672673/// Get hash for this array674uint64 GetHash() const675{676// Hash length first677uint64 ret = Hash<uint32> { } (uint32(size()));678679// Then hash elements680for (const T *element = mElements, *element_end = mElements + mSize; element < element_end; ++element)681HashCombine(ret, *element);682683return ret;684}685686private:687size_type mSize = 0;688size_type mCapacity = 0;689T * mElements = nullptr;690};691692JPH_NAMESPACE_END693694JPH_SUPPRESS_WARNING_PUSH695JPH_CLANG_SUPPRESS_WARNING("-Wc++98-compat")696697namespace std698{699/// Declare std::hash for Array700template <class T, class Allocator>701struct hash<JPH::Array<T, Allocator>>702{703size_t operator () (const JPH::Array<T, Allocator> &inRHS) const704{705return std::size_t(inRHS.GetHash());706}707};708}709710JPH_SUPPRESS_WARNING_POP711712#endif // JPH_USE_STD_VECTOR713714715