RavEngine
Loading...
Searching...
No Matches
PxBitMap.h
1// Redistribution and use in source and binary forms, with or without
2// modification, are permitted provided that the following conditions
3// are met:
4// * Redistributions of source code must retain the above copyright
5// notice, this list of conditions and the following disclaimer.
6// * Redistributions in binary form must reproduce the above copyright
7// notice, this list of conditions and the following disclaimer in the
8// documentation and/or other materials provided with the distribution.
9// * Neither the name of NVIDIA CORPORATION nor the names of its
10// contributors may be used to endorse or promote products derived
11// from this software without specific prior written permission.
12//
13// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
14// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24//
25// Copyright (c) 2008-2022 NVIDIA Corporation. All rights reserved.
26// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
27// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
28
29#ifndef PX_BITMAP_H
30#define PX_BITMAP_H
31
32#include "foundation/PxAssert.h"
33#include "foundation/PxMath.h"
34#include "foundation/PxMemory.h"
35#include "foundation/PxAllocator.h"
36#include "foundation/PxUserAllocated.h"
37#include "foundation/PxIntrinsics.h"
38#include "foundation/PxBitUtils.h"
39
40#if !PX_DOXYGEN
41namespace physx
42{
43#endif
50 template<class PxAllocator>
52 {
53 //= ATTENTION! =====================================================================================
54 // Changing the data layout of this class breaks the binary serialization format. See comments for
55 // PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData
56 // function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION
57 // accordingly.
58 //==================================================================================================
59
60 PX_NOCOPY(PxBitMapBase)
61
62 public:
63
64 // PX_SERIALIZATION
65 /* todo: explicit */ PxBitMapBase(const PxEMPTY)
66 {
67 if (mMap)
68 mWordCount |= PX_SIGN_BITMASK;
69 }
70 //~PX_SERIALIZATION
71
72 PX_INLINE PxBitMapBase(const PxAllocator& allocator) : mMap(0), mWordCount(0), mAllocator(allocator) {}
73
74 PX_INLINE PxBitMapBase() : mMap(0), mWordCount(0) {}
75
77 {
78 release();
79 }
80
81 PX_INLINE void release()
82 {
83 if (mMap && !isInUserMemory())
84 mAllocator.deallocate(mMap);
85 mMap = NULL;
86 }
87
88 PX_INLINE PxAllocator& getAllocator() { return mAllocator; }
89
90 PX_INLINE void growAndSet(PxU32 index)
91 {
92 extend(index + 1);
93 mMap[index >> 5] |= 1 << (index & 31);
94 }
95
96 PX_INLINE void growAndReset(PxU32 index)
97 {
98 extend(index + 1);
99 mMap[index >> 5] &= ~(1 << (index & 31));
100 }
101
102 PX_INLINE PxIntBool boundedTest(PxU32 index) const
103 {
104 return PxIntBool(index >> 5 >= getWordCount() ? PxIntFalse : (mMap[index >> 5] & (1 << (index & 31))));
105 }
106
107 PX_INLINE void boundedReset(PxU32 index)
108 {
109 if((index >> 5) < getWordCount())
110 mMap[index >> 5] &= ~(1 << (index & 31));
111 }
112
113 // Special optimized versions, when you _know_ your index is in range
114 PX_INLINE void set(PxU32 index)
115 {
116 PX_ASSERT(index<getWordCount() * 32);
117 mMap[index >> 5] |= 1 << (index & 31);
118 }
119
120 PX_INLINE void reset(PxU32 index)
121 {
122 PX_ASSERT(index<getWordCount() * 32);
123 mMap[index >> 5] &= ~(1 << (index & 31));
124 }
125
126 PX_INLINE PxIntBool test(PxU32 index) const
127 {
128 PX_ASSERT(index<getWordCount() * 32);
129 return PxIntBool(mMap[index >> 5] & (1 << (index & 31)));
130 }
131
132 // nibble == 4 bits
133 PX_INLINE PxU32 getNibbleFast(PxU32 nibIndex) const
134 {
135 const PxU32 bitIndex = nibIndex << 2;
136 PX_ASSERT(bitIndex < getWordCount() * 32);
137 return (mMap[bitIndex >> 5] >> (bitIndex & 31)) & 0xf;
138 }
139
140 PX_INLINE void andNibbleFast(PxU32 nibIndex, PxU32 mask)
141 {
142 //TODO: there has to be a faster way...
143 const PxU32 bitIndex = nibIndex << 2;
144 const PxU32 shift = (bitIndex & 31);
145 const PxU32 nibMask = (0xfu << shift);
146
147 PX_ASSERT(bitIndex < getWordCount() * 32);
148
149 mMap[bitIndex >> 5] &= ((mask << shift) | ~nibMask);
150 }
151
152 PX_INLINE void orNibbleFast(PxU32 nibIndex, PxU32 mask)
153 {
154 PX_ASSERT(!(mask & ~0xfu)); //check extra bits are not set
155
156 const PxU32 bitIndex = nibIndex << 2;
157 const PxU32 shift = bitIndex & 31;
158
159 PX_ASSERT(bitIndex < getWordCount() * 32);
160
161 mMap[bitIndex >> 5] |= (mask << shift);
162 }
163
164 void clear()
165 {
166 PxMemSet(mMap, 0, getWordCount() * sizeof(PxU32));
167 }
168
169 void resizeAndClear(PxU32 newBitCount)
170 {
171 extendUninitialized(newBitCount);
172 PxMemSet(mMap, 0, getWordCount() * sizeof(PxU32));
173 }
174
175 void setEmpty()
176 {
177 mMap = NULL;
178 mWordCount = 0;
179 }
180
181 void setWords(PxU32* map, PxU32 wordCount)
182 {
183 mMap = map;
184 mWordCount = wordCount;
185 mWordCount |= PX_SIGN_BITMASK;
186 }
187
188 // !!! only sets /last/ bit to value
189 void resize(PxU32 newBitCount, bool value = false)
190 {
191 PX_ASSERT(!value); // only new class supports this
192 PX_UNUSED(value);
193 extend(newBitCount);
194 }
195
196 PxU32 size() const { return getWordCount() * 32; }
197
198 void copy(const PxBitMapBase& a)
199 {
200 extendUninitialized(a.getWordCount() << 5);
201 PxMemCopy(mMap, a.mMap, a.getWordCount() * sizeof(PxU32));
202 if (getWordCount() > a.getWordCount())
203 PxMemSet(mMap + a.getWordCount(), 0, (getWordCount() - a.getWordCount()) * sizeof(PxU32));
204 }
205
206 PX_INLINE PxU32 count() const
207 {
208 // NOTE: we can probably do this faster, since the last steps in PxcBitCount32 can be defered to
209 // the end of the seq. + 64/128bits at a time + native bit counting instructions(360 is fast non micro code).
210 PxU32 count = 0;
211 const PxU32 wordCount = getWordCount();
212 for (PxU32 i = 0; i<wordCount; i++)
213 count += PxBitCount(mMap[i]);
214
215 return count;
216 }
217
218 PX_INLINE PxU32 count(PxU32 start, PxU32 length) const
219 {
220 const PxU32 end = PxMin(getWordCount() << 5, start + length);
221 PxU32 count = 0;
222 for (PxU32 i = start; i<end; i++)
223 count += (test(i) != 0);
224 return count;
225 }
226
228 PxU32 findLast() const
229 {
230 const PxU32 wordCount = getWordCount();
231 for (PxU32 i = wordCount; i-- > 0;)
232 {
233 if (mMap[i])
234 return (i << 5) + PxHighestSetBit(mMap[i]);
235 }
236 return PxU32(0);
237 }
238
239 // the obvious combiners and some used in the SDK
240
241 struct OR { PX_INLINE PxU32 operator()(PxU32 a, PxU32 b) { return a | b; } };
242 struct AND { PX_INLINE PxU32 operator()(PxU32 a, PxU32 b) { return a&b; } };
243 struct XOR { PX_INLINE PxU32 operator()(PxU32 a, PxU32 b) { return a^b; } };
244
245 // we use auxiliary functions here so as not to generate combiners for every combination
246 // of allocators
247
248 template<class Combiner, class _>
249 PX_INLINE void combineInPlace(const PxBitMapBase<_>& b)
250 {
251 combine1<Combiner>(b.mMap, b.getWordCount());
252 }
253
254 template<class Combiner, class _1, class _2>
255 PX_INLINE void combine(const PxBitMapBase<_1>& a, const PxBitMapBase<_2>& b)
256 {
257 combine2<Combiner>(a.mMap, a.getWordCount(), b.mMap, b.getWordCount());
258 }
259
260 PX_FORCE_INLINE const PxU32* getWords() const { return mMap; }
261 PX_FORCE_INLINE PxU32* getWords() { return mMap; }
262
263 // PX_SERIALIZATION
264 PX_FORCE_INLINE PxU32 getWordCount() const { return mWordCount & ~PX_SIGN_BITMASK; }
265
266 // We need one bit to mark arrays that have been deserialized from a user-provided memory block.
267 PX_FORCE_INLINE PxU32 isInUserMemory() const { return mWordCount & PX_SIGN_BITMASK; }
268 //~PX_SERIALIZATION
269
278 {
279 public:
280 static const PxU32 DONE = 0xffffffff;
281
282 PX_INLINE Iterator(const PxBitMapBase &map) : mBitMap(map)
283 {
284 reset();
285 }
286
287 PX_INLINE Iterator& operator=(const Iterator& other)
288 {
289 PX_ASSERT(&mBitMap == &other.mBitMap);
290 mBlock = other.mBlock;
291 mIndex = other.mIndex;
292 return *this;
293 }
294
295 PX_INLINE PxU32 getNext()
296 {
297 if (mBlock)
298 {
299 PxU32 bitIndex = mIndex << 5 | PxLowestSetBit(mBlock);
300 mBlock &= mBlock - 1;
301 PxU32 wordCount = mBitMap.getWordCount();
302 while (!mBlock && ++mIndex < wordCount)
303 mBlock = mBitMap.mMap[mIndex];
304 return bitIndex;
305 }
306 return DONE;
307 }
308
309 PX_INLINE void reset()
310 {
311 mIndex = mBlock = 0;
312 PxU32 wordCount = mBitMap.getWordCount();
313 while (mIndex < wordCount && ((mBlock = mBitMap.mMap[mIndex]) == 0))
314 ++mIndex;
315 }
316 private:
317 PxU32 mBlock, mIndex;
318 const PxBitMapBase& mBitMap;
319 };
320
321 // DS: faster but less general: hasBits() must be true or getNext() is illegal so it is the calling code's responsibility to ensure that getNext() is not called illegally.
323 {
324 PX_NOCOPY(PxLoopIterator)
325
326 public:
327 PX_FORCE_INLINE PxLoopIterator(const PxBitMapBase &map) : mMap(map.getWords()), mBlock(0), mIndex(-1), mWordCount(PxI32(map.getWordCount())) {}
328
329 PX_FORCE_INLINE bool hasBits()
330 {
331 PX_ASSERT(mIndex<mWordCount);
332 while (mBlock == 0)
333 {
334 if (++mIndex == mWordCount)
335 return false;
336 mBlock = mMap[mIndex];
337 }
338 return true;
339 }
340
341 PX_FORCE_INLINE PxU32 getNext()
342 {
343 PX_ASSERT(mIndex<mWordCount && mBlock != 0);
344 PxU32 result = PxU32(mIndex) << 5 | PxLowestSetBit(mBlock); // will assert if mask is zero
345 mBlock &= (mBlock - 1);
346 return result;
347 }
348
349 private:
350 const PxU32*const mMap;
351 PxU32 mBlock; // the word we're currently scanning
352 PxI32 mIndex; // the index of the word we're currently looking at
353 PxI32 mWordCount;
354 };
355
356 //Class to iterate over the bitmap from a particular start location rather than the beginning of the list
358 {
359 public:
360 static const PxU32 DONE = 0xffffffff;
361
362 PX_INLINE PxCircularIterator(const PxBitMapBase &map, PxU32 index) : mBitMap(map)
363 {
364 mIndex = mBlock = mStartIndex = 0;
365 const PxU32 wordCount = mBitMap.getWordCount();
366 if ((index << 5) < wordCount)
367 {
368 mIndex = index << 5;
369 mStartIndex = mIndex;
370 }
371
372 if (mIndex < wordCount)
373 {
374 mBlock = mBitMap.mMap[mIndex];
375 if (mBlock == 0)
376 {
377 mIndex = (mIndex + 1) % wordCount;
378 while (mIndex != mStartIndex && (mBlock = mBitMap.mMap[mIndex]) == 0)
379 mIndex = (mIndex + 1) % wordCount;
380 }
381 }
382 }
383
384 PX_INLINE PxU32 getNext()
385 {
386 if (mBlock)
387 {
388 PxU32 bitIndex = mIndex << 5 | PxLowestSetBit(mBlock);
389 mBlock &= mBlock - 1;
390 PxU32 wordCount = mBitMap.getWordCount();
391 while (!mBlock && (mIndex = ((mIndex + 1) % wordCount)) != mStartIndex)
392 mBlock = mBitMap.mMap[mIndex];
393 return bitIndex;
394 }
395 return DONE;
396 }
397
398 private:
399 PxU32 mBlock, mIndex;
400 PxU32 mStartIndex;
401 const PxBitMapBase& mBitMap;
402
403 PX_NOCOPY(PxCircularIterator)
404 };
405
406 protected:
407 PxU32* mMap; //one bit per index
408 PxU32 mWordCount;
409 PxAllocator mAllocator;
410 PxU8 mPadding[3]; // PT: "mAllocator" is empty but consumes 1 byte
411
412 void extend(PxU32 size)
413 {
414 const PxU32 newWordCount = (size + 31) >> 5;
415 if (newWordCount > getWordCount())
416 {
417 PxU32* newMap = reinterpret_cast<PxU32*>(mAllocator.allocate(newWordCount * sizeof(PxU32), __FILE__, __LINE__));
418 if (mMap)
419 {
420 PxMemCopy(newMap, mMap, getWordCount() * sizeof(PxU32));
421 if (!isInUserMemory())
422 mAllocator.deallocate(mMap);
423 }
424 PxMemSet(newMap + getWordCount(), 0, (newWordCount - getWordCount()) * sizeof(PxU32));
425 mMap = newMap;
426 // also resets the isInUserMemory bit
427 mWordCount = newWordCount;
428 }
429 }
430
431 void extendUninitialized(PxU32 size)
432 {
433 PxU32 newWordCount = (size + 31) >> 5;
434 if (newWordCount > getWordCount())
435 {
436 if (mMap && !isInUserMemory())
437 mAllocator.deallocate(mMap);
438 // also resets the isInUserMemory bit
439 mWordCount = newWordCount;
440 mMap = reinterpret_cast<PxU32*>(mAllocator.allocate(mWordCount * sizeof(PxU32), __FILE__, __LINE__));
441 }
442 }
443
444 template<class Combiner>
445 void combine1(const PxU32* words, PxU32 length)
446 {
447 extend(length << 5);
448 PxU32 combineLength = PxMin(getWordCount(), length);
449 for (PxU32 i = 0; i<combineLength; i++)
450 mMap[i] = Combiner()(mMap[i], words[i]);
451 }
452
453 template<class Combiner>
454 void combine2(const PxU32* words1, PxU32 length1,
455 const PxU32* words2, PxU32 length2)
456 {
457 extendUninitialized(PxMax(length1, length2) << 5);
458
459 PxU32 commonSize = PxMin(length1, length2);
460
461 for (PxU32 i = 0; i<commonSize; i++)
462 mMap[i] = Combiner()(words1[i], words2[i]);
463
464 for (PxU32 i = commonSize; i<length1; i++)
465 mMap[i] = Combiner()(words1[i], 0);
466
467 for (PxU32 i = commonSize; i<length2; i++)
468 mMap[i] = Combiner()(0, words2[i]);
469 }
470
471 friend class Iterator;
472 };
473
474 typedef PxBitMapBase<PxAllocator> PxBitMap;
475 typedef PxBitMapBase<PxVirtualAllocator> PxBitMapPinned;
476#if !PX_DOXYGEN
477} // namespace physx
478#endif
479
480#endif
Definition PxAllocator.h:97
Definition PxBitMap.h:278
Definition PxBitMap.h:323
Definition PxBitMap.h:52
PxU32 findLast() const
returns 0 if no bits set (!!!)
Definition PxBitMap.h:228
Definition PxUserAllocated.h:43
#define PX_FORCE_INLINE
Definition PxPreprocessor.h:335
#define PX_INLINE
Definition PxPreprocessor.h:320
GLM_FUNC_DECL T length2(vec< L, T, Q > const &x)
Definition norm.inl:26
Sorts an array of objects in ascending order, assuming that the predicate implements the < operator:
Definition PxBoxController.h:39
PX_FORCE_INLINE void * PxMemSet(void *dest, PxI32 c, PxU32 count)
Sets the bytes of the provided buffer to the specified value.
Definition PxMemory.h:67
PX_FORCE_INLINE void * PxMemCopy(void *dest, const void *src, PxU32 count)
Copies the bytes of one memory block to another. The memory blocks must not overlap.
Definition PxMemory.h:83
PX_INLINE uint32_t PxHighestSetBit(uint32_t x)
Definition PxBitUtils.h:83
PX_INLINE uint32_t PxLowestSetBit(uint32_t x)
Definition PxBitUtils.h:73
PX_CUDA_CALLABLE PX_FORCE_INLINE T PxMax(T a, T b)
The return value is the greater of the two specified values.
Definition PxMath.h:72
PxEMPTY
Definition Px.h:87
PX_CUDA_CALLABLE PX_FORCE_INLINE T PxMin(T a, T b)
The return value is the lesser of the two specified values.
Definition PxMath.h:88
Definition PxBitMap.h:242
Definition PxBitMap.h:241
Definition PxBitMap.h:243