yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
7f04adbfb
master
1#ifndef SLANG_CORE_BLOB_H 2#define SLANG_CORE_BLOB_H 3 4#include "../core/slang-com-object.h" 5#include "slang-com-helper.h" 6#include "slang-com-ptr.h" 7#include "slang-list.h" 8#include "slang-string.h" 9#include "slang.h" 10 11#include <stdarg.h> 12 13namespace Slang 14{ 15 16/** Base class for simple blobs. 17*/ 18class BlobBase :public ComBaseObject ,public ISlangBlob ,public ICastable 19{ 20public : 21// ISlangUnknown 22SLANG_COM_BASE_IUNKNOWN_ALL 23 24// ICastable 25virtual SLANG_NO_THROW void * SLANG_MCALL castAs (const SlangUUID & guid )SLANG_OVERRIDE ; 26 27protected : 28ISlangUnknown * getInterface (const Guid & guid ); 29void * getObject (const Guid & guid ); 30}; 31 32/** A blob that uses a `StringRepresentation` for its storage. 33 34By design the StringBlob owns a unique reference to the StringRepresentation. 35This is because StringBlob, implements an interface which should work across threads. 36*/ 37class StringBlob :public BlobBase 38{ 39public : 40SLANG_CLASS_GUID (0xf7e0e93c ,0xde70 ,0x4531 , {0x9c ,0x9f ,0xdd ,0xa3 ,0xf6 ,0xc6 ,0xc0 ,0xdd }); 41 42// ICastable 43virtual SLANG_NO_THROW void * SLANG_MCALL castAs (const SlangUUID & guid )SLANG_OVERRIDE ; 44 45// ISlangBlob 46SLANG_NO_THROW void const * SLANG_MCALL getBufferPointer ()SLANG_OVERRIDE 47 { 48return m_slice .begin (); 49 } 50SLANG_NO_THROW size_t SLANG_MCALL getBufferSize ()SLANG_OVERRIDE {return m_slice .getLength (); } 51 52/// Since in is not being moved will *always* create a new representation, unless the in is 53/// empty 54static ComPtr < ISlangBlob > create (const String & in ); 55/// Create from a slice 56static ComPtr < ISlangBlob > create (const UnownedStringSlice & slice ); 57 58/// Moves from in into the created blob. 59/// NOTE! That will only use the representation from in, if it is *unique* 60/// otherwise it will make a new copy. 61static ComPtr < ISlangBlob > moveCreate (String & in ); 62static ComPtr < ISlangBlob > moveCreate (String && in ); 63 64/// Dtor 65 ~StringBlob (); 66 67protected : 68/// Init with a rep when can't be owned. 69void _setWithCopy (StringRepresentation * rep ); 70/// Init with a representation that has been moved. 71void _setWithMove (StringRepresentation * rep ); 72 73/// Create a unique copy of rep. 74/// If nullptr will work (if rep is empty, will return that) 75static StringRepresentation * _createUniqueCopy (StringRepresentation * rep ); 76 77/// Rep can only be nullptr or have a single ref 78void _setUniqueRep (StringRepresentation * rep ); 79 80void * getObject (const Guid & guid ); 81 82UnownedTerminatedStringSlice m_slice ;///< The contents 83StringRepresentation * m_uniqueRep = 84nullptr ;///< Holds actual bytes. Can be nullptr if it's an empty string. 85}; 86 87class ListBlob :public BlobBase 88{ 89public : 90typedef BlobBase Super ; 91typedef ListBlob ThisType ; 92 93// ICastable 94virtual SLANG_NO_THROW void * SLANG_MCALL castAs (const SlangUUID & guid )SLANG_OVERRIDE ; 95// ISlangBlob 96SLANG_NO_THROW void const * SLANG_MCALL getBufferPointer ()SLANG_OVERRIDE 97 { 98return m_data .getBuffer (); 99 } 100SLANG_NO_THROW size_t SLANG_MCALL getBufferSize ()SLANG_OVERRIDE {return m_data .getCount (); } 101 102static ComPtr < ISlangBlob > create (const List < uint8_t >& data ) 103 { 104return ComPtr < ISlangBlob > (new ListBlob (data )); 105 } 106 107static ComPtr < ISlangBlob > moveCreate (List < uint8_t >& data ) 108 { 109return ComPtr < ISlangBlob > (new ListBlob (_Move (data ))); 110 } 111 112protected : 113explicit ListBlob (const List < uint8_t >& data ) 114 :m_data (data ) 115 { 116 } 117// Move ctor 118explicit ListBlob (List < uint8_t >&& data ) 119 :m_data (data ) 120 { 121 } 122 123void * getObject (const Guid & guid ); 124 125void operator = (const ThisType & rhs )= delete ; 126 127List < uint8_t > m_data ; 128}; 129 130class ScopedAllocation 131{ 132public : 133typedef ScopedAllocation ThisType ; 134// Returns the allocation if successful. 135void * allocate (size_t size ) 136 { 137deallocate (); 138if (size > 0 ) 139 { 140m_data = ::malloc (size ); 141 } 142m_sizeInBytes = size ; 143m_capacityInBytes = size ; 144return m_data ; 145 } 146/// Allocate size including a 0 byte at `size`. 147void * allocateTerminated (size_t size ) 148 { 149SLANG_ASSUME (size != std ::numeric_limits < size_t > ::max ()); 150uint8_t * data = (uint8_t * )allocate (size + 1 ); 151data [size ]= 0 ; 152m_sizeInBytes = size ; 153return data ; 154 } 155/// Deallocates if holds an allocation 156void deallocate () 157 { 158if (m_data ) 159 { 160 ::free (m_data ); 161m_data = nullptr ; 162 } 163m_sizeInBytes = 0 ; 164m_capacityInBytes = 0 ; 165 } 166// Reallocate so the buffer is the specified capacity/size. Contents of buffer up to size remain 167// intact. 168void reallocate (size_t capacity ) 169 { 170if (capacity != m_capacityInBytes ) 171 { 172m_data = ::realloc (m_data ,capacity ); 173m_sizeInBytes = capacity ; 174m_capacityInBytes = capacity ; 175 } 176 } 177/// Makes this no longer own the allocation. Returns the allocated data (or nullptr if no 178/// allocation) 179void * detach () 180 { 181void * data = m_data ; 182m_data = nullptr ; 183m_sizeInBytes = 0 ; 184m_capacityInBytes = 0 ; 185return data ; 186 } 187/// Attach some data. 188/// NOTE! data must be a pointer that was returned from malloc, otherwise will incorrectly free. 189void attach (void * data ,size_t size ) 190 { 191deallocate (); 192m_data = data ; 193m_sizeInBytes = size ; 194m_capacityInBytes = size ; 195 } 196 197void * set (const void * data ,size_t size ) 198 { 199void * dst = allocate (size ); 200if (dst ) 201 { 202memcpy (dst ,data ,size ); 203 } 204return dst ; 205 } 206 207/// Get the allocated data. Returns nullptr if there is no allocated data 208void * getData ()const {return m_data ; } 209/// Get the size of the allocated data. 210size_t getSizeInBytes ()const {return m_sizeInBytes ; } 211/// Get the capacity in bytes 212size_t getCapacityInBytes ()const {return m_capacityInBytes ; } 213 214void setSizeInBytes (size_t size ) 215 { 216SLANG_ASSERT (size <=m_capacityInBytes ); 217m_sizeInBytes = size ; 218 } 219 220void swap (ThisType & rhs ) 221 { 222Swap (m_data ,rhs .m_data ); 223Swap (m_sizeInBytes ,rhs .m_sizeInBytes ); 224Swap (m_capacityInBytes ,rhs .m_capacityInBytes ); 225 } 226 227/// True if has zero termination, at the byte at m_sizeInBytes 228bool isTerminated ()const 229 { 230return m_capacityInBytes > m_sizeInBytes && ((const char * )m_data )[m_sizeInBytes ]== 0 ; 231 } 232 233ScopedAllocation () 234 :m_data (nullptr ),m_sizeInBytes (0 ),m_capacityInBytes (0 ) 235 { 236 } 237 238 ~ScopedAllocation () {deallocate (); } 239 240private : 241// disable 242ScopedAllocation (const ThisType & rhs )= delete ; 243void operator = (const ThisType & rhs )= delete ; 244 245void * m_data ; 246size_t m_sizeInBytes ; 247size_t m_capacityInBytes ; 248}; 249 250/** A blob that manages some raw data that it owns. 251*/ 252class RawBlob :public BlobBase 253{ 254public : 255// ICastable 256virtual SLANG_NO_THROW void * SLANG_MCALL castAs (const SlangUUID & guid )SLANG_OVERRIDE ; 257// ISlangBlob 258SLANG_NO_THROW void const * SLANG_MCALL getBufferPointer ()SLANG_OVERRIDE 259 { 260return m_data .getData (); 261 } 262SLANG_NO_THROW size_t SLANG_MCALL getBufferSize ()SLANG_OVERRIDE 263 { 264return m_data .getSizeInBytes (); 265 } 266 267static ComPtr < ISlangBlob > moveCreate (ScopedAllocation & alloc ) 268 { 269RawBlob * blob = new RawBlob ; 270blob -> m_data .swap (alloc ); 271return ComPtr < ISlangBlob > (blob ); 272 } 273 274/// Create a blob that will retain (a copy of) raw data. 275static inline ComPtr < ISlangBlob > create (void const * inData ,size_t size ) 276 { 277return ComPtr < ISlangBlob > (new RawBlob (inData ,size )); 278 } 279 280protected : 281// Ctor 282// NOTE! Takes a copy of the input data 283RawBlob (const void * data ,size_t size ) {memcpy (m_data .allocateTerminated (size ),data ,size ); } 284 285void * getObject (const Guid & guid ); 286 287RawBlob ()= default ; 288 289ScopedAllocation m_data ; 290}; 291 292// A blob that does not own it's contained data. 293class UnownedRawBlob :public BlobBase 294{ 295public : 296// ISlangBlob 297SLANG_NO_THROW void const * SLANG_MCALL getBufferPointer ()SLANG_OVERRIDE {return m_data ; } 298SLANG_NO_THROW size_t SLANG_MCALL getBufferSize ()SLANG_OVERRIDE {return m_dataSizeInBytes ; } 299 300static inline ComPtr < ISlangBlob > create (void const * inData ,size_t size ) 301 { 302return ComPtr < ISlangBlob > (new UnownedRawBlob (inData ,size )); 303 } 304 305protected : 306// Ctor 307UnownedRawBlob (const void * data ,size_t size ) 308 :m_data (data ),m_dataSizeInBytes (size ) 309 { 310 } 311 312UnownedRawBlob ()= default ; 313 314const void * m_data ; 315size_t m_dataSizeInBytes ; 316}; 317 318/** A Blob that has no ref counting and exists typically for entire execution. 319The memory it references is *not* owned by the blob. 320This is useful when a Blob is useful to represent some global immutable chunk of memory. 321*/ 322class StaticBlob :public ISlangBlob ,public ICastable 323{ 324public : 325// ISlangUnknown 326SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface (SlangUUID const & uuid ,void ** outObject ) 327SLANG_OVERRIDE ; 328SLANG_NO_THROW uint32_t SLANG_MCALL addRef ()SLANG_OVERRIDE {return 1 ; } 329SLANG_NO_THROW uint32_t SLANG_MCALL release ()SLANG_OVERRIDE {return 1 ; } 330 331// ICastable 332virtual SLANG_NO_THROW void * SLANG_MCALL castAs (const SlangUUID & guid )SLANG_OVERRIDE ; 333 334// ISlangBlob 335SLANG_NO_THROW void const * SLANG_MCALL getBufferPointer ()SLANG_OVERRIDE {return m_data ; } 336SLANG_NO_THROW size_t SLANG_MCALL getBufferSize ()SLANG_OVERRIDE {return m_dataCount ; } 337 338StaticBlob (const void * data ,size_t dataCount ) 339 :m_data (data ),m_dataCount (dataCount ) 340 { 341 } 342 343protected : 344ISlangUnknown * getInterface (const Guid & guid ); 345void * getObject (const Guid & guid ); 346 347const void * m_data ; 348size_t m_dataCount ; 349}; 350 351class ScopeBlob :public BlobBase 352{ 353public : 354// ICastable 355virtual SLANG_NO_THROW void * SLANG_MCALL castAs (const SlangUUID & guid )SLANG_OVERRIDE ; 356 357// ISlangBlob 358SLANG_NO_THROW void const * SLANG_MCALL getBufferPointer ()SLANG_OVERRIDE 359 { 360return m_blob -> getBufferPointer (); 361 } 362SLANG_NO_THROW size_t SLANG_MCALL getBufferSize ()SLANG_OVERRIDE 363 { 364return m_blob -> getBufferSize (); 365 } 366 367static inline ComPtr < ISlangBlob > create (ISlangBlob * blob ,ISlangUnknown * scope ) 368 { 369return ComPtr < ISlangBlob > (new ScopeBlob (blob ,scope )); 370 } 371 372protected : 373// Ctor 374ScopeBlob (ISlangBlob * blob ,ISlangUnknown * scope ) 375 :m_blob (blob ),m_scope (scope ) 376 { 377// Cache the ICastable interface if there is one. 378blob -> queryInterface (SLANG_IID_PPV_ARGS (m_castable .writeRef ())); 379 } 380 381ComPtr < ISlangUnknown > m_scope ; 382ComPtr < ISlangBlob > m_blob ; 383ComPtr < ICastable > 384m_castable ;///< Set if the blob has this interface. Set to nullptr if does not. 385}; 386 387}// namespace Slang 388 389#endif // SLANG_CORE_BLOB_H