java-topology/defects/box2d/patch/box2d-0001-broad-phase-index-map.patch

82 lines
2.8 KiB
Diff

# UNDF: UNDF-2026-000000015
--- a/src/broad_phase.h
+++ b/src/broad_phase.h
@@ -30,8 +30,9 @@ typedef struct b2BroadPhase
// The move set and array are used to track shapes that have moved significantly
// and need a pair query for new contacts. The array has a deterministic order.
- // todo perhaps just a move set?
- // todo implement a 32bit hash set for faster lookup
- // todo moveSet can grow quite large on the first time step and remain large
b2HashSet moveSet;
b2IntArray moveArray;
+ // Maps proxyKey+1 → index into moveArray for O(1) removal.
+ // Updated on every push and on every RemoveSwap (displaced element index fix-up).
+ b2HashTable moveIndex; // key: proxyKey+1, value: array index (stored in value field)
--- a/src/broad_phase.c
+++ b/src/broad_phase.c
@@ -35,6 +35,7 @@ void b2CreateBroadPhase( b2BroadPhase* bp )
bp->moveSet = b2CreateSet( 16 );
bp->moveArray = b2IntArray_Create( 16 );
+ bp->moveIndex = b2CreateTable( 16 );
bp->pairSet = b2CreateSet( 16 );
}
@@ -55,6 +56,7 @@ void b2DestroyBroadPhase( b2BroadPhase* bp )
b2DestroySet( &bp->moveSet );
b2IntArray_Destroy( &bp->moveArray );
+ b2DestroyTable( &bp->moveIndex );
b2DestroySet( &bp->pairSet );
@@ -63,25 +64,29 @@ void b2DestroyBroadPhase( b2BroadPhase* bp )
// in b2BufferMove — add both to moveSet (O(1)) and moveArray, recording the
// new array index into moveIndex (O(1)).
static inline void b2BufferMove( b2BroadPhase* bp, int queryProxy )
{
// Adding 1 because 0 is the sentinel
bool alreadyAdded = b2AddKey( &bp->moveSet, queryProxy + 1 );
if ( alreadyAdded == false )
{
+ int idx = bp->moveArray.count;
b2IntArray_Push( &bp->moveArray, queryProxy );
+ b2TableSet( &bp->moveIndex, (uint32_t)( queryProxy + 1 ), (uint32_t)idx );
}
}
static inline void b2UnBufferMove( b2BroadPhase* bp, int proxyKey )
{
bool found = b2RemoveKey( &bp->moveSet, proxyKey + 1 );
if ( found )
{
- // Purge from move buffer. Linear search.
- // todo if I can iterate the move set then I don't need the moveArray
- int count = bp->moveArray.count;
- for ( int i = 0; i < count; ++i )
- {
- if ( bp->moveArray.data[i] == proxyKey )
- {
- b2IntArray_RemoveSwap( &bp->moveArray, i );
- break;
- }
- }
+ // O(1) index lookup, then RemoveSwap with displaced-element fix-up.
+ uint32_t idx = b2TableGet( &bp->moveIndex, (uint32_t)( proxyKey + 1 ) );
+ b2TableRemove( &bp->moveIndex, (uint32_t)( proxyKey + 1 ) );
+ int last = bp->moveArray.count - 1;
+ if ( (int)idx != last )
+ {
+ // RemoveSwap moves the last element to position idx.
+ int displaced = bp->moveArray.data[last];
+ bp->moveArray.data[idx] = displaced;
+ bp->moveArray.count = last;
+ // Update the displaced element's index in the map.
+ b2TableSet( &bp->moveIndex, (uint32_t)( displaced + 1 ), idx );
+ }
+ else
+ {
+ bp->moveArray.count = last;
+ }
}
}