33#if defined( __SSE2__ )
35#elif defined( __ARM_NEON ) || defined( __ARM_NEON__ )
54inline uint64_t
HilbertXY2D(
int aOrder, uint32_t aX, uint32_t aY )
60 for( uint32_t s = ( 1U << ( aOrder - 1 ) ); s > 0; s >>= 1 )
62 uint32_t rx = ( x & s ) ? 1 : 0;
63 uint32_t ry = ( y & s ) ? 1 : 0;
65 d +=
static_cast<uint64_t
>( s ) * s * ( ( 3 * rx ) ^ ry );
98inline uint64_t
HilbertND2D(
int aOrder,
const uint32_t aCoords[NUMDIMS] )
100 if constexpr( NUMDIMS == 2 )
102 return HilbertXY2D( aOrder, aCoords[0], aCoords[1] );
112 const int bits = std::min( aOrder, 64 / NUMDIMS );
113 const int drop = aOrder - bits;
117 for(
int bit = bits - 1; bit >= 0; --bit )
119 for(
int dim = NUMDIMS - 1; dim >= 0; --dim )
122 d |= ( aCoords[dim] >> ( bit + drop ) ) & 1;
150template <
class ELEMTYPE,
int FANOUT>
151inline uint32_t
OverlapMask2D(
const ELEMTYPE* aBoundsMin0,
const ELEMTYPE* aBoundsMax0,
152 const ELEMTYPE* aBoundsMin1,
const ELEMTYPE* aBoundsMax1,
154 const ELEMTYPE aMin[2],
const ELEMTYPE aMax[2] )
156 static_assert( FANOUT <= 31,
"OverlapMask2D requires FANOUT <= 31" );
157 static_assert( FANOUT % 4 == 0,
"OverlapMask2D requires FANOUT divisible by 4 for SIMD" );
159#if defined( __SSE2__ )
160 if constexpr(
sizeof( ELEMTYPE ) == 4 )
163 __m128i qmin0 = _mm_set1_epi32(
static_cast<int>( aMin[0] ) );
164 __m128i qmax0 = _mm_set1_epi32(
static_cast<int>( aMax[0] ) );
165 __m128i qmin1 = _mm_set1_epi32(
static_cast<int>( aMin[1] ) );
166 __m128i qmax1 = _mm_set1_epi32(
static_cast<int>( aMax[1] ) );
174 for(
int j = 0; j < FANOUT; j += 4 )
176 __m128i bmin0 = _mm_loadu_si128(
177 reinterpret_cast<const __m128i*
>( &aBoundsMin0[j] ) );
178 __m128i bmax0 = _mm_loadu_si128(
179 reinterpret_cast<const __m128i*
>( &aBoundsMax0[j] ) );
180 __m128i bmin1 = _mm_loadu_si128(
181 reinterpret_cast<const __m128i*
>( &aBoundsMin1[j] ) );
182 __m128i bmax1 = _mm_loadu_si128(
183 reinterpret_cast<const __m128i*
>( &aBoundsMax1[j] ) );
186 __m128i fail = _mm_or_si128(
187 _mm_or_si128( _mm_cmpgt_epi32( bmin0, qmax0 ),
188 _mm_cmpgt_epi32( qmin0, bmax0 ) ),
189 _mm_or_si128( _mm_cmpgt_epi32( bmin1, qmax1 ),
190 _mm_cmpgt_epi32( qmin1, bmax1 ) ) );
193 int failBits = _mm_movemask_ps( _mm_castsi128_ps( fail ) );
194 mask |=
static_cast<uint32_t
>( ~failBits & 0xF ) << j;
197 return mask & ( ( 1U << aCount ) - 1 );
200#elif defined( __ARM_NEON ) || defined( __ARM_NEON__ )
201 if constexpr(
sizeof( ELEMTYPE ) == 4 )
204 int32x4_t qmin0 = vdupq_n_s32(
static_cast<int32_t
>( aMin[0] ) );
205 int32x4_t qmax0 = vdupq_n_s32(
static_cast<int32_t
>( aMax[0] ) );
206 int32x4_t qmin1 = vdupq_n_s32(
static_cast<int32_t
>( aMin[1] ) );
207 int32x4_t qmax1 = vdupq_n_s32(
static_cast<int32_t
>( aMax[1] ) );
211 static const int32_t kBitShifts[4] = { 0, 1, 2, 3 };
212 int32x4_t shifts = vld1q_s32( kBitShifts );
220 for(
int j = 0; j < FANOUT; j += 4 )
222 int32x4_t bmin0 = vld1q_s32(
223 reinterpret_cast<const int32_t*
>( &aBoundsMin0[j] ) );
224 int32x4_t bmax0 = vld1q_s32(
225 reinterpret_cast<const int32_t*
>( &aBoundsMax0[j] ) );
226 int32x4_t bmin1 = vld1q_s32(
227 reinterpret_cast<const int32_t*
>( &aBoundsMin1[j] ) );
228 int32x4_t bmax1 = vld1q_s32(
229 reinterpret_cast<const int32_t*
>( &aBoundsMax1[j] ) );
232 uint32x4_t fail = vorrq_u32(
233 vorrq_u32( vcgtq_s32( bmin0, qmax0 ),
234 vcgtq_s32( qmin0, bmax0 ) ),
235 vorrq_u32( vcgtq_s32( bmin1, qmax1 ),
236 vcgtq_s32( qmin1, bmax1 ) ) );
239 uint32x4_t bits = vshrq_n_u32( fail, 31 );
240 uint32x4_t positioned = vshlq_u32( bits, shifts );
243 uint32x2_t half = vorr_u32( vget_low_u32( positioned ),
244 vget_high_u32( positioned ) );
245 uint32_t failMask = vget_lane_u32( half, 0 ) | vget_lane_u32( half, 1 );
247 mask |=
static_cast<uint32_t
>( ~failMask & 0xF ) << j;
250 return mask & ( ( 1U << aCount ) - 1 );
266 for(
int i = 0; i < FANOUT; ++i )
268 result[i] = ( aBoundsMin0[i] <= aMax[0] )
269 & ( aBoundsMax0[i] >= aMin[0] )
270 & ( aBoundsMin1[i] <= aMax[1] )
271 & ( aBoundsMax1[i] >= aMin[1] );
276 for(
int i = 0; i < FANOUT; ++i )
277 mask |= (
static_cast<uint32_t
>(
result[i] ) << i );
279 return mask & ( ( 1U << aCount ) - 1 );
300template <
class DATATYPE,
class ELEMTYPE,
int NUMDIMS,
int MAXNODES>
341 for(
int d = 0; d < NUMDIMS; ++d )
343 aMin[d] = std::numeric_limits<ELEMTYPE>::max();
344 aMax[d] = std::numeric_limits<ELEMTYPE>::lowest();
347 for(
int i = 0; i <
count; ++i )
349 for(
int d = 0; d < NUMDIMS; ++d )
351 if(
bounds[d * 2][i] < aMin[d] )
352 aMin[d] =
bounds[d * 2][i];
354 if(
bounds[d * 2 + 1][i] > aMax[d] )
355 aMax[d] =
bounds[d * 2 + 1][i];
367 for(
int d = 0; d < NUMDIMS; ++d )
368 area *=
static_cast<int64_t
>(
bounds[d * 2 + 1][i] ) -
bounds[d * 2][i];
376 bool ChildOverlaps(
int i,
const ELEMTYPE aMin[NUMDIMS],
const ELEMTYPE aMax[NUMDIMS] )
const
378 for(
int d = 0; d < NUMDIMS; ++d )
380 if(
bounds[d * 2][i] > aMax[d] ||
bounds[d * 2 + 1][i] < aMin[d] )
392 const ELEMTYPE aMax[NUMDIMS] )
const
394 if constexpr( NUMDIMS == 2 )
403 for(
int i = 0; i <
count; ++i )
417 const ELEMTYPE aMax[NUMDIMS] )
const
421 for(
int d = 0; d < NUMDIMS; ++d )
423 ELEMTYPE lo = std::max(
bounds[d * 2][i], aMin[d] );
424 ELEMTYPE hi = std::min(
bounds[d * 2 + 1][i], aMax[d] );
429 overlap *=
static_cast<int64_t
>( hi ) - lo;
440 const ELEMTYPE aMax[NUMDIMS] )
const
443 int64_t enlargedArea = 1;
445 for(
int d = 0; d < NUMDIMS; ++d )
447 ELEMTYPE lo = std::min(
bounds[d * 2][i], aMin[d] );
448 ELEMTYPE hi = std::max(
bounds[d * 2 + 1][i], aMax[d] );
449 enlargedArea *=
static_cast<int64_t
>( hi ) - lo;
452 return enlargedArea - originalArea;
461 int64_t perimeter = 0;
463 for(
int d = 0; d < NUMDIMS; ++d )
464 perimeter +=
static_cast<int64_t
>(
bounds[d * 2 + 1][i] ) -
bounds[d * 2][i];
466 return 2 * perimeter;
472 void SetChildBounds(
int i,
const ELEMTYPE aMin[NUMDIMS],
const ELEMTYPE aMax[NUMDIMS] )
474 for(
int d = 0; d < NUMDIMS; ++d )
476 bounds[d * 2][i] = aMin[d];
477 bounds[d * 2 + 1][i] = aMax[d];
484 void GetChildBounds(
int i, ELEMTYPE aMin[NUMDIMS], ELEMTYPE aMax[NUMDIMS] )
const
486 for(
int d = 0; d < NUMDIMS; ++d )
488 aMin[d] =
bounds[d * 2][i];
489 aMax[d] =
bounds[d * 2 + 1][i];
496 void SetInsertBounds(
int i,
const ELEMTYPE aMin[NUMDIMS],
const ELEMTYPE aMax[NUMDIMS] )
498 for(
int d = 0; d < NUMDIMS; ++d )
510 for(
int d = 0; d < NUMDIMS; ++d )
523 int last =
count - 1;
527 for(
int d = 0; d < NUMDIMS * 2; ++d )
562 std::bitset<NODES_PER_PAGE>
used;
577 m_pages( std::move( aOther.m_pages ) ),
584 if(
this != &aOther )
586 m_pages = std::move( aOther.m_pages );
620 NODE* node = &page->nodes[i];
629 m_pages.push_back( std::make_unique<PAGE>() );
632 NODE* node = &page->
nodes[0];
664 bool Owns(
const NODE* aNode )
const
677 const auto addr =
reinterpret_cast<uintptr_t
>( aNode );
681 const auto begin =
reinterpret_cast<uintptr_t
>( &page->nodes[0] );
684 if( addr >= begin && addr <
end )
687 aOffset =
static_cast<size_t>( aNode - &page->nodes[0] );
701 page->
used.set( offset );
710 page->
used.reset( offset );
NODE * Allocate()
Allocate a new node, either from the free list or from a new page.
static constexpr size_t NODES_PER_PAGE
size_t MemoryUsage() const
Return approximate memory usage in bytes.
SLAB_ALLOCATOR & operator=(SLAB_ALLOCATOR &&aOther) noexcept
std::vector< std::unique_ptr< PAGE > > m_pages
SLAB_ALLOCATOR & operator=(const SLAB_ALLOCATOR &)=delete
void markUnused(NODE *aNode)
bool Owns(const NODE *aNode) const
Check if a node was allocated from one of this allocator's pages.
~SLAB_ALLOCATOR()=default
SLAB_ALLOCATOR(SLAB_ALLOCATOR &&aOther) noexcept
void Free(NODE *aNode)
Return a node to the free list for reuse.
SLAB_ALLOCATOR(const SLAB_ALLOCATOR &)=delete
PAGE * findOwningPage(const NODE *aNode, size_t &aOffset) const
Find the page that contains aNode using address-range comparison (no UB).
std::vector< NODE * > m_freeList
void markUsed(NODE *aNode)
uint64_t HilbertND2D(int aOrder, const uint32_t aCoords[NUMDIMS])
Compute Hilbert index for N-dimensional coordinates.
uint64_t HilbertXY2D(int aOrder, uint32_t aX, uint32_t aY)
Compute a 64-bit Hilbert curve index from 2D unsigned coordinates.
uint32_t OverlapMask2D(const ELEMTYPE *aBoundsMin0, const ELEMTYPE *aBoundsMax0, const ELEMTYPE *aBoundsMin1, const ELEMTYPE *aBoundsMax1, int aCount, const ELEMTYPE aMin[2], const ELEMTYPE aMax[2])
Compute a bitmask of which child slots overlap a 2D query rectangle.
static constexpr int MINNODES
int64_t ChildOverlapArea(int i, const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS]) const
Compute the overlap area between child slot i and the given box.
ELEMTYPE insertBounds[NUMDIMS *2][MAXNODES]
ELEMTYPE bounds[NUMDIMS *2][MAXNODES]
std::atomic< int > refcount
int64_t ChildEnlargement(int i, const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS]) const
Compute how much child slot i's area would increase if it were enlarged to include the given bounding...
int64_t ChildPerimeter(int i) const
Compute the perimeter (or margin for 3D) of child slot i's bounding box.
int64_t ChildArea(int i) const
Compute the area (or volume for 3D) of child slot i's bounding box.
void GetChildBounds(int i, ELEMTYPE aMin[NUMDIMS], ELEMTYPE aMax[NUMDIMS]) const
Get the bounding box for child slot i.
RTREE_NODE * children[MAXNODES]
uint32_t ChildOverlapMask(const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS]) const
Bitmask of children whose bounding boxes overlap the query rectangle.
bool ChildOverlaps(int i, const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS]) const
Test whether child slot i's bounding box overlaps with the given query box.
void SetChildBounds(int i, const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS])
Set the bounding box for child slot i.
void SetInsertBounds(int i, const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS])
Store the insertion bounding box for leaf entry i.
void GetInsertBounds(int i, ELEMTYPE aMin[NUMDIMS], ELEMTYPE aMax[NUMDIMS]) const
Get the stored insertion bounding box for leaf entry i.
void ComputeEnclosingBounds(ELEMTYPE aMin[NUMDIMS], ELEMTYPE aMax[NUMDIMS]) const
Compute the bounding box that encloses all children in this node.
void RemoveChild(int i)
Remove child at slot i by swapping with last entry.
NODE nodes[NODES_PER_PAGE]
std::bitset< NODES_PER_PAGE > used
wxString result
Test unit parsing edge cases and error handling.