yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
4d517794e
master
1// slang-json-value.h 2#ifndef SLANG_JSON_VALUE_H 3#define SLANG_JSON_VALUE_H 4 5#include "../core/slang-basic.h" 6#include "../core/slang-rtti-info.h" 7#include "slang-diagnostic-sink.h" 8#include "slang-json-parser.h" 9#include "slang-source-loc.h" 10 11#include <optional> 12 13namespace Slang 14{ 15 16typedef uint32_t JSONKey ; 17 18struct JSONValue 19{ 20enum class Kind 21 { 22Invalid , 23 24Null , 25 26Bool , 27String , 28Integer , 29Float , 30 31Array , 32Object , 33 34CountOf , 35 }; 36 37enum class Type 38 { 39Invalid , 40 41True , 42False , 43Null , 44 45StringLexeme , 46IntegerLexeme , 47FloatLexeme , 48 49IntegerValue , 50FloatValue , 51StringValue , 52 53StringRepresentation , 54 55Array , 56Object , 57 58CountOf , 59 }; 60 61static bool isLexeme (Type type ) 62 { 63return Index (type ) >=Index (Type ::StringLexeme )&& Index (type ) <=Index (Type ::FloatLexeme ); 64 } 65 66static JSONValue makeInt (int64_t inValue ,SourceLoc loc = SourceLoc ()) 67 { 68JSONValue value ; 69value .type = Type ::IntegerValue ; 70value .loc = loc ; 71value .intValue = inValue ; 72return value ; 73 } 74static JSONValue makeFloat (double inValue ,SourceLoc loc = SourceLoc ()) 75 { 76JSONValue value ; 77value .type = Type ::FloatValue ; 78value .loc = loc ; 79value .floatValue = inValue ; 80return value ; 81 } 82static JSONValue makeNull (SourceLoc loc = SourceLoc ()) 83 { 84JSONValue value ; 85value .type = Type ::Null ; 86value .loc = loc ; 87return value ; 88 } 89static JSONValue makeBool (bool inValue ,SourceLoc loc = SourceLoc ()) 90 { 91JSONValue value ; 92value .type = (inValue ?Type ::True :Type ::False ); 93value .loc = loc ; 94return value ; 95 } 96 97static JSONValue makeLexeme (Type type ,SourceLoc loc ,Index length ) 98 { 99SLANG_ASSERT (isLexeme (type )); 100JSONValue value ; 101value .type = type ; 102value .loc = loc ; 103value .length = length ; 104return value ; 105 } 106 107static JSONValue makeEmptyArray (SourceLoc loc = SourceLoc ()) 108 { 109JSONValue value ; 110value .type = Type ::Array ; 111value .loc = loc ; 112value .rangeIndex = 0 ; 113return value ; 114 } 115static JSONValue makeEmptyObject (SourceLoc loc = SourceLoc ()) 116 { 117JSONValue value ; 118value .type = Type ::Object ; 119value .loc = loc ; 120value .rangeIndex = 0 ; 121return value ; 122 } 123 124static JSONValue makeInvalid (SourceLoc loc = SourceLoc ()) 125 { 126JSONValue value ; 127value .type = Type ::Invalid ; 128value .loc = loc ; 129return value ; 130 } 131// The following functions only work if the value is stored directly NOT as a lexeme. Use the 132// methods on the container to access values if it is potentially stored as a lexeme 133 134/// As a boolean value 135bool asBool ()const ; 136/// As an integer value 137int64_t asInteger ()const ; 138/// As a float value 139double asFloat ()const ; 140 141/// True if this is a object like 142bool isObjectLike ()const {return Index (type ) >=Index (Type ::Array ); } 143 144/// True if this appears to be a valid value 145bool isValid ()const {return type != JSONValue ::Type ::Invalid ; } 146 147/// True if needs destroy 148bool needsDestroy ()const {return isObjectLike ()&& rangeIndex != 0 ; } 149 150/// Get the kind 151SLANG_FORCE_INLINE Kind getKind ()const {return getKindForType (type ); } 152 153void reset () 154 { 155type = Type ::Invalid ; 156loc = SourceLoc (); 157 } 158 159/// Given a type return the associated kind 160static Kind getKindForType (Type type ) {return g_typeToKind [Index (type )]; } 161 162Type type = Type ::Invalid ;///< The type of value 163SourceLoc loc ;///< The (optional) location in source of this value. 164 165union 166 { 167Index rangeIndex ;///< Used for Array/Object 168Index length ;///< Length in bytes if it is a 'Lexeme' 169double floatValue ;///< Float value 170int64_t intValue ;///< Integer value 171JSONKey stringKey ;///< The pool key if it's a string 172StringRepresentation * stringRep ;///< Only ever used on a 'PersistentJSONValue' 173 }; 174 175static const Kind g_typeToKind [Index (Type ::CountOf )]; 176 177static const OtherRttiInfo g_rttiInfo ; 178}; 179 180template <> 181struct GetRttiInfo < JSONValue > 182{ 183static const RttiInfo * get () {return & JSONValue ::g_rttiInfo ; } 184}; 185 186struct JSONKeyValue 187{ 188/// True if it's valid 189bool isValid ()const {return value .type != JSONValue ::Type ::Invalid ; } 190 191void reset () 192 { 193key = JSONKey (0 ); 194keyLoc = SourceLoc (); 195value .reset (); 196 } 197 198JSONKey key ; 199SourceLoc keyLoc ; 200JSONValue value ; 201 202static JSONKeyValue make (JSONKey inKey ,JSONValue inValue ,SourceLoc inKeyLoc = SourceLoc ()) 203 { 204return JSONKeyValue {inKey ,inKeyLoc ,inValue }; 205 } 206 207static JSONKeyValue g_invalid ; 208}; 209 210class JSONContainer ; 211 212/* Is similar to JSONValue, but is designed to 213 214* Only be able to hold 'Simple' types (ie not array/object) 215* Does not reference/require JSONContainer. 216 217Not requiring JSONContainer means it's useful to hold state when JSONContainer goes out of scope. 218Care may need to be taken if sourceManager goes out of scope, sourceLocs may become invalid. This 219is true of a regular JSONValue. 220 221Care must also be taken because it is derived from JSONValue. It *can* be sliced and work correctly, 222but *requires* that the PersistentJSONValue with same value to stay in scope in general. In practice 223this is only an issue with StringRepresention type. 224*/ 225class PersistentJSONValue :public JSONValue 226{ 227public : 228typedef JSONValue Super ; 229typedef PersistentJSONValue ThisType ; 230 231/// If it's a string type this will always work 232String getString ()const ; 233UnownedStringSlice getSlice ()const ; 234 235/// Set to the value 236void set (const JSONValue & in ,JSONContainer * container ); 237/// Set directly to a string 238void set (const UnownedStringSlice & slice ,SourceLoc loc ); 239 240/// True if identical 241bool operator == (const ThisType & rhs )const ; 242bool operator != (const ThisType & rhs )const {return !(* this == rhs ); } 243 244/// Assignable 245void operator = (const ThisType & rhs ); 246 247PersistentJSONValue (const JSONValue & in ,JSONContainer * container ) {_init (in ,container ); } 248PersistentJSONValue (const JSONValue & in ,JSONContainer * container ,SourceLoc inLoc ) 249 { 250_init (in ,container ); 251loc = inLoc ; 252 } 253 254/// Copy Ctor 255PersistentJSONValue (const ThisType & rhs ); 256/// Default Ctor (will be set to invalid) 257PersistentJSONValue () {} 258 259 260 ~PersistentJSONValue () 261 { 262if (type == Type ::StringRepresentation && stringRep ) 263 { 264stringRep -> releaseReference (); 265 } 266 } 267 268protected : 269/// Assumes this has no valid data 270void _init (const JSONValue & in ,JSONContainer * container ); 271void _init (const UnownedStringSlice & slice ,SourceLoc loc ); 272}; 273 274class JSONContainer :public RefObject 275{ 276public : 277/// Make a new array 278JSONValue createArray (const JSONValue * values ,Index valuesCount ,SourceLoc loc = SourceLoc ()); 279/// Make a new object 280JSONValue createObject ( 281const JSONKeyValue * keyValues , 282Index keyValueCount , 283SourceLoc loc = SourceLoc ()); 284/// Make a string 285JSONValue createString (const UnownedStringSlice & slice ,SourceLoc loc = SourceLoc ()); 286 287ConstArrayView < JSONValue > getArray (const JSONValue & in )const ; 288ConstArrayView < JSONKeyValue > getObject (const JSONValue & in )const ; 289 290ArrayView < JSONValue > getArray (const JSONValue & in ); 291ArrayView < JSONKeyValue > getObject (const JSONValue & in ); 292 293/// Add value to array. 294void addToArray (JSONValue & array ,const JSONValue & value ); 295 296/// Get the value at the index in the array 297JSONValue & getAt (const JSONValue & array ,Index index ); 298 299/// Returns the index of key in obj, or -1 if not found 300Index findObjectIndex (const JSONValue & obj ,JSONKey key )const ; 301/// Get the value in the object at key. Returns invalid if not found. 302JSONValue findObjectValue (const JSONValue & obj ,JSONKey key )const ; 303 304/// Returns the index 305Index findKeyGlobalIndex (const JSONValue & obj ,JSONKey key ); 306Index findKeyGlobalIndex (const JSONValue & obj ,const UnownedStringSlice & slice ); 307 308/// Set a key value for the obj 309void setKeyValue ( 310JSONValue & obj , 311JSONKey key , 312const JSONValue & value , 313SourceLoc loc = SourceLoc ()); 314 315/// Returns true if found 316bool removeKey (JSONValue & obj ,JSONKey key ); 317bool removeKey (JSONValue & obj ,const UnownedStringSlice & slice ); 318 319/// As a boolean value 320bool asBool (const JSONValue & value ); 321/// As an integer value 322int64_t asInteger (const JSONValue & value ); 323/// As a float value 324double asFloat (const JSONValue & value ); 325 326/// Returns string as a key 327JSONKey getStringKey (const JSONValue & in ); 328 329/// Get as a string. The slice may used backing lexeme (ie will only last 330/// as long as the backing JSON text, or be decoded and be transitory). 331UnownedStringSlice getTransientString (const JSONValue & in ); 332 333/// Get as a string. The contents will stay in scope as long as the container 334UnownedStringSlice getString (const JSONValue & in ); 335 336/// Gets the lexeme 337UnownedStringSlice getLexeme (const JSONValue & in ); 338 339/// Get a key for a name 340JSONKey getKey (const UnownedStringSlice & slice ); 341/// Returns JSONKey(0) if not found 342JSONKey findKey (const UnownedStringSlice & slice )const ; 343/// Get the string from the key 344UnownedStringSlice getStringFromKey (JSONKey key )const 345 { 346return m_slicePool .getSlice (StringSlicePool ::Handle (key )); 347 } 348 349/// True if they are the same value 350/// If object like type comparison is performed recursively. 351/// NOTE! That Float and Integer values do not compare & source locations are ignored. 352bool areEqual (const JSONValue & a ,const JSONValue & b ); 353bool areEqual (const JSONValue * a ,const JSONValue * b ,Index count ); 354bool areEqual (const JSONKeyValue * a ,const JSONKeyValue * b ,Index count ); 355 356bool areEqual (const JSONValue & a ,const UnownedStringSlice & slice ); 357 358/// Destroy value 359void destroy (JSONValue & value ); 360/// Destroy recursively from value 361void destroyRecursively (JSONValue & value ); 362 363/// Traverse a JSON hierarchy from value, outputting to the listener 364void traverseRecursively (const JSONValue & value ,JSONListener * listener ); 365 366/// Returns the source manager used. 367SourceManager * getSourceManager ()const {return m_sourceManager ; } 368/// Set the source manager 369void setSourceManager (SourceManager * sourceManger ) {m_sourceManager = sourceManger ; } 370 371/// Clears all the source locs. Useful if the sourceManager is no longer available, or has 372/// itself been reset. All JSONValues which were Lexeme based will become held in the container 373/// The source manager will set to nullptr 374void clearSourceManagerDependency (JSONValue * ioValues ,Index count ); 375 376/// Reset the state 377void reset (); 378 379/// Return inValue as a regular value (ie not held as a lexeme) 380JSONValue asValue (const JSONValue & inValue ); 381 382// Ctor 383JSONContainer (SourceManager * sourceManger ); 384 385/// Returns true if all the keys are unique 386static bool areKeysUnique (const JSONKeyValue * keyValues ,Index keyValueCount ); 387 388/// Access the internal set of strings, removing anything from this 389/// will invalidate the container, so only do it immediately prior to 390/// destruction. 391StringSlicePool & getStringSlicePool () {return m_slicePool ; }; 392 393protected : 394struct Range 395 { 396// We want to record the underlying range, because we don't track JSONValue, and so we need 397// to know what the range applies to if we want to reorder, flatten etc. 398enum class Type 399 { 400None , 401Destroyed , 402Object , 403Array , 404 }; 405 406/// Is active if it consuming some part of a value list (even if zero count) 407SLANG_FORCE_INLINE bool isActive ()const {return Index (type ) >=Index (Type ::Object ); } 408 409Type type ; 410Index startIndex ; 411Index count ; 412Index capacity ; 413 }; 414 415template < typename T > 416static void _add (Range & range ,List < T >& list ,const T & value ); 417 418Index _addRange (Range ::Type type ,Index startIndex ,Index count ); 419void _removeKey (JSONValue & obj ,Index globalIndex ); 420/// Note does not destroy values in range. 421void _destroyRange (Index rangeIndex ); 422 423static bool _sameKeyOrder (const JSONKeyValue * a ,const JSONKeyValue * b ,Index count ); 424/// True if the values are equal 425bool _areEqualValues (const JSONKeyValue * a ,const JSONKeyValue * b ,Index count ); 426/// True if the key and value are equal 427bool _areEqualOrderedKeys (const JSONKeyValue * a ,const JSONKeyValue * b ,Index count ); 428 429void _clearSourceManagerDependency (JSONValue * ioValues ,Index count ); 430JSONValue _removeManagerDependency (const JSONValue & inValue ); 431 432StringBuilder m_buf ;///< A temporary buffer used to hold unescaped strings 433 434SourceView * m_currentView = nullptr ; 435SourceManager * m_sourceManager ; 436 437StringSlicePool m_slicePool ; 438List < Range > m_ranges ; 439List < Index > m_freeRangeIndices ; 440List < JSONValue > m_arrayValues ; 441List < JSONKeyValue > m_objectValues ; 442}; 443 444template < typename T > 445class JSONOptional 446{ 447public : 448bool hasValue = false; 449T value ; 450JSONOptional ()= default ; 451JSONOptional (std ::nullopt_t ) {} 452JSONOptional (const T & inValue ) 453 :hasValue (true),value (inValue ) 454 { 455 } 456}; 457 458template < typename T > 459struct GetRttiInfo < JSONOptional < T >> 460{ 461static const OptionalRttiInfo _make () 462 { 463OptionalRttiInfo info ; 464info .init < JSONOptional < T >>(RttiInfo ::Kind ::Optional ); 465info .m_elementType = GetRttiInfo < T > ::get (); 466info .m_valueOffset = (uint32_t )offsetof(JSONOptional < T > ,value ); 467return info ; 468 } 469static const RttiInfo * get () 470 { 471static const OptionalRttiInfo g_info = _make (); 472return & g_info ; 473 } 474}; 475 476 477class JSONBuilder :public JSONListener 478{ 479public : 480typedef uint32_t Flags ; 481struct Flag 482 { 483enum Enum :Flags 484 { 485ConvertLexemes = 0x01 , 486 }; 487 }; 488 489 490virtual void startObject (SourceLoc loc )SLANG_OVERRIDE ; 491virtual void endObject (SourceLoc loc )SLANG_OVERRIDE ; 492virtual void startArray (SourceLoc loc )SLANG_OVERRIDE ; 493virtual void endArray (SourceLoc loc )SLANG_OVERRIDE ; 494virtual void addQuotedKey (const UnownedStringSlice & key ,SourceLoc loc )SLANG_OVERRIDE ; 495virtual void addUnquotedKey (const UnownedStringSlice & key ,SourceLoc loc )SLANG_OVERRIDE ; 496virtual void addLexemeValue (JSONTokenType type ,const UnownedStringSlice & value ,SourceLoc loc ) 497SLANG_OVERRIDE ; 498virtual void addIntegerValue (int64_t value ,SourceLoc loc )SLANG_OVERRIDE ; 499virtual void addFloatValue (double value ,SourceLoc loc )SLANG_OVERRIDE ; 500virtual void addBoolValue (bool value ,SourceLoc loc )SLANG_OVERRIDE ; 501virtual void addStringValue (const UnownedStringSlice & string ,SourceLoc loc )SLANG_OVERRIDE ; 502virtual void addNullValue (SourceLoc loc )SLANG_OVERRIDE ; 503 504/// Reset the state 505void reset (); 506 507/// Get the root value. Will be set after valid construction 508const JSONValue & getRootValue ()const {return m_rootValue ; } 509 510JSONBuilder (JSONContainer * container ,Flags flags = 0 ); 511 512protected : 513struct State 514 { 515enum class Kind :uint8_t 516 { 517Root , 518Object , 519Array , 520 }; 521void setKey (JSONKey key ,SourceLoc loc ) 522 { 523m_key = key ; 524m_keyLoc = loc ; 525 } 526void resetKey () 527 { 528m_key = JSONKey (0 ); 529m_keyLoc = SourceLoc (); 530 } 531bool hasKey ()const {return m_key != JSONKey (0 ); } 532 533Kind m_kind ; 534Index m_startIndex ; 535SourceLoc m_loc ; 536JSONKey m_key ; 537SourceLoc m_keyLoc ; 538 }; 539 540void _popState (); 541void _add (const JSONValue & value ); 542 543Index _findKeyIndex (JSONKey key )const ; 544 545Flags m_flags ; 546 547List < JSONKeyValue > m_keyValues ; 548List < JSONValue > m_values ; 549List < State > m_stateStack ; 550 551State m_state ; 552 553JSONContainer * m_container ; 554JSONValue m_rootValue ; 555 556StringBuilder m_work ; 557}; 558 559}// namespace Slang 560 561#endif