yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
f65d756bf
master
1#ifndef SLANG_CORE_UINT_SET_H 2#define SLANG_CORE_UINT_SET_H 3 4#include "slang-common.h" 5#include "slang-hash.h" 6#include "slang-list.h" 7#include "slang-math.h" 8 9#if defined(_MSC_VER ) 10#include <intrin.h> 11#endif 12#include <memory.h> 13 14namespace Slang 15{ 16 17constexprIndex intLog2 (unsigned x ) 18{ 19return x == 1 ?0 :1 + intLog2 (x >>1 ); 20} 21 22// if `in` is 0, result is undefined behavior 23static inline Index bitscanForward (uint64_t in ) 24{ 25SLANG_ASSERT (in != 0 ); 26#if defined(_MSC_VER ) 27 28#ifdef _WIN64 29uint64_t out = 0 ; 30_BitScanForward64 ((unsigned long * )& out ,in ); 31return Index (out ); 32#else 33uint32_t out ; 34// check for 0s in 0bit->31bit. If all 0's, check for 0s in 32bit->63bit 35if (_BitScanForward ((unsigned long * )& out ,* (((uint32_t * )& in )))) 36return Index (out ); 37_BitScanForward ((unsigned long * )& out ,* (((uint32_t * )& in )+ 1 )); 38return Index (out )+ 32 ; 39#endif // #ifdef _WIN64 40 41#else 42return Index (__builtin_ctzll (in )); 43#endif // #if defined(_MSC_VER) 44} 45 46/* Hold a set of UInt values. Implementation works by storing as a bit per value */ 47/// UIntSet is essentially a Element[], where each Element is `b` bits big. 48/// Each index has `b` number of integers. If the bit is 1, we have an element there. 49/// Value of each element is equal to the binary offset from Element[0], bit 0. 50class UIntSet 51{ 52public : 53typedef UIntSet ThisType ; 54typedef uint64_t Element ;///< Type that holds the bits to say if value is present 55 56 constexprstatic Index kElementSize = 57sizeof (Element )* 8 ;///< The number of bits in an element. This also determines how many 58///< values a element can hold. 59 constexprstatic Index kElementMask = kElementSize - 1 ;///< Mask to get shift from an index 60 constexprstatic Index kElementShift = intLog2 ( 61sizeof (Element )* 8 );///< How many bits to shift to get Element index from an index. 5 for 62///< 2^5=32 elements in a uint32_t. 6 for 2^6=64 in a uint64_t. 63 64UIntSet () {} 65UIntSet (const UIntSet & other ) {m_buffer = other .m_buffer ; } 66UIntSet (UIntSet && other ) {* this = (_Move (other )); } 67UIntSet (UInt maxVal ) {resizeAndClear (maxVal ); } 68 69UIntSet & operator = (UIntSet && other ); 70UIntSet & operator = (const UIntSet & other ); 71 72HashCode getHashCode ()const ; 73 74/// Return the count of all bits directly represented 75Int getCount ()const {return Int (m_buffer .getCount ())* kElementSize ; } 76 77const List < Element >& getBuffer ()const {return m_buffer ; } 78 79/// Resize such that val can be stored and clear contents 80void resizeAndClear (UInt val ); 81/// Set all of the values up to count, as set 82void setAll (); 83/// Resize (but maintain contents) up to bit size. 84/// NOTE! That since storage is in Element blocks, it may mean some values after size are set 85/// (up to the Element boundary) 86void resize (UInt size ); 87void resizeBackingBufferDirectly (Index size ); 88 89/// Clear all of the contents (by clearing the bits) 90void clear (); 91 92/// Clear all the contents and free memory 93void clearAndDeallocate (); 94 95/// Add a value 96inline void add (UInt val ); 97inline void add (const UIntSet & val ); 98inline void addRange (const List < UInt >& other ); 99 100inline void addRawElement (Element val ,Index bitOffset ); 101 102/// Remove a value 103inline void remove (UInt val ); 104/// Returns true if the value is present 105inline bool contains (UInt val )const ; 106 107inline bool contains (const UIntSet & set )const ; 108 109/// == 110bool operator == (const UIntSet & set )const ; 111/// != 112bool operator != (const UIntSet & set )const {return !(* this == set ); } 113 114/// Store the union between this and set 115void unionWith (const UIntSet & set ); 116/// Store the intersection between this and set 117void intersectWith (const UIntSet & set ); 118/// Store the subtraction between this and set 119void subtractWith (const UIntSet & set ); 120 121/// 122bool isEmpty ()const ; 123 124/// Swap this with rhs 125void swapWith (ThisType & rhs ) {m_buffer .swapWith (rhs .m_buffer ); } 126 127template < typename T > 128List < T > getElements ()const ; 129Index countElements ()const ; 130 131/// Store the union of set1 and set2 in outRs 132static void calcUnion (UIntSet & outRs ,const UIntSet & set1 ,const UIntSet & set2 ); 133/// Store the intersection of set1 and set2 in outRs 134static void calcIntersection (UIntSet & outRs ,const UIntSet & set1 ,const UIntSet & set2 ); 135/// Store the subtraction of set2 from set1 in outRs 136static void calcSubtract (UIntSet & outRs ,const UIntSet & set1 ,const UIntSet & set2 ); 137 138/// Returns true if set1 and set2 have a same value set (ie there is an intersection) 139static bool hasIntersection (const UIntSet & set1 ,const UIntSet & set2 ); 140 141/// Get LSB Zero of UIntSet. LSB Zero is the smallest value missing from this UIntSet. 142Index getLSBZero (); 143 144struct Iterator 145 { 146friend class UIntSet ; 147 148private : 149const List < Element >* m_context ; 150Index m_block = 0 ; 151Element m_processedElement = 0 ; 152uint64_t m_LSB = 0 ; 153 154void clearLSB () 155 { 156m_LSB = bitscanForward (m_processedElement ); 157m_processedElement &=m_processedElement - 1 ; 158 } 159 160Iterator (const List < Element >* context ) {m_context = context ; } 161 162public : 163Element operator * () {return Element (m_LSB + (kElementSize * m_block )); } 164 165Iterator & operator ++ () 166 { 167while (m_processedElement == 0 ) 168 { 169m_block ++ ; 170if (m_block >=m_context -> getCount ()) 171 { 172return * this ; 173 } 174m_processedElement = (* m_context )[m_block ]; 175 } 176clearLSB (); 177return * this ; 178 } 179Iterator & operator ++ (int ) {return ++ (* this ); } 180bool operator == (const Iterator & other )const 181 { 182return other .m_block == this -> m_block && 183other .m_processedElement == this -> m_processedElement ; 184 } 185bool operator != (const Iterator & other )const {return !(other == * this ); } 186 }; 187Iterator begin ()const 188 { 189Iterator tmp (& m_buffer ); 190if (m_buffer .getCount ()== 0 ) 191return tmp ; 192 193tmp .m_processedElement = m_buffer [0 ]; 194if (tmp .m_processedElement == 0 ) 195 { 196tmp ++ ; 197return tmp ; 198 } 199 200tmp .clearLSB (); 201return tmp ; 202 } 203Iterator end ()const 204 { 205Iterator tmp (& m_buffer ); 206tmp .m_block = m_buffer .getCount (); 207tmp .m_processedElement = 0 ; 208return tmp ; 209 } 210 211bool areAllZero () {return _areAllZero (m_buffer .getBuffer (),m_buffer .getCount ()); } 212 213protected : 214static bool _areAllZero (const UIntSet ::Element * elems ,Index count ) 215 { 216for (Index i = 0 ;i < count ;++ i ) 217 { 218if (elems [i ]) 219 { 220return false; 221 } 222 } 223return true; 224 } 225 226List < Element > m_buffer ; 227}; 228 229// -------------------------------------------------------------------------- 230inline void UIntSet ::remove (UInt val ) 231{ 232const Index idx = Index (val >>kElementShift ); 233if (idx < m_buffer .getCount ()) 234 { 235m_buffer [idx ] &= ~(Element (1 ) << (val & kElementMask )); 236 } 237} 238 239// -------------------------------------------------------------------------- 240inline bool UIntSet ::contains (UInt val )const 241{ 242const Index idx = Index (val >>kElementShift ); 243return idx < m_buffer .getCount ()&& 244 ((m_buffer [idx ]& (Element (1 ) << (val & kElementMask )))!= 0 ); 245} 246 247// -------------------------------------------------------------------------- 248inline bool UIntSet ::contains (const UIntSet & set )const 249{ 250for (Index i = 0 ;i < set .m_buffer .getCount ();i ++ ) 251 { 252if (i >=m_buffer .getCount ()) 253 { 254if (set .m_buffer [i ]) 255return false; 256 } 257else 258 { 259if ((m_buffer [i ]& set .m_buffer [i ])!= set .m_buffer [i ]) 260return false; 261 } 262 } 263return true; 264} 265 266// -------------------------------------------------------------------------- 267 268inline void UIntSet ::resizeBackingBufferDirectly (Index newCount ) 269{ 270const Index oldCount = m_buffer .getCount (); 271m_buffer .setCount (newCount ); 272 273if (newCount > oldCount ) 274 { 275 ::memset (m_buffer .getBuffer ()+ oldCount ,0 , (newCount - oldCount )* sizeof (Element )); 276 } 277} 278 279inline void UIntSet ::add (UInt val ) 280{ 281const Index idx = Index (val >>kElementShift ); 282if (idx >=m_buffer .getCount ()) 283 { 284resize (val + 1 ); 285 } 286m_buffer [idx ] |=Element (1 ) << (val & kElementMask ); 287} 288 289inline void UIntSet ::add (const UIntSet & other ) 290{ 291 autootherCount = other. m_buffer . getCount (); 292if (this -> m_buffer . getCount () < otherCount) 293resizeBackingBufferDirectly (otherCount); 294 295for (auto i = 0 ; i < otherCount; i ++ ) 296m_buffer[i] |= other. m_buffer [i]; 297} 298 299inline void UIntSet:: addRange ( const List < UInt >& other) 300{ 301for (auto i : other) 302add ( i ); 303} 304 305inline void UIntSet:: addRawElement ( Element other, Index elementIndex) 306{ 307if ( this -> m_buffer. getCount () <= elementIndex) 308resizeBackingBufferDirectly (elementIndex + 1 ); 309m_buffer[elementIndex] |= other; 310} 311 312template < typename T > 313List < T > UIntSet:: getElements () const 314{ 315auto count = m_buffer. getCount (); 316if (count == 0 ) 317return {}; 318 319// Specific path for uint64_t. If using SIMD we should not use this path due to larger data 320// types. 321 322List < T > elements; 323elements. reserve (count); 324for (Index block = 0 ; block < count; block ++ ) 325{ 326Element n = m_buffer[block]; 327while (n != 0 ) 328{ 329elements. add ( T ( bitscanForward (( uint64_t )n) + (kElementSize * block))); 330n &= n - 1 ; 331} 332} 333return elements; 334} 335 336} // namespace Slang 337#endif