Projekt_Grafika/dependencies/physx-4.1/source/common/src/CmPriorityQueue.h
Jakub Adamski f5087ee7b6 new repo
2021-01-29 17:02:11 +01:00

238 lines
6.7 KiB
C++

//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of NVIDIA CORPORATION nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (c) 2008-2019 NVIDIA Corporation. All rights reserved.
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
#ifndef PX_PHYSICS_COMMON_PRIORITYQUEUE
#define PX_PHYSICS_COMMON_PRIORITYQUEUE
#include "PsBasicTemplates.h"
#include "CmPhysXCommon.h"
#include "PsAllocator.h"
#include "foundation/PxMemory.h"
namespace physx
{
namespace Cm
{
template<class Element, class Comparator = Ps::Less<Element> >
class PriorityQueueBase : protected Comparator // inherit so that stateless comparators take no space
{
public:
PriorityQueueBase(const Comparator& less, Element* elements) : Comparator(less), mHeapSize(0), mDataPtr(elements)
{
}
~PriorityQueueBase()
{
}
//! Get the element with the highest priority
PX_FORCE_INLINE const Element top() const
{
return mDataPtr[0];
}
//! Get the element with the highest priority
PX_FORCE_INLINE Element top()
{
return mDataPtr[0];
}
//! Check to whether the priority queue is empty
PX_FORCE_INLINE bool empty() const
{
return (mHeapSize == 0);
}
//! Empty the priority queue
PX_FORCE_INLINE void clear()
{
mHeapSize = 0;
}
//! Insert a new element into the priority queue. Only valid when size() is less than Capacity
PX_FORCE_INLINE void push(const Element& value)
{
PxU32 newIndex;
PxU32 parentIndex = parent(mHeapSize);
for (newIndex = mHeapSize; newIndex > 0 && compare(value, mDataPtr[parentIndex]); newIndex = parentIndex, parentIndex= parent(newIndex))
{
mDataPtr[ newIndex ] = mDataPtr[parentIndex];
}
mDataPtr[newIndex] = value;
mHeapSize++;
PX_ASSERT(valid());
}
//! Delete the highest priority element. Only valid when non-empty.
PX_FORCE_INLINE Element pop()
{
PX_ASSERT(mHeapSize > 0);
PxU32 i, child;
//try to avoid LHS
PxU32 tempHs = mHeapSize-1;
mHeapSize = tempHs;
Element min = mDataPtr[0];
Element last = mDataPtr[tempHs];
for (i = 0; (child = left(i)) < tempHs; i = child)
{
/* Find highest priority child */
const PxU32 rightChild = child + 1;
child += ((rightChild < tempHs) & compare((mDataPtr[rightChild]), (mDataPtr[child]))) ? 1 : 0;
if(compare(last, mDataPtr[child]))
break;
mDataPtr[i] = mDataPtr[child];
}
mDataPtr[ i ] = last;
PX_ASSERT(valid());
return min;
}
//! Make sure the priority queue sort all elements correctly
bool valid() const
{
const Element& min = mDataPtr[0];
for(PxU32 i=1; i<mHeapSize; ++i)
{
if(compare(mDataPtr[i], min))
return false;
}
return true;
}
//! Return number of elements in the priority queue
PxU32 size() const
{
return mHeapSize;
}
protected:
PxU32 mHeapSize;
Element* mDataPtr;
PX_FORCE_INLINE bool compare(const Element& a, const Element& b) const
{
return Comparator::operator()(a,b);
}
static PX_FORCE_INLINE PxU32 left(PxU32 nodeIndex)
{
return (nodeIndex << 1) + 1;
}
static PX_FORCE_INLINE PxU32 parent(PxU32 nodeIndex)
{
return (nodeIndex - 1) >> 1;
}
private:
PriorityQueueBase<Element, Comparator>& operator = (const PriorityQueueBase<Element, Comparator>);
};
template <typename Element, PxU32 Capacity, typename Comparator>
class InlinePriorityQueue : public PriorityQueueBase<Element, Comparator>
{
Element mData[Capacity];
public:
InlinePriorityQueue(const Comparator& less = Comparator()) : PriorityQueueBase<Element, Comparator>(less, mData)
{
}
PX_FORCE_INLINE void push(Element& elem)
{
PX_ASSERT(this->mHeapSize < Capacity);
PriorityQueueBase<Element, Comparator>::push(elem);
}
private:
InlinePriorityQueue<Element, Capacity, Comparator>& operator = (const InlinePriorityQueue<Element, Capacity, Comparator>);
};
template <typename Element, typename Comparator, typename Alloc = typename physx::shdfnd::AllocatorTraits<Element>::Type>
class PriorityQueue : public PriorityQueueBase<Element, Comparator>, protected Alloc
{
PxU32 mCapacity;
public:
PriorityQueue(const Comparator& less = Comparator(), PxU32 initialCapacity = 0, Alloc alloc = Alloc())
: PriorityQueueBase<Element, Comparator>(less, NULL), Alloc(alloc), mCapacity(initialCapacity)
{
if(initialCapacity > 0)
this->mDataPtr = reinterpret_cast<Element*>(Alloc::allocate(sizeof(Element)*initialCapacity, __FILE__, __LINE__));
}
~PriorityQueue()
{
if(this->mDataPtr)
this->deallocate(this->mDataPtr);
}
PX_FORCE_INLINE void push(Element& elem)
{
if(this->mHeapSize == mCapacity)
{
reserve((this->mHeapSize+1)*2);
}
PriorityQueueBase<Element, Comparator>::push(elem);
}
PX_FORCE_INLINE PxU32 capacity()
{
return mCapacity;
}
PX_FORCE_INLINE void reserve(const PxU32 newCapacity)
{
if(newCapacity > mCapacity)
{
Element* newElems = reinterpret_cast<Element*>(Alloc::allocate(sizeof(Element)*newCapacity, __FILE__, __LINE__));
if(this->mDataPtr)
{
physx::PxMemCopy(newElems, this->mDataPtr, sizeof(Element) * this->mHeapSize);
Alloc::deallocate(this->mDataPtr);
}
this->mDataPtr = newElems;
mCapacity = newCapacity;
}
}
private:
PriorityQueue<Element, Comparator, Alloc>& operator = (const PriorityQueue<Element, Comparator, Alloc>);
};
}
}
#endif