diff options
Diffstat (limited to 'indra/llmath/lloctree.h')
-rw-r--r-- | indra/llmath/lloctree.h | 159 |
1 files changed, 112 insertions, 47 deletions
diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h index 3c1ae45d68..7348904c61 100644 --- a/indra/llmath/lloctree.h +++ b/indra/llmath/lloctree.h @@ -31,7 +31,6 @@ #include "v3math.h" #include "llvector4a.h" #include <vector> -#include <set> #define OCT_ERRS LL_WARNS("OctreeErrors") @@ -79,16 +78,18 @@ public: typedef LLOctreeTraveler<T> oct_traveler; typedef LLTreeTraveler<T> tree_traveler; - typedef typename std::set<LLPointer<T> > element_list; - typedef typename std::set<LLPointer<T> >::iterator element_iter; - typedef typename std::set<LLPointer<T> >::const_iterator const_element_iter; + typedef std::vector< LLPointer<T> > element_list; // note: don't remove the whitespace between "> >" + typedef LLPointer<T>* element_iter; + typedef const LLPointer<T>* const_element_iter; typedef typename std::vector<LLTreeListener<T>*>::iterator tree_listener_iter; - typedef typename std::vector<LLOctreeNode<T>* > child_list; + typedef LLOctreeNode<T>** child_list; + typedef LLOctreeNode<T>** child_iter; + typedef LLTreeNode<T> BaseType; typedef LLOctreeNode<T> oct_node; typedef LLOctreeListener<T> oct_listener; - /*void* operator new(size_t size) + void* operator new(size_t size) { return ll_aligned_malloc_16(size); } @@ -96,7 +97,7 @@ public: void operator delete(void* ptr) { ll_aligned_free_16(ptr); - }*/ + } LLOctreeNode( const LLVector4a& center, const LLVector4a& size, @@ -105,6 +106,10 @@ public: : mParent((oct_node*)parent), mOctant(octant) { + //always keep a NULL terminated list to avoid out of bounds exceptions in debug builds + mData.push_back(NULL); + mDataEnd = &mData[0]; + mCenter = center; mSize = size; @@ -114,6 +119,8 @@ public: mOctant = ((oct_node*) mParent)->getOctant(mCenter); } + mElementCount = 0; + clearChildren(); } @@ -121,6 +128,16 @@ public: { BaseType::destroyListeners(); + for (U32 i = 0; i < mElementCount; ++i) + { + mData[i]->setBinIndex(-1); + mData[i] = NULL; + } + + mData.clear(); + mData.push_back(NULL); + mDataEnd = &mData[0]; + for (U32 i = 0; i < getChildCount(); i++) { delete getChild(i); @@ -217,13 +234,18 @@ public: } void accept(oct_traveler* visitor) { visitor->visit(this); } - virtual bool isLeaf() const { return mChild.empty(); } + virtual bool isLeaf() const { return mChildCount == 0; } - U32 getElementCount() const { return mData.size(); } + U32 getElementCount() const { return mElementCount; } + bool isEmpty() const { return mElementCount == 0; } element_list& getData() { return mData; } const element_list& getData() const { return mData; } - - U32 getChildCount() const { return mChild.size(); } + element_iter getDataBegin() { return &mData[0]; } + element_iter getDataEnd() { return mDataEnd; } + const_element_iter getDataBegin() const { return &mData[0]; } + const_element_iter getDataEnd() const { return mDataEnd; } + + U32 getChildCount() const { return mChildCount; } oct_node* getChild(U32 index) { return mChild[index]; } const oct_node* getChild(U32 index) const { return mChild[index]; } child_list& getChildren() { return mChild; } @@ -287,7 +309,7 @@ public: virtual bool insert(T* data) { - if (data == NULL) + if (data == NULL || data->getBinIndex() != -1) { OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << llendl; return false; @@ -300,16 +322,11 @@ public: if ((getElementCount() < gOctreeMaxCapacity && contains(data->getBinRadius()) || (data->getBinRadius() > getSize()[0] && parent && parent->getElementCount() >= gOctreeMaxCapacity))) { //it belongs here -#if LL_OCTREE_PARANOIA_CHECK - //if this is a redundant insertion, error out (should never happen) - if (mData.find(data) != mData.end()) - { - llwarns << "Redundant octree insertion detected. " << data << llendl; - return false; - } -#endif - - mData.insert(data); + mData.push_back(NULL); + mData[mElementCount] = data; + mElementCount++; + mDataEnd = &mData[mElementCount]; + data->setBinIndex(mElementCount-1); BaseType::insert(data); return true; } @@ -344,7 +361,11 @@ public: if( lt == 0x7 ) { - mData.insert(data); + mData.push_back(NULL); + mData[mElementCount] = data; + mElementCount++; + mDataEnd = &mData[mElementCount]; + data->setBinIndex(mElementCount-1); BaseType::insert(data); return true; } @@ -394,22 +415,58 @@ public: return false; } + void _remove(T* data, S32 i) + { //precondition -- mElementCount > 0, idx is in range [0, mElementCount) + + mElementCount--; + data->setBinIndex(-1); + + if (mElementCount > 0) + { + if (mElementCount != i) + { + mData[i] = mData[mElementCount]; //might unref data, do not access data after this point + mData[i]->setBinIndex(i); + } + + mData[mElementCount] = NULL; + mData.pop_back(); + mDataEnd = &mData[mElementCount]; + } + else + { + mData.clear(); + mData.push_back(NULL); + mDataEnd = &mData[0]; + } + + notifyRemoval(data); + checkAlive(); + } + bool remove(T* data) { - if (mData.find(data) != mData.end()) - { //we have data - mData.erase(data); - notifyRemoval(data); - checkAlive(); - return true; - } - else if (isInside(data)) + S32 i = data->getBinIndex(); + + if (i >= 0 && i < mElementCount) + { + if (mData[i] == data) + { //found it + _remove(data, i); + llassert(data->getBinIndex() == -1); + return true; + } + } + + if (isInside(data)) { oct_node* dest = getNodeAt(data); if (dest != this) { - return dest->remove(data); + bool ret = dest->remove(data); + llassert(data->getBinIndex() == -1); + return ret; } } @@ -426,20 +483,22 @@ public: } //node is now root - llwarns << "!!! OCTREE REMOVING FACE BY ADDRESS, SEVERE PERFORMANCE PENALTY |||" << llendl; + llwarns << "!!! OCTREE REMOVING ELEMENT BY ADDRESS, SEVERE PERFORMANCE PENALTY |||" << llendl; node->removeByAddress(data); + llassert(data->getBinIndex() == -1); return true; } void removeByAddress(T* data) { - if (mData.find(data) != mData.end()) + for (U32 i = 0; i < mElementCount; ++i) { - mData.erase(data); - notifyRemoval(data); - llwarns << "FOUND!" << llendl; - checkAlive(); - return; + if (mData[i] == data) + { //we have data + _remove(data, i); + llwarns << "FOUND!" << llendl; + return; + } } for (U32 i = 0; i < getChildCount(); i++) @@ -451,7 +510,7 @@ public: void clearChildren() { - mChild.clear(); + mChildCount = 0; U32* foo = (U32*) mChildMap; foo[0] = foo[1] = 0xFFFFFFFF; @@ -512,9 +571,10 @@ public: } #endif - mChildMap[child->getOctant()] = (U8) mChild.size(); + mChildMap[child->getOctant()] = mChildCount; - mChild.push_back(child); + mChild[mChildCount] = child; + ++mChildCount; child->setParent(this); if (!silent) @@ -534,21 +594,23 @@ public: oct_listener* listener = getOctListener(i); listener->handleChildRemoval(this, getChild(index)); } - - if (destroy) { mChild[index]->destroy(); delete mChild[index]; } - mChild.erase(mChild.begin() + index); + + --mChildCount; + + mChild[index] = mChild[mChildCount]; + //rebuild child map U32* foo = (U32*) mChildMap; foo[0] = foo[1] = 0xFFFFFFFF; - for (U32 i = 0; i < mChild.size(); ++i) + for (U32 i = 0; i < mChildCount; ++i) { mChildMap[mChild[i]->getOctant()] = i; } @@ -599,10 +661,13 @@ protected: oct_node* mParent; U8 mOctant; - child_list mChild; + LLOctreeNode<T>* mChild[8]; U8 mChildMap[8]; + U32 mChildCount; element_list mData; + element_iter mDataEnd; + U32 mElementCount; }; |