yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
bcd53322f
master
1#ifndef SLANG_CORE_STRING_H 2#define SLANG_CORE_STRING_H 3 4#include "slang-common.h" 5#include "slang-hash.h" 6#include "slang-secure-crt.h" 7#include "slang-smart-pointer.h" 8#include "slang-stable-hash.h" 9 10#include <cstdlib> 11#include <iostream> 12#include <new> 13#include <stdio.h> 14#include <string.h> 15#include <type_traits> 16 17namespace Slang 18{ 19class _EndLine 20{ 21}; 22extern _EndLine EndLine ; 23 24// in-place reversion, works only for ascii string 25inline void reverseInplaceAscii (char * buffer ,int length ) 26{ 27int i ,j ; 28char c ; 29for (i = 0 ,j = length - 1 ;i < j ;i ++ ,j -- ) 30 { 31c = buffer [i ]; 32buffer [i ]= buffer [j ]; 33buffer [j ]= c ; 34 } 35} 36template < typename IntType > 37inline int intToAscii (char * buffer ,IntType val ,int radix ,int padTo = 0 ) 38{ 39static_assert (std ::is_integral_v < IntType > ); 40 41int i = 0 ; 42IntType sign ; 43 44sign = val ; 45if (sign < 0 ) 46 { 47val = (IntType )(0 - val ); 48 } 49 50do 51 { 52int digit = (val %radix ); 53if (digit <=9 ) 54buffer [i ++ ]= (char )(digit + '0' ); 55else 56buffer [i ++ ]= (char )(digit - 10 + 'A' ); 57 }while ((val /=radix )> 0 ); 58 59SLANG_ASSERT (i >=0 ); 60while (i < padTo ) 61buffer [i ++ ]= '0' ; 62 63if (sign < 0 ) 64buffer [i ++ ]= '-' ; 65 66// Put in normal character order 67reverseInplaceAscii (buffer ,i ); 68 69buffer [i ]= '\0' ; 70return i ; 71} 72 73SLANG_FORCE_INLINE bool isUtf8LeadingByte (char ch ) 74{ 75return (((unsigned char )ch )& 0xC0 )== 0xC0 ; 76} 77 78SLANG_FORCE_INLINE bool isUtf8ContinuationByte (char ch ) 79{ 80return (((unsigned char )ch )& 0xC0 )== 0x80 ; 81} 82 83/* A string slice that doesn't own the contained characters. 84It is the responsibility of code using the type to keep the memory backing 85the slice in scope. 86A slice is generally *not* zero terminated. */ 87struct SLANG_RT_API UnownedStringSlice 88{ 89public : 90typedef UnownedStringSlice ThisType ; 91 92// Type to indicate that a ctor is with a length to disabmiguate 0/nullptr 93// causing ambiguity. 94struct WithLength 95 { 96 }; 97 98UnownedStringSlice () 99 :m_begin (nullptr ),m_end (nullptr ) 100 { 101 } 102 103explicit UnownedStringSlice (char const * a ) 104 :m_begin (a ),m_end (a ?a + strlen (a ) : nullptr) 105 { 106 } 107UnownedStringSlice (char const * b ,char const * e ) 108 :m_begin (b ),m_end (e ) 109 { 110 } 111UnownedStringSlice (char const * b ,size_t len ) 112 :m_begin (b ),m_end (b + len ) 113 { 114 } 115UnownedStringSlice (WithLength ,char const * b ,size_t len ) 116 :m_begin (b ),m_end (b + len ) 117 { 118 } 119 120SLANG_FORCE_INLINE char const * begin ()const {return m_begin ; } 121 122SLANG_FORCE_INLINE char const * end ()const {return m_end ; } 123 124/// True if slice is strictly contained in memory. 125bool isMemoryContained (const UnownedStringSlice & slice )const 126 { 127return slice .m_begin >=m_begin && slice .m_end <=m_end ; 128 } 129bool isMemoryContained (const char * pos )const {return pos >=m_begin && pos <=m_end ; } 130 131/// Get the length in *bytes* 132Count getLength ()const {return Index (m_end - m_begin ); } 133 134/// Finds first index of char 'c'. If not found returns -1. 135Index indexOf (char c )const ; 136/// Find first index of slice. If not found returns -1 137Index indexOf (const UnownedStringSlice & slice )const ; 138 139/// Returns a substring. idx is the start index, and len 140/// is the amount of characters. 141/// The returned length might be truncated, if len extends beyond slice. 142UnownedStringSlice subString (Index idx ,Index len )const ; 143 144/// Return a head of the slice - everything up to the index 145SLANG_FORCE_INLINE UnownedStringSlice head (Index idx )const 146 { 147SLANG_ASSERT (idx >=0 && idx <=getLength ()); 148return UnownedStringSlice (m_begin ,idx ); 149 } 150/// Return a tail of the slice - everything from the index to the end of the slice 151SLANG_FORCE_INLINE UnownedStringSlice tail (Index idx )const 152 { 153SLANG_ASSERT (idx >=0 && idx <=getLength ()); 154return UnownedStringSlice (m_begin + idx ,m_end ); 155 } 156 157/// True if rhs and this are equal without having to take into account case 158/// Note 'case' here is *not* locale specific - it is only A-Z and a-z 159bool caseInsensitiveEquals (const ThisType & rhs )const ; 160 161Index lastIndexOf (char c )const 162 { 163const Index size = Index (m_end - m_begin ); 164for (Index i = size - 1 ;i >=0 ;-- i ) 165 { 166if (m_begin [i ]== c ) 167 { 168return i ; 169 } 170 } 171return -1 ; 172 } 173 174const char & operator [](Index i )const 175 { 176assert (i >=0 && i < Index (m_end - m_begin )); 177return m_begin [i ]; 178 } 179 180bool operator == (ThisType const & other )const ; 181bool operator != (UnownedStringSlice const & other )const {return !(* this == other ); } 182 183bool operator == (char const * str )const {return (* this )== UnownedStringSlice (str ); } 184bool operator != (char const * str )const {return !(* this == str ); } 185 186/// True if contents is a single char of c 187SLANG_FORCE_INLINE bool isChar (char c )const {return getLength ()== 1 && m_begin [0 ]== c ; } 188 189bool startsWithCaseInsensitive (UnownedStringSlice const & other )const ; 190bool startsWith (UnownedStringSlice const & other )const ; 191bool startsWith (char const * str )const ; 192 193bool endsWithCaseInsensitive (UnownedStringSlice const & other )const ; 194bool endsWithCaseInsensitive (char const * str )const ; 195 196bool endsWith (UnownedStringSlice const & other )const ; 197bool endsWith (char const * str )const ; 198 199/// Trims any horizontal whitespace from the start and end and returns as a substring 200UnownedStringSlice trim ()const ; 201/// Trims any 'c' from the start or the end, and returns as a substring 202UnownedStringSlice trim (char c )const ; 203 204/// Trims any horizontal whitespace from start and returns as a substring 205UnownedStringSlice trimStart ()const ; 206 207static constexprbool kHasUniformHash = true; 208HashCode64 getHashCode ()const {return Slang ::getHashCode (m_begin ,size_t (m_end - m_begin )); } 209 210template < size_t SIZE > 211SLANG_FORCE_INLINE static UnownedStringSlice fromLiteral (const char (& in )[SIZE ]) 212 { 213return UnownedStringSlice (in ,SIZE - 1 ); 214 } 215 216protected : 217char const * m_begin ; 218char const * m_end ; 219}; 220 221/// Three-way comparison of string slices. 222/// 223/// * Returns 0 if `lhs == rhs` 224/// * Returns a value < 0 if `lhs < rhs` 225/// * Returns a value > 0 if `lhs > rhs` 226/// 227int compare (UnownedStringSlice const & lhs ,UnownedStringSlice const & rhs ); 228 229// A more convenient way to make slices from *string literals* 230template < size_t SIZE > 231SLANG_FORCE_INLINE UnownedStringSlice toSlice (const char (& in )[SIZE ]) 232{ 233return UnownedStringSlice (in ,SIZE - 1 ); 234} 235 236/// Same as UnownedStringSlice, but must be zero terminated. 237/// Zero termination is *not* included in the length. 238struct SLANG_RT_API UnownedTerminatedStringSlice :public UnownedStringSlice 239{ 240public : 241typedef UnownedStringSlice Super ; 242typedef UnownedTerminatedStringSlice ThisType ; 243 244/// We can turn into a regular zero terminated string 245SLANG_FORCE_INLINE operator const char * ()const { return m_begin; } 246 247/// Exists to match the equivalent function in String. 248SLANG_FORCE_INLINE char const * getBuffer () const { return m_begin; } 249 250/// Construct from a literal directly. 251template < size_t SIZE > 252SLANG_FORCE_INLINE static ThisType fromLiteral ( const char ( & in )[ SIZE ]) 253{ 254return ThisType (in, SIZE - 1 ); 255} 256 257/// Default constructor 258UnownedTerminatedStringSlice () 259: Super ( Super :: WithLength (), "" , 0 ) 260{ 261} 262 263/// Note, b cannot be null because if it were then the string would not be null terminated 264UnownedTerminatedStringSlice( char const * b) 265: Super ( b , b + strlen ( b )) 266{ 267} 268UnownedTerminatedStringSlice( char const * b, size_t len) 269: Super ( b , len ) 270{ 271// b must be valid and it must be null terminated 272SLANG_ASSERT ( b && b[len] == 0 ); 273} 274}; 275 276// A more convenient way to make terminated slices from *string literals* 277template < size_t SIZE > 278SLANG_FORCE_INLINE UnownedTerminatedStringSlice toTerminatedSlice ( const char ( & in )[ SIZE ]) 279{ 280return UnownedTerminatedStringSlice (in, SIZE - 1 ); 281} 282 283// A `StringRepresentation` provides the backing storage for 284// all reference-counted string-related types. 285class SLANG_RT_API StringRepresentation : public RefObject 286{ 287public : 288Index length; 289Index capacity; 290 291SLANG_FORCE_INLINE Index getLength () const { return length; } 292 293SLANG_FORCE_INLINE char * getData () { return ( char * )(this + 1 ); } 294SLANG_FORCE_INLINE const char * getData () const { return ( const char * )(this + 1 ); } 295 296/// Set the contents to be the slice. Must be enough capacity to hold the slice. 297void setContents ( const UnownedStringSlice & slice); 298 299static const char * getData ( const StringRepresentation * stringRep) 300{ 301return stringRep ? stringRep -> getData () : "" ; 302} 303 304static UnownedStringSlice asSlice ( const StringRepresentation * rep) 305{ 306return rep ? UnownedStringSlice (rep -> getData (), rep -> getLength ()) : UnownedStringSlice (); 307} 308 309static bool equal ( const StringRepresentation * a, const StringRepresentation * b) 310{ 311return (a == b) || asSlice (a) == asSlice (b); 312} 313 314static StringRepresentation * createWithCapacityAndLength ( Index capacity, Index length) 315{ 316SLANG_ASSERT (capacity >= length); 317void * allocation = operator new ( sizeof (StringRepresentation) + capacity + 1 ); 318StringRepresentation * obj = new (allocation) StringRepresentation (); 319obj -> capacity = capacity; 320obj -> length = length; 321obj -> getData ()[length] = 0 ; 322return obj; 323} 324 325static StringRepresentation * createWithCapacity ( Index capacity) 326{ 327return createWithCapacityAndLength (capacity, 0 ); 328} 329 330static StringRepresentation * createWithLength ( Index length) 331{ 332return createWithCapacityAndLength (length, length); 333} 334 335/// Create a representation from the slice. If slice is empty will return nullptr. 336static StringRepresentation * create ( const UnownedStringSlice & slice); 337/// Same as create, but representation will have refcount of 1 (if not nullptr) 338static StringRepresentation * createWithReference ( const UnownedStringSlice & slice); 339 340StringRepresentation * cloneWithCapacity ( Index newCapacity) 341{ 342StringRepresentation * newObj = createWithCapacityAndLength (newCapacity, length); 343memcpy ( getData (), newObj -> getData (), length + 1 ); 344return newObj; 345} 346 347StringRepresentation * clone () { return cloneWithCapacity (length); } 348 349StringRepresentation * ensureCapacity ( Index required) 350{ 351if (capacity >= required) 352return this; 353 354Index newCapacity = capacity; 355if (!newCapacity) 356newCapacity = 16 ; // TODO: figure out good value for minimum capacity 357 358while (newCapacity < required) 359{ 360newCapacity = 2 * newCapacity; 361} 362 363return cloneWithCapacity (newCapacity); 364} 365 366/// Overload delete to silence ASAN new-delete-type-mismatch errors. 367/// These occur because the allocation size of StringRepresentation 368/// does not match deallocation size (due variable sized string payload). 369void operator delete ( void * p) 370{ 371StringRepresentation * str = ( StringRepresentation * )p; 372:: operator delete ( str ); 373} 374}; 375 376class String; 377 378struct SLANG_RT_API StringSlice 379{ 380public : 381StringSlice (); 382 383StringSlice( String const & str); 384 385StringSlice( String const & str, UInt beginIndex, UInt endIndex); 386 387UInt getLength () const { return endIndex - beginIndex; } 388 389char const * begin () const 390{ 391return representation ? representation -> getData () + beginIndex : "" ; 392} 393 394char const * end () const { return begin () + getLength (); } 395 396private : 397RefPtr < StringRepresentation > representation; 398UInt beginIndex; 399UInt endIndex; 400 401friend class String; 402 403StringSlice (RefPtr < StringRepresentation > const & representation, UInt beginIndex, UInt endIndex) 404: representation (representation), beginIndex (beginIndex), endIndex (endIndex) 405{ 406} 407}; 408 409/// String as expected by underlying platform APIs 410class SLANG_RT_API OSString 411{ 412public : 413/// Default 414OSString (); 415/// NOTE! This assumes that begin is a new wchar_t[] buffer, and it will 416/// now be owned by the OSString 417OSString (wchar_t * begin, wchar_t * end); 418/// Move Ctor 419OSString (OSString && rhs) 420: m_begin (rhs. m_begin ), m_end (rhs. m_end ) 421{ 422rhs. m_begin = nullptr ; 423rhs. m_end = nullptr ; 424} 425// Copy Ctor 426OSString( const OSString & rhs) 427: m_begin ( nullptr ), m_end ( nullptr ) 428{ 429set (rhs. m_begin , rhs. m_end ); 430} 431 432/// = 433void operator = ( const OSString & rhs) { set (rhs. m_begin , rhs. m_end ); } 434void operator = (OSString && rhs) 435{ 436auto begin = m_begin; 437auto end = m_end; 438m_begin = rhs. m_begin ; 439m_end = rhs. m_end ; 440rhs. m_begin = begin; 441rhs. m_end = end; 442} 443 444~ OSString () { _releaseBuffer (); } 445 446size_t getLength () const { return (m_end - m_begin); } 447void set ( const wchar_t * begin, const wchar_t * end); 448 449operator wchar_t const * () const { return begin (); } 450 451wchar_t const * begin () const; 452wchar_t const * end () const; 453 454private : 455void _releaseBuffer (); 456 457wchar_t * m_begin; ///< First character. This is a new wchar_t[] buffer 458wchar_t * m_end; ///< Points to terminating 0 459}; 460 461/*! 462@brief Represents an owned, zero-terminated UTF-8 encoded string. 463*/ 464class SLANG_RT_API String 465{ 466friend struct StringSlice; 467friend class StringBuilder; 468 469private : 470char * getData () const { return m_buffer ? m_buffer -> getData () : ( char * ) "" ; } 471 472 473void ensureUniqueStorageWithCapacity ( Index capacity); 474 475RefPtr < StringRepresentation > m_buffer; 476 477public : 478explicit String ( StringRepresentation * buffer) 479: m_buffer (buffer) 480{ 481} 482 483static String fromWString ( const wchar_t * wstr); 484static String fromWString ( const wchar_t * wstr, const wchar_t * wend); 485static String fromWChar ( const wchar_t ch); 486static String fromUnicodePoint ( Char32 codePoint); 487 488String () {} 489 490/// Returns a buffer which can hold at least count chars 491char * prepareForAppend ( Index count); 492/// Append data written to buffer output via 'prepareForAppend' directly written 'inplace' 493void appendInPlace ( const char * chars, Index count); 494 495/// Get the internal string represenation 496SLANG_FORCE_INLINE StringRepresentation * getStringRepresentation () const { return m_buffer; } 497 498/// Detach the representation (will leave string as empty). Rep ref count will remain unchanged. 499SLANG_FORCE_INLINE StringRepresentation * detachStringRepresentation () 500{ 501return m_buffer. detach (); 502} 503 504const char * begin () const { return getData (); } 505const char * end () const { return getData () + getLength (); } 506 507void append ( int32_t value, int radix = 10 ); 508void append ( uint32_t value, int radix = 10 ); 509void append ( int64_t value, int radix = 10 ); 510void append ( uint64_t value, int radix = 10 ); 511void append ( float val, const char * format = "%g" ); 512void append ( double val, const char * format = "%g" ); 513 514// Padded hex representations 515void append ( StableHashCode32 val); 516void append ( StableHashCode64 val); 517 518void append ( char const * str); 519void append ( char const * str, size_t len); 520void append ( const char * textBegin, char const * textEnd); 521void append ( char chr); 522void append ( String const & str); 523void append ( StringSlice const & slice); 524void append ( UnownedStringSlice const & slice); 525 526/// Append a character (to remove ambiguity with other integral types) 527void appendChar ( char chr); 528 529/// Append the specified char count times 530void appendRepeatedChar ( char chr, Index count); 531 532String( const char * str) { append ( str ); } 533String( const char * textBegin, char const * textEnd) { append ( textBegin , textEnd ); } 534 535// Make all String ctors from a numeric explicit, to avoid unexpected/unnecessary conversions 536explicit String ( int32_t val, int radix = 10 ) { append (val, radix); } 537explicit String ( uint32_t val, int radix = 10 ) { append (val, radix); } 538explicit String ( int64_t val, int radix = 10 ) { append (val, radix); } 539explicit String ( uint64_t val, int radix = 10 ) { append (val, radix); } 540explicit String ( StableHashCode32 val) { append (val); } 541explicit String ( StableHashCode64 val) { append (val); } 542explicit String ( float val, const char * format = "%g" ) { append (val, format); } 543explicit String ( double val, const char * format = "%g" ) { append (val, format); } 544 545explicit String ( char chr) { appendChar (chr); } 546String( String const & str) { m_buffer = str. m_buffer ; } 547String (String && other) { m_buffer = _Move (other. m_buffer ); } 548 549String( StringSlice const & slice) { append (slice); } 550 551String( UnownedStringSlice const & slice) { append (slice); } 552 553~ String () { m_buffer. setNull (); } 554 555String & operator = ( const String & str) 556{ 557m_buffer = str. m_buffer ; 558return * this; 559} 560String & operator = (String && other) 561{ 562m_buffer = _Move (other. m_buffer ); 563return * this; 564} 565char operator[]( Index id) const 566{ 567SLANG_ASSERT (id >= 0 && id < getLength ()); 568// Silence a pedantic warning on GCC 569#if __GNUC__ 570if (id < 0 ) 571__builtin_unreachable (); 572#endif 573return begin ()[id]; 574} 575 576Index getLength () const { return m_buffer ? m_buffer -> getLength () : 0 ; } 577/// Make the length of the string the amount specified. Must be less than current size 578void reduceLength ( Index length); 579 580friend String operator + ( const char * op1, const String & op2); 581friend String operator + ( const String & op1, const char * op2); 582friend String operator + ( const String & op1, const String & op2); 583 584StringSlice trimStart () const 585{ 586if (!m_buffer) 587return StringSlice (); 588Index startIndex = 0 ; 589const char * const data = getData (); 590while (startIndex < getLength () && (data[startIndex] == ' ' || data[startIndex] == '\t' || 591data[startIndex] == '\r' || data[startIndex] == '\n' )) 592startIndex ++ ; 593return StringSlice (m_buffer, startIndex, getLength ()); 594} 595 596StringSlice trimEnd () const 597{ 598if (!m_buffer) 599return StringSlice (); 600 601Index endIndex = getLength (); 602const char * const data = getData (); 603while (endIndex > 0 && (data[endIndex - 1 ] == ' ' || data[endIndex - 1 ] == '\t' || 604data[endIndex - 1 ] == '\r' || data[endIndex - 1 ] == '\n' )) 605endIndex -- ; 606 607return StringSlice (m_buffer, 0 , endIndex); 608} 609 610StringSlice trim () const 611{ 612if (!m_buffer) 613return StringSlice (); 614 615Index startIndex = 0 ; 616const char * const data = getData (); 617while (startIndex < getLength () && (data[startIndex] == ' ' || data[startIndex] == '\t' || 618data[startIndex] == '\r' || data[startIndex] == '\n' )) 619startIndex ++ ; 620Index endIndex = getLength (); 621while (endIndex > startIndex && (data[endIndex - 1 ] == ' ' || data[endIndex - 1 ] == '\t' || 622data[endIndex - 1 ] == '\r' || data[endIndex - 1 ] == '\n' )) 623endIndex -- ; 624 625return StringSlice (m_buffer, startIndex, endIndex); 626} 627 628StringSlice subString ( Index id, Index len) const 629{ 630if (len == 0 ) 631return StringSlice (); 632 633if (id + len > getLength ()) 634len = getLength () - id; 635#if _DEBUG 636if (id < 0 || id >= getLength () || (id + len) > getLength ()) 637SLANG_ASSERT_FAILURE ( "SubString: index out of range." ); 638if (len < 0 ) 639SLANG_ASSERT_FAILURE ( "SubString: length less than zero." ); 640#endif 641return StringSlice (m_buffer, id, id + len); 642} 643 644char const * getBuffer () const { return getData (); } 645 646OSString toWString ( Index * len = 0 ) const ; 647 648bool equals ( const String & str, bool caseSensitive = true) 649{ 650if (caseSensitive) 651return ( strcmp ( begin (), str. begin ()) == 0 ); 652else 653{ 654#ifdef _MSC_VER 655return ( _stricmp ( begin (), str. begin ()) == 0 ); 656#else 657return ( strcasecmp ( begin (), str. begin ()) == 0 ); 658#endif 659} 660} 661bool operator == ( const char * strbuffer) const { return ( strcmp ( begin (), strbuffer) == 0 ); } 662 663bool operator == ( const String & str) const { return ( strcmp ( begin (), str. begin ()) == 0 ); } 664bool operator != ( const char * strbuffer) const { return ( strcmp ( begin (), strbuffer) != 0 ); } 665bool operator != ( const String & str) const { return ( strcmp ( begin (), str. begin ()) != 0 ); } 666bool operator > ( const String & str) const { return ( strcmp ( begin (), str. begin ()) > 0 ); } 667bool operator < ( const String & str) const { return ( strcmp ( begin (), str. begin ()) < 0 ); } 668bool operator>=( const String & str) const { return ( strcmp ( begin (), str. begin ()) >= 0 ); } 669bool operator<=( const String & str) const { return ( strcmp ( begin (), str. begin ()) <= 0 ); } 670 671SLANG_FORCE_INLINE bool operator == ( const UnownedStringSlice & slice) const 672{ 673return getUnownedSlice () == slice; 674} 675SLANG_FORCE_INLINE bool operator != ( const UnownedStringSlice & slice) const 676{ 677return getUnownedSlice () != slice; 678} 679 680String toUpper () const 681{ 682String result; 683for ( auto c : * this) 684{ 685char d = (c >= 'a' && c <= 'z' ) ? (c - ( 'a' - 'A' )) : c; 686result. append (d); 687} 688return result; 689} 690 691String toLower () const 692{ 693String result; 694for (auto c : * this) 695{ 696char d = (c >= 'A' && c <= 'Z' ) ? (c - ( 'A' - 'a' )) : c; 697result. append (d); 698} 699return result; 700} 701 702Index indexOf (const char * str, Index id) const // String str 703{ 704if (id >= getLength ()) 705return Index ( -1 ); 706auto findRs = strstr ( begin () + id, str); 707Index res = findRs ? findRs - begin () : Index ( -1 ); 708return res; 709} 710 711Index indexOf (const String & str, Index id) const { return indexOf (str. begin (), id); } 712 713Index indexOf (const char * str) const { return indexOf (str, 0 ); } 714 715Index indexOf (const String & str) const { return indexOf (str. begin (), 0 ); } 716 717void swapWith (String & other) { m_buffer. swapWith (other. m_buffer ); } 718 719Index indexOf (char ch, Index id) const 720{ 721const Index length = getLength (); 722SLANG_ASSERT (id >= 0 && id <= length); 723 724if (!m_buffer) 725return Index ( -1 ); 726 727const char * data = getData (); 728for (Index i = id; i < length; i ++ ) 729if (data[i] == ch) 730return i; 731return Index ( -1 ); 732} 733 734Index indexOf (char ch) const { return indexOf (ch, 0 ); } 735 736Index lastIndexOf (char ch) const 737{ 738const Index length = getLength (); 739const char * data = getData (); 740 741for (Index i = length - 1 ; i >= 0 ; -- i) 742if (data[i] == ch) 743return i; 744return Index ( -1 ); 745} 746 747bool startsWith (const char * str) const 748{ 749if (!m_buffer) 750return false; 751Index strLen = Index (:: strlen (str)); 752if (strLen > getLength ()) 753return false; 754 755const char * const data = getData (); 756 757for (Index i = 0 ; i < strLen; i ++ ) 758if (str[i] != data[i]) 759return false; 760return true; 761} 762 763bool startsWith (const String & str) const { return startsWith (str. begin ()); } 764 765bool endsWith (char const * str) const // String str 766{ 767if (!m_buffer) 768return false; 769 770const Index strLen = Index (:: strlen (str)); 771const Index len = getLength (); 772 773if (strLen > len) 774return false; 775const char * data = getData (); 776for (Index i = strLen; i > 0 ; i -- ) 777if (str[i - 1 ] != data[len - strLen + i - 1 ]) 778return false; 779return true; 780} 781 782bool endsWith (const String & str) const { return endsWith (str. begin ()); } 783 784bool contains (const char * str) const // String str 785{ 786return m_buffer && indexOf (str) != Index ( -1 ); 787} 788 789bool contains (const String & str) const { return contains (str. begin ()); } 790 791static constexpr bool kHasUniformHash = true; 792HashCode64 getHashCode () const 793{ 794return Slang:: getHashCode (StringRepresentation:: asSlice (m_buffer)); 795} 796 797UnownedStringSlice getUnownedSlice () const { return StringRepresentation:: asSlice (m_buffer); } 798}; 799 800class ImmutableHashedString 801{ 802public: 803String slice; 804HashCode64 hashCode; 805ImmutableHashedString () 806: hashCode ( 0 ) 807{ 808} 809ImmutableHashedString (const UnownedStringSlice & slice) 810: slice (slice), hashCode (slice. getHashCode ()) 811{ 812} 813ImmutableHashedString (const char * begin, const char * end) 814: slice(begin, end), hashCode (slice. getHashCode ()) 815{ 816} 817ImmutableHashedString( const char * begin, size_t len) 818: slice ( UnownedStringSlice ( begin , len )), hashCode ( slice . getHashCode ()) 819{ 820} 821ImmutableHashedString ( const char * begin) 822: slice (begin), hashCode ( slice . getHashCode ()) 823{ 824} 825ImmutableHashedString ( const String & str) 826: slice (str), hashCode ( str . getHashCode ()) 827{ 828} 829ImmutableHashedString ( String && str) 830: slice ( _Move (str)), hashCode ( str . getHashCode ()) 831{ 832} 833ImmutableHashedString ( const ImmutableHashedString & other) = default; 834ImmutableHashedString & operator = ( const ImmutableHashedString & other) = default; 835bool operator == ( const ImmutableHashedString & other) const 836{ 837return hashCode == other. hashCode && slice == other. slice ; 838} 839bool operator != ( const ImmutableHashedString & other) const 840{ 841return hashCode != other. hashCode || slice != other. slice ; 842} 843bool operator == ( const UnownedStringSlice & other) const { return slice == other; } 844bool operator != ( const UnownedStringSlice & other) const { return slice != other; } 845bool operator == ( const String & other) const { return slice == other. getUnownedSlice (); } 846bool operator != ( const String & other) const { return slice != other. getUnownedSlice (); } 847bool operator == ( const char * other) const { return slice == UnownedStringSlice (other); } 848HashCode64 getHashCode () const { return hashCode; } 849}; 850 851class SLANG_RT_API StringBuilder : public String 852{ 853private : 854enum 855{ 856InitialSize = 1024 857}; 858 859public : 860typedef String Super; 861using Super::append; 862 863explicit StringBuilder ( UInt bufferSize = InitialSize) 864{ 865ensureUniqueStorageWithCapacity (bufferSize); 866} 867 868void ensureCapacity ( UInt size) { ensureUniqueStorageWithCapacity (size); } 869StringBuilder & operator<<( char ch) 870{ 871appendChar (ch); 872return * this; 873} 874StringBuilder & operator<<( Int32 val) 875{ 876append (val); 877return * this; 878} 879StringBuilder & operator<<( UInt32 val) 880{ 881append (val); 882return * this; 883} 884StringBuilder & operator<<( Int64 val) 885{ 886append (val); 887return * this; 888} 889StringBuilder & operator<<( UInt64 val) 890{ 891append (val); 892return * this; 893} 894StringBuilder & operator<<( float val) 895{ 896append (val); 897return * this; 898} 899StringBuilder & operator<<( double val) 900{ 901append (val); 902return * this; 903} 904StringBuilder & operator<<( const char * str) 905{ 906append (str, strlen (str)); 907return * this; 908} 909StringBuilder & operator<<( const String & str) 910{ 911append (str); 912return * this; 913} 914StringBuilder & operator<<( UnownedStringSlice const & str ) 915{ 916append (str); 917return * this; 918} 919StringBuilder & operator<<( const _EndLine ) 920{ 921appendChar ( '\n' ); 922return * this; 923} 924 925String toString () { return * this; } 926 927String produceString () { return * this; } 928 929#if 0 930void Remove ( int id, int len) 931{ 932#if _DEBUG 933if (id >= length || id < 0 ) 934SLANG_ASSERT_FAILURE ( "Remove: Index out of range." ); 935if (len < 0 ) 936SLANG_ASSERT_FAILURE ( "Remove: remove length smaller than zero." ); 937#endif 938int actualDelLength = ((id + len) >= length) ? (length - id) : len; 939for ( int i = id + actualDelLength; i <= length; i ++ ) 940buffer[i - actualDelLength] = buffer[i]; 941length -= actualDelLength; 942} 943#endif 944friend std::ostream & operator<<(std::ostream & stream, const String & s); 945 946void clear () { m_buffer. setNull (); } 947}; 948 949int stringToInt ( const String & str, int radix = 10 ); 950unsigned int stringToUInt ( const String & str, int radix = 10 ); 951double stringToDouble ( const String & str); 952float stringToFloat ( const String & str); 953} // namespace Slang 954 955std ::ostream & operator<<(std::ostream & stream, const Slang::String & s); 956 957#endif