123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598 |
- // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
- // SPDX-FileCopyrightText: 2024 Jorrit Rouwe
- // SPDX-License-Identifier: MIT
- #pragma once
- #include <Jolt/Core/STLAllocator.h>
- #include <Jolt/Core/HashCombine.h>
- #ifdef JPH_USE_STD_VECTOR
- JPH_SUPPRESS_WARNINGS_STD_BEGIN
- #include <vector>
- JPH_SUPPRESS_WARNINGS_STD_END
- JPH_NAMESPACE_BEGIN
- template <class T, class Allocator = STLAllocator<T>> using Array = std::vector<T, Allocator>;
- JPH_NAMESPACE_END
- #else
- JPH_NAMESPACE_BEGIN
- /// Simple replacement for std::vector
- ///
- /// Major differences:
- /// - Memory is not initialized to zero (this was causing a lot of page faults when deserializing large MeshShapes / HeightFieldShapes)
- /// - Iterators are simple pointers (for now)
- /// - No exception safety
- /// - No specialization like std::vector<bool> has
- /// - Not all functions have been implemented
- template <class T, class Allocator = STLAllocator<T>>
- class [[nodiscard]] Array : private Allocator
- {
- public:
- using value_type = T;
- using size_type = size_t;
- using pointer = T *;
- using const_pointer = const T *;
- using reference = T &;
- using const_reference = const T &;
- using const_iterator = const T *;
- using iterator = T *;
- private:
- /// Move elements from one location to another
- inline void move(pointer inDestination, pointer inSource, size_type inCount)
- {
- if constexpr (std::is_trivially_copyable<T>())
- memmove(inDestination, inSource, inCount * sizeof(T));
- else
- {
- if (inDestination < inSource)
- {
- for (T *destination_end = inDestination + inCount; inDestination < destination_end; ++inDestination, ++inSource)
- {
- ::new (inDestination) T(std::move(*inSource));
- inSource->~T();
- }
- }
- else
- {
- for (T *destination = inDestination + inCount - 1, *source = inSource + inCount - 1; destination >= inDestination; --destination, --source)
- {
- ::new (destination) T(std::move(*source));
- source->~T();
- }
- }
- }
- }
- /// Reallocate the data block to inNewCapacity
- inline void reallocate(size_type inNewCapacity)
- {
- JPH_ASSERT(inNewCapacity > 0 && inNewCapacity >= mSize);
- pointer pointer;
- if constexpr (AllocatorHasReallocate<Allocator>::sValue)
- {
- // Reallocate data block
- pointer = get_allocator().reallocate(mElements, mCapacity, inNewCapacity);
- }
- else
- {
- // Copy data to a new location
- pointer = get_allocator().allocate(inNewCapacity);
- if (mElements != nullptr)
- {
- move(pointer, mElements, mSize);
- get_allocator().deallocate(mElements, mCapacity);
- }
- }
- mElements = pointer;
- mCapacity = inNewCapacity;
- }
- /// Destruct elements [inStart, inEnd - 1]
- inline void destruct(size_type inStart, size_type inEnd)
- {
- if constexpr (!is_trivially_destructible<T>())
- if (inStart < inEnd)
- for (T *element = mElements + inStart, *element_end = mElements + inEnd; element < element_end; ++element)
- element->~T();
- }
- public:
- /// Reserve array space
- inline void reserve(size_type inNewSize)
- {
- if (mCapacity < inNewSize)
- reallocate(inNewSize);
- }
- /// Resize array to new length
- inline void resize(size_type inNewSize)
- {
- destruct(inNewSize, mSize);
- reserve(inNewSize);
- if constexpr (!is_trivially_constructible<T>())
- for (T *element = mElements + mSize, *element_end = mElements + inNewSize; element < element_end; ++element)
- ::new (element) T;
- mSize = inNewSize;
- }
- /// Resize array to new length and initialize all elements with inValue
- inline void resize(size_type inNewSize, const T &inValue)
- {
- JPH_ASSERT(&inValue < mElements || &inValue >= mElements + mSize, "Can't pass an element from the array to resize");
- destruct(inNewSize, mSize);
- reserve(inNewSize);
- for (T *element = mElements + mSize, *element_end = mElements + inNewSize; element < element_end; ++element)
- ::new (element) T(inValue);
- mSize = inNewSize;
- }
- /// Destruct all elements and set length to zero
- inline void clear()
- {
- destruct(0, mSize);
- mSize = 0;
- }
- private:
- /// Grow the array by at least inAmount elements
- inline void grow(size_type inAmount = 1)
- {
- size_type min_size = mSize + inAmount;
- if (min_size > mCapacity)
- {
- size_type new_capacity = max(min_size, mCapacity * 2);
- reserve(new_capacity);
- }
- }
- /// Free memory
- inline void free()
- {
- get_allocator().deallocate(mElements, mCapacity);
- mElements = nullptr;
- mCapacity = 0;
- }
- /// Destroy all elements and free memory
- inline void destroy()
- {
- if (mElements != nullptr)
- {
- clear();
- free();
- }
- }
- public:
- /// Replace the contents of this array with inBegin .. inEnd
- template <class Iterator>
- inline void assign(Iterator inBegin, Iterator inEnd)
- {
- clear();
- reserve(size_type(std::distance(inBegin, inEnd)));
- for (Iterator element = inBegin; element != inEnd; ++element)
- ::new (&mElements[mSize++]) T(*element);
- }
- /// Replace the contents of this array with inList
- inline void assign(std::initializer_list<T> inList)
- {
- clear();
- reserve(size_type(inList.size()));
- for (const T &v : inList)
- ::new (&mElements[mSize++]) T(v);
- }
- /// Default constructor
- Array() = default;
- /// Constructor with allocator
- explicit inline Array(const Allocator &inAllocator) :
- Allocator(inAllocator)
- {
- }
- /// Constructor with length
- explicit inline Array(size_type inLength, const Allocator &inAllocator = { }) :
- Allocator(inAllocator)
- {
- resize(inLength);
- }
- /// Constructor with length and value
- inline Array(size_type inLength, const T &inValue, const Allocator &inAllocator = { }) :
- Allocator(inAllocator)
- {
- resize(inLength, inValue);
- }
- /// Constructor from initializer list
- inline Array(std::initializer_list<T> inList, const Allocator &inAllocator = { }) :
- Allocator(inAllocator)
- {
- assign(inList);
- }
- /// Constructor from iterator
- inline Array(const_iterator inBegin, const_iterator inEnd, const Allocator &inAllocator = { }) :
- Allocator(inAllocator)
- {
- assign(inBegin, inEnd);
- }
- /// Copy constructor
- inline Array(const Array<T, Allocator> &inRHS) :
- Allocator(inRHS.get_allocator())
- {
- assign(inRHS.begin(), inRHS.end());
- }
- /// Move constructor
- inline Array(Array<T, Allocator> &&inRHS) noexcept :
- Allocator(std::move(inRHS.get_allocator())),
- mSize(inRHS.mSize),
- mCapacity(inRHS.mCapacity),
- mElements(inRHS.mElements)
- {
- inRHS.mSize = 0;
- inRHS.mCapacity = 0;
- inRHS.mElements = nullptr;
- }
- /// Destruct all elements
- inline ~Array()
- {
- destroy();
- }
- /// Get the allocator
- inline Allocator & get_allocator()
- {
- return *this;
- }
- inline const Allocator &get_allocator() const
- {
- return *this;
- }
- /// Add element to the back of the array
- inline void push_back(const T &inValue)
- {
- JPH_ASSERT(&inValue < mElements || &inValue >= mElements + mSize, "Can't pass an element from the array to push_back");
- grow();
- T *element = mElements + mSize++;
- ::new (element) T(inValue);
- }
- inline void push_back(T &&inValue)
- {
- grow();
- T *element = mElements + mSize++;
- ::new (element) T(std::move(inValue));
- }
- /// Construct element at the back of the array
- template <class... A>
- inline T & emplace_back(A &&... inValue)
- {
- grow();
- T *element = mElements + mSize++;
- ::new (element) T(std::forward<A>(inValue)...);
- return *element;
- }
- /// Remove element from the back of the array
- inline void pop_back()
- {
- JPH_ASSERT(mSize > 0);
- mElements[--mSize].~T();
- }
- /// Returns true if there are no elements in the array
- inline bool empty() const
- {
- return mSize == 0;
- }
- /// Returns amount of elements in the array
- inline size_type size() const
- {
- return mSize;
- }
- /// Returns maximum amount of elements the array can hold
- inline size_type capacity() const
- {
- return mCapacity;
- }
- /// Reduce the capacity of the array to match its size
- void shrink_to_fit()
- {
- if (mElements != nullptr)
- {
- if (mSize == 0)
- free();
- else if (mCapacity > mSize)
- reallocate(mSize);
- }
- }
- /// Swap the contents of two arrays
- void swap(Array<T, Allocator> &inRHS) noexcept
- {
- std::swap(get_allocator(), inRHS.get_allocator());
- std::swap(mSize, inRHS.mSize);
- std::swap(mCapacity, inRHS.mCapacity);
- std::swap(mElements, inRHS.mElements);
- }
- template <class Iterator>
- void insert(const_iterator inPos, Iterator inBegin, Iterator inEnd)
- {
- size_type num_elements = size_type(std::distance(inBegin, inEnd));
- if (num_elements > 0)
- {
- // After grow() inPos may be invalid
- size_type first_element = inPos - mElements;
- grow(num_elements);
- T *element_begin = mElements + first_element;
- T *element_end = element_begin + num_elements;
- move(element_end, element_begin, mSize - first_element);
- for (T *element = element_begin; element < element_end; ++element, ++inBegin)
- ::new (element) T(*inBegin);
- mSize += num_elements;
- }
- }
- void insert(const_iterator inPos, const T &inValue)
- {
- JPH_ASSERT(&inValue < mElements || &inValue >= mElements + mSize, "Can't pass an element from the array to insert");
- // After grow() inPos may be invalid
- size_type first_element = inPos - mElements;
- grow();
- T *element = mElements + first_element;
- move(element + 1, element, mSize - first_element);
- ::new (element) T(inValue);
- mSize++;
- }
- /// Remove one element from the array
- void erase(const_iterator inIter)
- {
- size_type p = size_type(inIter - begin());
- JPH_ASSERT(p < mSize);
- mElements[p].~T();
- if (p + 1 < mSize)
- move(mElements + p, mElements + p + 1, mSize - p - 1);
- --mSize;
- }
- /// Remove multiple element from the array
- void erase(const_iterator inBegin, const_iterator inEnd)
- {
- size_type p = size_type(inBegin - begin());
- size_type n = size_type(inEnd - inBegin);
- JPH_ASSERT(inEnd <= end());
- destruct(p, p + n);
- if (p + n < mSize)
- move(mElements + p, mElements + p + n, mSize - p - n);
- mSize -= n;
- }
- /// Iterators
- inline const_iterator begin() const
- {
- return mElements;
- }
- inline const_iterator end() const
- {
- return mElements + mSize;
- }
- inline const_iterator cbegin() const
- {
- return mElements;
- }
- inline const_iterator cend() const
- {
- return mElements + mSize;
- }
- inline iterator begin()
- {
- return mElements;
- }
- inline iterator end()
- {
- return mElements + mSize;
- }
- inline const T * data() const
- {
- return mElements;
- }
- inline T * data()
- {
- return mElements;
- }
- /// Access element
- inline T & operator [] (size_type inIdx)
- {
- JPH_ASSERT(inIdx < mSize);
- return mElements[inIdx];
- }
- inline const T & operator [] (size_type inIdx) const
- {
- JPH_ASSERT(inIdx < mSize);
- return mElements[inIdx];
- }
- /// Access element
- inline T & at(size_type inIdx)
- {
- JPH_ASSERT(inIdx < mSize);
- return mElements[inIdx];
- }
- inline const T & at(size_type inIdx) const
- {
- JPH_ASSERT(inIdx < mSize);
- return mElements[inIdx];
- }
- /// First element in the array
- inline const T & front() const
- {
- JPH_ASSERT(mSize > 0);
- return mElements[0];
- }
- inline T & front()
- {
- JPH_ASSERT(mSize > 0);
- return mElements[0];
- }
- /// Last element in the array
- inline const T & back() const
- {
- JPH_ASSERT(mSize > 0);
- return mElements[mSize - 1];
- }
- inline T & back()
- {
- JPH_ASSERT(mSize > 0);
- return mElements[mSize - 1];
- }
- /// Assignment operator
- Array<T, Allocator> & operator = (const Array<T, Allocator> &inRHS)
- {
- if (static_cast<const void *>(this) != static_cast<const void *>(&inRHS))
- assign(inRHS.begin(), inRHS.end());
- return *this;
- }
- /// Assignment move operator
- Array<T, Allocator> & operator = (Array<T, Allocator> &&inRHS) noexcept
- {
- if (static_cast<const void *>(this) != static_cast<const void *>(&inRHS))
- {
- destroy();
- get_allocator() = std::move(inRHS.get_allocator());
- mSize = inRHS.mSize;
- mCapacity = inRHS.mCapacity;
- mElements = inRHS.mElements;
- inRHS.mSize = 0;
- inRHS.mCapacity = 0;
- inRHS.mElements = nullptr;
- }
- return *this;
- }
- /// Assignment operator
- Array<T, Allocator> & operator = (std::initializer_list<T> inRHS)
- {
- assign(inRHS);
- return *this;
- }
- /// Comparing arrays
- bool operator == (const Array<T, Allocator> &inRHS) const
- {
- if (mSize != inRHS.mSize)
- return false;
- for (size_type i = 0; i < mSize; ++i)
- if (!(mElements[i] == inRHS.mElements[i]))
- return false;
- return true;
- }
- bool operator != (const Array<T, Allocator> &inRHS) const
- {
- if (mSize != inRHS.mSize)
- return true;
- for (size_type i = 0; i < mSize; ++i)
- if (mElements[i] != inRHS.mElements[i])
- return true;
- return false;
- }
- private:
- size_type mSize = 0;
- size_type mCapacity = 0;
- T * mElements = nullptr;
- };
- JPH_NAMESPACE_END
- JPH_SUPPRESS_WARNING_PUSH
- JPH_CLANG_SUPPRESS_WARNING("-Wc++98-compat")
- namespace std
- {
- /// Declare std::hash for Array
- template <class T, class Allocator>
- struct hash<JPH::Array<T, Allocator>>
- {
- size_t operator () (const JPH::Array<T, Allocator> &inRHS) const
- {
- std::size_t ret = 0;
- // Hash length first
- JPH::HashCombine(ret, inRHS.size());
- // Then hash elements
- for (const T &t : inRHS)
- JPH::HashCombine(ret, t);
- return ret;
- }
- };
- }
- JPH_SUPPRESS_WARNING_POP
- #endif // JPH_USE_STD_VECTOR
|