Files
godot/thirdparty/jolt_physics/Jolt/Core/StaticArray.h
noahbackus 9d30169a8d
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
initial commit, 4.5 stable
2025-09-16 20:46:46 -04:00

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