yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
b118451e3
master
1#include "slang-byte-encode-util.h" 2 3namespace Slang 4{ 5 6// Descriptions of algorithms here... 7// https://github.com/stoklund/varint 8 9#if SLANG_LITTLE_ENDIAN && SLANG_UNALIGNED_ACCESS 10// Testing on i7, unaligned access is around 40% faster 11#define SLANG_BYTE_ENCODE_USE_UNALIGNED_ACCESS 1 12#endif 13 14#ifndef SLANG_BYTE_ENCODE_USE_UNALIGNED_ACCESS 15#define SLANG_BYTE_ENCODE_USE_UNALIGNED_ACCESS 0 16#endif 17 18#define SLANG_REPEAT_2 (n ) n, n 19#define SLANG_REPEAT_4 (n ) SLANG_REPEAT_2(n), SLANG_REPEAT_2(n) 20#define SLANG_REPEAT_8 (n ) SLANG_REPEAT_4(n), SLANG_REPEAT_4(n) 21#define SLANG_REPEAT_16 (n ) SLANG_REPEAT_8(n), SLANG_REPEAT_8(n) 22#define SLANG_REPEAT_32 (n ) SLANG_REPEAT_16(n), SLANG_REPEAT_16(n) 23#define SLANG_REPEAT_64 (n ) SLANG_REPEAT_32(n), SLANG_REPEAT_32(n) 24#define SLANG_REPEAT_128 (n ) SLANG_REPEAT_64(n), SLANG_REPEAT_64(n) 25 26/* static */ const int8_t ByteEncodeUtil ::s_msb8 [256 ]= { 27-1 , 280 , 29SLANG_REPEAT_2 (1 ), 30SLANG_REPEAT_4 (2 ), 31SLANG_REPEAT_8 (3 ), 32SLANG_REPEAT_16 (4 ), 33SLANG_REPEAT_32 (5 ), 34SLANG_REPEAT_64 (6 ), 35SLANG_REPEAT_128 (7 ), 36}; 37 38/* static */ size_t ByteEncodeUtil ::calcEncodeLiteSizeUInt32 (const uint32_t * in ,size_t num ) 39{ 40size_t totalNumEncodeBytes = 0 ; 41 42for (size_t i = 0 ;i < num ;i ++ ) 43 { 44const uint32_t v = in [i ]; 45 46if (v < kLiteCut1 ) 47 { 48totalNumEncodeBytes += 1 ; 49 } 50else if (v <=kLiteCut1 + 255 * (kLiteCut2 - 1 - kLiteCut1 )) 51 { 52totalNumEncodeBytes += 2 ; 53 } 54else 55 { 56totalNumEncodeBytes += calcNonZeroMsByte32 (v )+ 2 ; 57 } 58 } 59return totalNumEncodeBytes ; 60} 61 62/* static */ size_t ByteEncodeUtil ::encodeLiteUInt32 ( 63const uint32_t * in , 64size_t num , 65uint8_t * encodeOut ) 66{ 67uint8_t * encodeStart = encodeOut ; 68 69for (size_t i = 0 ;i < num ;++ i ) 70 { 71uint32_t v = in [i ]; 72 73if (v < kLiteCut1 ) 74 { 75* encodeOut ++ = uint8_t (v ); 76 } 77else if (v <=kLiteCut1 + 255 * (kLiteCut2 - 1 - kLiteCut1 )) 78 { 79v -= kLiteCut1 ; 80 81encodeOut [0 ]= uint8_t (kLiteCut1 + (v >>8 )); 82encodeOut [1 ]= uint8_t (v ); 83encodeOut += 2 ; 84 } 85else 86 { 87uint8_t * encodeOutStart = encodeOut ++ ; 88while (v ) 89 { 90* encodeOut ++ = uint8_t (v ); 91v >>=8 ; 92 } 93// Finally write the size to the start 94const int numBytes = int (encodeOut - encodeOutStart ); 95encodeOutStart [0 ]= uint8_t (kLiteCut2 + (numBytes - 2 )); 96 } 97 } 98return size_t (encodeOut - encodeStart ); 99} 100 101/* static */ void ByteEncodeUtil ::encodeLiteUInt32 ( 102const uint32_t * in , 103size_t num , 104List < uint8_t >& encodeArrayOut ) 105{ 106// Make sure there is at least enough space for all bytes 107encodeArrayOut .setCount (num ); 108 109uint8_t * encodeOut = encodeArrayOut .begin (); 110uint8_t * encodeOutEnd = encodeArrayOut .end (); 111 112for (size_t i = 0 ;i < num ;++ i ) 113 { 114// Check if we need some more space 115if (encodeOut + kMaxLiteEncodeUInt32 > encodeOutEnd ) 116 { 117const size_t offset = size_t (encodeOut - encodeArrayOut .begin ()); 118 119const UInt oldCapacity = encodeArrayOut .getCapacity (); 120 121// Make some more space 122encodeArrayOut .reserve (oldCapacity + (oldCapacity >>1 )+ kMaxLiteEncodeUInt32 ); 123// Make the size the capacity 124const UInt capacity = encodeArrayOut .getCapacity (); 125encodeArrayOut .setCount (capacity ); 126 127encodeOut = encodeArrayOut .begin ()+ offset ; 128encodeOutEnd = encodeArrayOut .end (); 129 } 130 131uint32_t v = in [i ]; 132 133if (v < kLiteCut1 ) 134 { 135* encodeOut ++ = uint8_t (v ); 136 } 137else if (v <=kLiteCut1 + 255 * (kLiteCut2 - 1 - kLiteCut1 )) 138 { 139v -= kLiteCut1 ; 140 141encodeOut [0 ]= uint8_t (kLiteCut1 + (v >>8 )); 142encodeOut [1 ]= uint8_t (v ); 143encodeOut += 2 ; 144 } 145else 146 { 147uint8_t * encodeOutStart = encodeOut ++ ; 148while (v ) 149 { 150* encodeOut ++ = uint8_t (v ); 151v >>=8 ; 152 } 153// Finally write the size to the start 154const int numBytes = int (encodeOut - encodeOutStart ); 155encodeOutStart [0 ]= uint8_t (kLiteCut2 + (numBytes - 2 )); 156 } 157 } 158 159encodeArrayOut .setCount (UInt (encodeOut - encodeArrayOut .begin ())); 160encodeArrayOut .compress (); 161} 162 163/* static */ int ByteEncodeUtil ::encodeLiteUInt32 (uint32_t in ,uint8_t out [kMaxLiteEncodeUInt32 ]) 164{ 165// 0-184 1 byte value = B0 166// 185 - 248 2 bytes value = 185 + 256 * (B0 - 185) + B1 167// 249 - 255 3 - 9 bytes value = (B0 - 249 + 2) little - endian bytes following B0. 168 169if (in < kLiteCut1 ) 170 { 171out [0 ]= uint8_t (in ); 172return 1 ; 173 } 174else if (in <=kLiteCut1 + 255 * (kLiteCut2 - 1 - kLiteCut1 )) 175 { 176in -= kLiteCut1 ; 177 178out [0 ]= uint8_t (kLiteCut1 + (in >>8 )); 179out [1 ]= uint8_t (in ); 180return 2 ; 181 } 182else 183 { 184int numBytes = 1 ; 185while (in ) 186 { 187out [numBytes ++ ]= uint8_t (in ); 188in >>=8 ; 189 } 190// Finally write the size 191out [0 ]= uint8_t (kLiteCut2 + (numBytes - 2 )); 192return numBytes ; 193 } 194} 195 196static const uint32_t s_unalignedUInt32Mask [5 ]= { 1970x00000000 , 1980x000000ff , 1990x0000ffff , 2000x00ffffff , 2010xffffffff , 202}; 203 204// Decode the >= kLiteCut2. 205// in is pointing past the first byte. 206// Only valid numBytesRemaining is 2, 3, or 4 207SLANG_FORCE_INLINE static uint32_t _decodeLiteCut2UInt32 (const uint8_t * in ,int numBytesRemaining ) 208{ 209uint32_t value = 0 ; 210#if SLANG_BYTE_ENCODE_USE_UNALIGNED_ACCESS 211switch (numBytesRemaining ) 212 { 213case 2 : 214value = * (const uint16_t * )in ; 215break ; 216case 3 : 217value = (uint32_t (in [2 ]) <<16 ) | (uint32_t (in [1 ]) <<8 ) |uint32_t (in [0 ]); 218break ; 219case 4 : 220value = * (const uint32_t * )in ; 221break ; 222default : 223break ; 224 } 225#else 226// This works on all cpus although slower 227value = in [0 ]; 228switch (numBytesRemaining ) 229 { 230case 4 : 231value |=uint32_t (in [3 ]) <<24 ;/* fall thru */ 232case 3 : 233value |=uint32_t (in [2 ]) <<16 ;/* fall thru */ 234case 2 : 235value |=uint32_t (in [1 ]) <<8 ;/* fall thru */ 236case 1 : 237break ; 238 } 239#endif 240return value ; 241} 242 243/* static */ int ByteEncodeUtil ::decodeLiteUInt32 (const uint8_t * in ,uint32_t * out ) 244{ 245uint8_t b0 = * in ++ ; 246if (b0 < kLiteCut1 ) 247 { 248* out = uint32_t (b0 ); 249return 1 ; 250 } 251else if (b0 < kLiteCut2 ) 252 { 253uint8_t b1 = * in ++ ; 254* out = kLiteCut1 + b1 + (uint32_t (b0 - kLiteCut1 ) <<8 ); 255return 2 ; 256 } 257else 258 { 259const int numBytesRemaining = b0 - kLiteCut2 + 2 - 1 ; 260* out = _decodeLiteCut2UInt32 (in ,numBytesRemaining ); 261return numBytesRemaining + 1 ; 262 } 263} 264 265/* static */ size_t ByteEncodeUtil ::decodeLiteUInt32 ( 266const uint8_t * encodeIn , 267size_t numValues , 268uint32_t * valuesOut ) 269{ 270const uint8_t * encodeStart = encodeIn ; 271 272for (size_t i = 0 ;i < numValues ;++ i ) 273 { 274uint8_t b0 = * encodeIn ++ ; 275if (b0 < kLiteCut1 ) 276 { 277valuesOut [i ]= uint32_t (b0 ); 278 } 279else if (b0 < kLiteCut2 ) 280 { 281uint8_t b1 = * encodeIn ++ ; 282valuesOut [i ]= kLiteCut1 + b1 + (uint32_t (b0 - kLiteCut1 ) <<8 ); 283 } 284else 285 { 286const int numBytesRemaining = b0 - kLiteCut2 + 2 - 1 ; 287 288// For unaligned access, do not use unaligned access for the last two values, 289// (3rd last is safe because this value will have at least 2 bytes, followed by at worst 290// two 1-byte values) otherwise we can access outside the bounds of the encoded array 291// This prevents memory validation tools from causing an exception here 292if (SLANG_BYTE_ENCODE_USE_UNALIGNED_ACCESS && i < numValues - 2 ) 293 { 294const uint32_t mask = s_unalignedUInt32Mask [numBytesRemaining ]; 295// const uint32_t mask = ~(uint32_t(0xffffff00) << ((numBytesRemaining - 1) * 8)); 296valuesOut [i ]= (* (const uint32_t * )encodeIn )& mask ; 297 } 298else 299 { 300valuesOut [i ]= _decodeLiteCut2UInt32 (encodeIn ,numBytesRemaining ); 301 } 302 303encodeIn += numBytesRemaining ; 304 } 305 } 306 307return size_t (encodeIn - encodeStart ); 308} 309 310}// namespace Slang