Some checks failed
🔗 GHA / 📊 Static checks (push) Has been cancelled
🔗 GHA / 🤖 Android (push) Has been cancelled
🔗 GHA / 🍏 iOS (push) Has been cancelled
🔗 GHA / 🐧 Linux (push) Has been cancelled
🔗 GHA / 🍎 macOS (push) Has been cancelled
🔗 GHA / 🏁 Windows (push) Has been cancelled
🔗 GHA / 🌐 Web (push) Has been cancelled
330 lines
7.3 KiB
C++
330 lines
7.3 KiB
C++
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
|
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
#pragma once
|
|
|
|
#include <Jolt/Core/HashCombine.h>
|
|
|
|
JPH_NAMESPACE_BEGIN
|
|
|
|
/// Simple variable length array backed by a fixed size buffer
|
|
template <class T, uint N>
|
|
class [[nodiscard]] StaticArray
|
|
{
|
|
public:
|
|
using value_type = T;
|
|
|
|
using size_type = uint;
|
|
|
|
static constexpr uint Capacity = N;
|
|
|
|
/// Default constructor
|
|
StaticArray() = default;
|
|
|
|
/// Constructor from initializer list
|
|
explicit StaticArray(std::initializer_list<T> inList)
|
|
{
|
|
JPH_ASSERT(inList.size() <= N);
|
|
for (const T &v : inList)
|
|
new (reinterpret_cast<T *>(&mElements[mSize++])) T(v);
|
|
}
|
|
|
|
/// Copy constructor
|
|
StaticArray(const StaticArray<T, N> &inRHS)
|
|
{
|
|
while (mSize < inRHS.mSize)
|
|
{
|
|
new (&mElements[mSize]) T(inRHS[mSize]);
|
|
++mSize;
|
|
}
|
|
}
|
|
|
|
/// Destruct all elements
|
|
~StaticArray()
|
|
{
|
|
if constexpr (!std::is_trivially_destructible<T>())
|
|
for (T *e = reinterpret_cast<T *>(mElements), *end = e + mSize; e < end; ++e)
|
|
e->~T();
|
|
}
|
|
|
|
/// Destruct all elements and set length to zero
|
|
void clear()
|
|
{
|
|
if constexpr (!std::is_trivially_destructible<T>())
|
|
for (T *e = reinterpret_cast<T *>(mElements), *end = e + mSize; e < end; ++e)
|
|
e->~T();
|
|
mSize = 0;
|
|
}
|
|
|
|
/// Add element to the back of the array
|
|
void push_back(const T &inElement)
|
|
{
|
|
JPH_ASSERT(mSize < N);
|
|
new (&mElements[mSize++]) T(inElement);
|
|
}
|
|
|
|
/// Construct element at the back of the array
|
|
template <class... A>
|
|
void emplace_back(A &&... inElement)
|
|
{
|
|
JPH_ASSERT(mSize < N);
|
|
new (&mElements[mSize++]) T(std::forward<A>(inElement)...);
|
|
}
|
|
|
|
/// Remove element from the back of the array
|
|
void pop_back()
|
|
{
|
|
JPH_ASSERT(mSize > 0);
|
|
reinterpret_cast<T &>(mElements[--mSize]).~T();
|
|
}
|
|
|
|
/// Returns true if there are no elements in the array
|
|
bool empty() const
|
|
{
|
|
return mSize == 0;
|
|
}
|
|
|
|
/// Returns amount of elements in the array
|
|
size_type size() const
|
|
{
|
|
return mSize;
|
|
}
|
|
|
|
/// Returns maximum amount of elements the array can hold
|
|
size_type capacity() const
|
|
{
|
|
return N;
|
|
}
|
|
|
|
/// Resize array to new length
|
|
void resize(size_type inNewSize)
|
|
{
|
|
JPH_ASSERT(inNewSize <= N);
|
|
if constexpr (!std::is_trivially_constructible<T>())
|
|
for (T *element = reinterpret_cast<T *>(mElements) + mSize, *element_end = reinterpret_cast<T *>(mElements) + inNewSize; element < element_end; ++element)
|
|
new (element) T;
|
|
if constexpr (!std::is_trivially_destructible<T>())
|
|
for (T *element = reinterpret_cast<T *>(mElements) + inNewSize, *element_end = reinterpret_cast<T *>(mElements) + mSize; element < element_end; ++element)
|
|
element->~T();
|
|
mSize = inNewSize;
|
|
}
|
|
|
|
using const_iterator = const T *;
|
|
|
|
/// Iterators
|
|
const_iterator begin() const
|
|
{
|
|
return reinterpret_cast<const T *>(mElements);
|
|
}
|
|
|
|
const_iterator end() const
|
|
{
|
|
return reinterpret_cast<const T *>(mElements + mSize);
|
|
}
|
|
|
|
using iterator = T *;
|
|
|
|
iterator begin()
|
|
{
|
|
return reinterpret_cast<T *>(mElements);
|
|
}
|
|
|
|
iterator end()
|
|
{
|
|
return reinterpret_cast<T *>(mElements + mSize);
|
|
}
|
|
|
|
const T * data() const
|
|
{
|
|
return reinterpret_cast<const T *>(mElements);
|
|
}
|
|
|
|
T * data()
|
|
{
|
|
return reinterpret_cast<T *>(mElements);
|
|
}
|
|
|
|
/// Access element
|
|
T & operator [] (size_type inIdx)
|
|
{
|
|
JPH_ASSERT(inIdx < mSize);
|
|
return reinterpret_cast<T &>(mElements[inIdx]);
|
|
}
|
|
|
|
const T & operator [] (size_type inIdx) const
|
|
{
|
|
JPH_ASSERT(inIdx < mSize);
|
|
return reinterpret_cast<const T &>(mElements[inIdx]);
|
|
}
|
|
|
|
/// Access element
|
|
T & at(size_type inIdx)
|
|
{
|
|
JPH_ASSERT(inIdx < mSize);
|
|
return reinterpret_cast<T &>(mElements[inIdx]);
|
|
}
|
|
|
|
const T & at(size_type inIdx) const
|
|
{
|
|
JPH_ASSERT(inIdx < mSize);
|
|
return reinterpret_cast<const T &>(mElements[inIdx]);
|
|
}
|
|
|
|
/// First element in the array
|
|
const T & front() const
|
|
{
|
|
JPH_ASSERT(mSize > 0);
|
|
return reinterpret_cast<const T &>(mElements[0]);
|
|
}
|
|
|
|
T & front()
|
|
{
|
|
JPH_ASSERT(mSize > 0);
|
|
return reinterpret_cast<T &>(mElements[0]);
|
|
}
|
|
|
|
/// Last element in the array
|
|
const T & back() const
|
|
{
|
|
JPH_ASSERT(mSize > 0);
|
|
return reinterpret_cast<const T &>(mElements[mSize - 1]);
|
|
}
|
|
|
|
T & back()
|
|
{
|
|
JPH_ASSERT(mSize > 0);
|
|
return reinterpret_cast<T &>(mElements[mSize - 1]);
|
|
}
|
|
|
|
/// Remove one element from the array
|
|
void erase(const_iterator inIter)
|
|
{
|
|
size_type p = size_type(inIter - begin());
|
|
JPH_ASSERT(p < mSize);
|
|
reinterpret_cast<T &>(mElements[p]).~T();
|
|
if (p + 1 < mSize)
|
|
memmove(mElements + p, mElements + p + 1, (mSize - p - 1) * sizeof(T));
|
|
--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());
|
|
for (size_type i = 0; i < n; ++i)
|
|
reinterpret_cast<T &>(mElements[p + i]).~T();
|
|
if (p + n < mSize)
|
|
memmove(mElements + p, mElements + p + n, (mSize - p - n) * sizeof(T));
|
|
mSize -= n;
|
|
}
|
|
|
|
/// Assignment operator
|
|
StaticArray<T, N> & operator = (const StaticArray<T, N> &inRHS)
|
|
{
|
|
size_type rhs_size = inRHS.size();
|
|
|
|
if (static_cast<const void *>(this) != static_cast<const void *>(&inRHS))
|
|
{
|
|
clear();
|
|
|
|
while (mSize < rhs_size)
|
|
{
|
|
new (&mElements[mSize]) T(inRHS[mSize]);
|
|
++mSize;
|
|
}
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
/// Assignment operator with static array of different max length
|
|
template <uint M>
|
|
StaticArray<T, N> & operator = (const StaticArray<T, M> &inRHS)
|
|
{
|
|
size_type rhs_size = inRHS.size();
|
|
JPH_ASSERT(rhs_size <= N);
|
|
|
|
if (static_cast<const void *>(this) != static_cast<const void *>(&inRHS))
|
|
{
|
|
clear();
|
|
|
|
while (mSize < rhs_size)
|
|
{
|
|
new (&mElements[mSize]) T(inRHS[mSize]);
|
|
++mSize;
|
|
}
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
/// Comparing arrays
|
|
bool operator == (const StaticArray<T, N> &inRHS) const
|
|
{
|
|
if (mSize != inRHS.mSize)
|
|
return false;
|
|
for (size_type i = 0; i < mSize; ++i)
|
|
if (!(reinterpret_cast<const T &>(mElements[i]) == reinterpret_cast<const T &>(inRHS.mElements[i])))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool operator != (const StaticArray<T, N> &inRHS) const
|
|
{
|
|
if (mSize != inRHS.mSize)
|
|
return true;
|
|
for (size_type i = 0; i < mSize; ++i)
|
|
if (reinterpret_cast<const T &>(mElements[i]) != reinterpret_cast<const T &>(inRHS.mElements[i]))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/// Get hash for this array
|
|
uint64 GetHash() const
|
|
{
|
|
// Hash length first
|
|
uint64 ret = Hash<uint32> { } (uint32(size()));
|
|
|
|
// Then hash elements
|
|
for (const T *element = reinterpret_cast<const T *>(mElements), *element_end = reinterpret_cast<const T *>(mElements) + mSize; element < element_end; ++element)
|
|
HashCombine(ret, *element);
|
|
|
|
return ret;
|
|
}
|
|
|
|
protected:
|
|
struct alignas(T) Storage
|
|
{
|
|
uint8 mData[sizeof(T)];
|
|
};
|
|
|
|
static_assert(sizeof(T) == sizeof(Storage), "Mismatch in size");
|
|
static_assert(alignof(T) == alignof(Storage), "Mismatch in alignment");
|
|
|
|
size_type mSize = 0;
|
|
Storage mElements[N];
|
|
};
|
|
|
|
JPH_NAMESPACE_END
|
|
|
|
JPH_SUPPRESS_WARNING_PUSH
|
|
JPH_CLANG_SUPPRESS_WARNING("-Wc++98-compat")
|
|
|
|
namespace std
|
|
{
|
|
/// Declare std::hash for StaticArray
|
|
template <class T, JPH::uint N>
|
|
struct hash<JPH::StaticArray<T, N>>
|
|
{
|
|
size_t operator () (const JPH::StaticArray<T, N> &inRHS) const
|
|
{
|
|
return std::size_t(inRHS.GetHash());
|
|
}
|
|
};
|
|
}
|
|
|
|
JPH_SUPPRESS_WARNING_POP
|