yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
c39c29bf4
master
1#include "slang-string-util.h" 2 3#include "slang-blob.h" 4#include "slang-char-util.h" 5#include "slang-text-io.h" 6 7namespace Slang 8{ 9 10// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! StringUtil !!!!!!!!!!!!!!!!!!!!!!!!!!! 11 12/* static */ bool StringUtil ::areAllEqual ( 13const List < UnownedStringSlice >& a , 14const List < UnownedStringSlice >& b , 15EqualFn equalFn ) 16{ 17if (a .getCount ()!= b .getCount ()) 18 { 19return false; 20 } 21 22const Index count = a .getCount (); 23for (Index i = 0 ;i < count ;++ i ) 24 { 25if (!equalFn (a [i ],b [i ])) 26 { 27return false; 28 } 29 } 30return true; 31} 32 33/* static */ bool StringUtil ::areAllEqualWithSplit ( 34const UnownedStringSlice & a , 35const UnownedStringSlice & b , 36char splitChar , 37EqualFn equalFn ) 38{ 39List < UnownedStringSlice > slicesA ,slicesB ; 40StringUtil ::split (a ,splitChar ,slicesA ); 41StringUtil ::split (b ,splitChar ,slicesB ); 42return areAllEqual (slicesA ,slicesB ,equalFn ); 43} 44 45/* static */ void StringUtil ::appendSplitOnWhitespace ( 46const UnownedStringSlice & in , 47List < UnownedStringSlice >& outSlices ) 48{ 49const char * start = in .begin (); 50const char * end = in .end (); 51 52// Skip any at the start 53while (start < end && CharUtil ::isWhitespace (* start )) 54start ++ ; 55 56while (start < end ) 57 { 58// Find all the non white space in a run 59const char * cur = start ; 60while (cur < end && !CharUtil ::isWhitespace (* cur )) 61 { 62cur ++ ; 63 } 64 65// Add to output 66outSlices .add (UnownedStringSlice (start ,cur )); 67 68// Find the next start 69start = cur + 1 ; 70 71// Skip the split 72while (start < end && CharUtil ::isWhitespace (* start )) 73start ++ ; 74 } 75} 76 77/* static */ void StringUtil ::appendSplit ( 78const UnownedStringSlice & in , 79char splitChar , 80List < UnownedStringSlice >& outSlices ) 81{ 82const char * start = in .begin (); 83const char * end = in .end (); 84 85while (start < end ) 86 { 87// Move cur so it's either at the end or at next split character 88const char * cur = start ; 89while (cur < end && * cur != splitChar ) 90 { 91cur ++ ; 92 } 93 94// Add to output 95outSlices .add (UnownedStringSlice (start ,cur )); 96 97// Skip the split character, if at end we are okay anyway 98start = cur + 1 ; 99 } 100} 101 102/* static */ void StringUtil ::appendSplit ( 103const UnownedStringSlice & in , 104const UnownedStringSlice & splitSlice , 105List < UnownedStringSlice >& outSlices ) 106{ 107const Index splitLen = splitSlice .getLength (); 108 109if (splitLen == 1 ) 110 { 111return appendSplit (in ,splitSlice [0 ],outSlices ); 112 } 113 114SLANG_ASSERT (splitLen > 0 ); 115if (splitLen <=0 ) 116 { 117return ; 118 } 119 120const char * start = in .begin (); 121const char * end = in .end (); 122 123const char splitChar = splitSlice [0 ]; 124 125while (start < end ) 126 { 127// Move cur so it's either at the end or at next splitSlice 128const char * cur = start ; 129while (cur < end ) 130 { 131if (* cur == splitChar && 132 (cur + splitLen <=end && UnownedStringSlice (cur ,splitLen )== splitSlice )) 133 { 134// We hit a split 135break ; 136 } 137 138cur ++ ; 139 } 140 141// Add to output 142outSlices .add (UnownedStringSlice (start ,cur )); 143 144// Skip the split, if at end we are okay anyway 145start = cur + splitLen ; 146 } 147} 148 149/* static */ void StringUtil ::split ( 150const UnownedStringSlice & in , 151char splitChar , 152List < UnownedStringSlice >& outSlices ) 153{ 154outSlices .clear (); 155appendSplit (in ,splitChar ,outSlices ); 156} 157 158/* static */ void StringUtil ::split ( 159const UnownedStringSlice & in , 160const UnownedStringSlice & splitSlice , 161List < UnownedStringSlice >& outSlices ) 162{ 163outSlices .clear (); 164appendSplit (in ,splitSlice ,outSlices ); 165} 166 167/* static */ void StringUtil ::splitOnWhitespace ( 168const UnownedStringSlice & in , 169List < UnownedStringSlice >& outSlices ) 170{ 171outSlices .clear (); 172appendSplitOnWhitespace (in ,outSlices ); 173} 174 175/* static */ Index StringUtil ::split ( 176const UnownedStringSlice & in , 177char splitChar , 178Index maxSlices , 179UnownedStringSlice * outSlices ) 180{ 181Index index = 0 ; 182 183const char * start = in .begin (); 184const char * end = in .end (); 185 186while (start < end && index < maxSlices ) 187 { 188// Move cur so it's either at the end or at next split character 189const char * cur = start ; 190while (cur < end && * cur != splitChar ) 191 { 192cur ++ ; 193 } 194 195// Add to output 196outSlices [index ++ ]= UnownedStringSlice (start ,cur ); 197 198// Skip the split character, if at end we are okay anyway 199start = cur + 1 ; 200 } 201 202return index ; 203} 204 205/* static */ SlangResult StringUtil ::split ( 206const UnownedStringSlice & in , 207char splitChar , 208Index maxSlices , 209UnownedStringSlice * outSlices , 210Index & outSlicesCount ) 211{ 212const Index sliceCount = split (in ,splitChar ,maxSlices ,outSlices ); 213if (sliceCount == maxSlices && sliceCount > 0 ) 214 { 215// To succeed must have parsed all of the input 216if (in .end ()!= outSlices [sliceCount - 1 ].end ()) 217 { 218return SLANG_FAIL ; 219 } 220 } 221outSlicesCount = sliceCount ; 222return SLANG_OK ; 223} 224 225/* static */ void StringUtil ::join (const List < String >& values ,char separator ,StringBuilder & out ) 226{ 227join (values ,UnownedStringSlice (& separator ,1 ),out ); 228} 229 230/* static */ void StringUtil ::join ( 231const List < String >& values , 232const UnownedStringSlice & separator , 233StringBuilder & out ) 234{ 235const Index count = values .getCount (); 236if (count <=0 ) 237 { 238return ; 239 } 240out .append (values [0 ]); 241for (Index i = 1 ;i < count ;i ++ ) 242 { 243out .append (separator ); 244out .append (values [i ]); 245 } 246} 247 248/* static */ void StringUtil ::join ( 249const UnownedStringSlice * values , 250Index valueCount , 251char separator , 252StringBuilder & out ) 253{ 254join (values ,valueCount ,UnownedStringSlice (& separator ,1 ),out ); 255} 256 257/* static */ void StringUtil ::join ( 258const UnownedStringSlice * values , 259Index valueCount , 260const UnownedStringSlice & separator , 261StringBuilder & out ) 262{ 263if (valueCount <=0 ) 264 { 265return ; 266 } 267out .append (values [0 ]); 268for (Index i = 1 ;i < valueCount ;i ++ ) 269 { 270out .append (separator ); 271out .append (values [i ]); 272 } 273} 274 275/* static */ Index StringUtil ::indexOfInSplit ( 276const UnownedStringSlice & in , 277char splitChar , 278const UnownedStringSlice & find ) 279{ 280const char * start = in .begin (); 281const char * end = in .end (); 282 283for (Index i = 0 ;start < end ;++ i ) 284 { 285// Move cur so it's either at the end or at next split character 286const char * cur = start ; 287while (cur < end && * cur != splitChar ) 288 { 289cur ++ ; 290 } 291 292// See if we have a match 293if (UnownedStringSlice (start ,cur )== find ) 294 { 295return i ; 296 } 297 298// Skip the split character, if at end we are okay anyway 299start = cur + 1 ; 300 } 301return -1 ; 302} 303 304UnownedStringSlice StringUtil ::getAtInSplit ( 305const UnownedStringSlice & in , 306char splitChar , 307Index index ) 308{ 309const char * start = in .begin (); 310const char * end = in .end (); 311 312for (Index i = 0 ;start < end ;++ i ) 313 { 314// Move cur so it's either at the end or at next split character 315const char * cur = start ; 316while (cur < end && * cur != splitChar ) 317 { 318cur ++ ; 319 } 320 321if (i == index ) 322 { 323return UnownedStringSlice (start ,cur ); 324 } 325 326// Skip the split character, if at end we are okay anyway 327start = cur + 1 ; 328 } 329 330return UnownedStringSlice (); 331} 332 333/* static */ size_t StringUtil ::calcFormattedSize (const char * format ,va_list args ) 334{ 335#if SLANG_WINDOWS_FAMILY 336return _vscprintf (format ,args ); 337#else 338return vsnprintf (nullptr ,0 ,format ,args ); 339#endif 340} 341 342/* static */ void StringUtil ::calcFormatted ( 343const char * format , 344va_list args , 345size_t numChars , 346char * dst ) 347{ 348#if SLANG_WINDOWS_FAMILY 349vsnprintf_s (dst ,numChars + 1 ,_TRUNCATE ,format ,args ); 350#else 351vsnprintf (dst ,numChars + 1 ,format ,args ); 352#endif 353} 354 355/* static */ void StringUtil ::append (const char * format ,va_list args ,StringBuilder & buf ) 356{ 357// Calculate the size required (not including terminating 0) 358size_t numChars ; 359 { 360// Create a copy of args, as will be consumed by calcFormattedSize 361va_list argsCopy ; 362va_copy (argsCopy ,args ); 363numChars = calcFormattedSize (format ,argsCopy ); 364va_end (argsCopy ); 365 } 366 367// Requires + 1 , because calcFormatted appends a terminating 0 368char * dst = buf .prepareForAppend (numChars + 1 ); 369calcFormatted (format ,args ,numChars ,dst ); 370buf .appendInPlace (dst ,numChars ); 371} 372 373/* static */ void StringUtil ::appendFormat (StringBuilder & buf ,const char * format , ...) 374{ 375va_list args ; 376va_start (args ,format ); 377append (format ,args ,buf ); 378va_end (args ); 379} 380 381/* static */ String StringUtil ::makeStringWithFormat (const char * format , ...) 382{ 383StringBuilder builder ; 384 385va_list args ; 386va_start (args ,format ); 387append (format ,args ,builder ); 388va_end (args ); 389 390return builder ; 391} 392 393template < typename T > 394static T readValue (ArrayView < const void *> ptrToArgs ,Count & argIndex ) 395{ 396if (argIndex < ptrToArgs .getCount ()) 397 { 398T value ; 399memcpy (& value ,ptrToArgs [argIndex ],sizeof (T )); 400argIndex ++ ; 401return value ; 402 } 403return T (); 404} 405 406String StringUtil ::makeStringWithFormatFromArgArray ( 407const char * format , 408ArrayView < const void *> ptrToArgs ) 409{ 410if (!format ) 411 { 412return String (); 413 } 414StringBuilder builder ; 415const char * ptr = format ; 416Count argIndex = 0 ; 417auto consumeString = [& ]() 418 { 419if (argIndex < ptrToArgs .getCount ()) 420 { 421const char * strPtr = * (const char ** )ptrToArgs [argIndex ]; 422argIndex ++ ; 423if (strPtr ) 424 { 425// Append the string to the builder 426builder .append (strPtr ); 427 } 428 } 429 }; 430#define ADVANCE_PTR \ 431 ptr++; \ 432 if (!*ptr) \ 433 { \ 434 return builder.produceString(); \ 435 } 436 437while (* ptr ) 438 { 439if (* ptr == '%' ) 440 { 441const char * formatStart = ptr ; 442ADVANCE_PTR ; 443if (* ptr == 's' ) 444 { 445// If we have a %s, then we want to append the data 446consumeString (); 447// Move past the 's' 448ADVANCE_PTR ; 449continue ; 450 } 451if (* ptr == '-' ) 452 { 453// If we have a %- then we want to continue parsing format string. 454ADVANCE_PTR ; 455 } 456while (CharUtil ::isDigit (* ptr )) 457 { 458// Skip the digits after the '.' 459ADVANCE_PTR ; 460 } 461if (* ptr == '.' ) 462 { 463ADVANCE_PTR ; 464while (CharUtil ::isDigit (* ptr )) 465 { 466// Skip the digits after the '.' 467ADVANCE_PTR ; 468 } 469 } 470int isLong = 0 ; 471if (* ptr == 'l' || * ptr == 'L' ) 472 { 473// If we have a 'l' or 'L', then we want to skip it. 474ADVANCE_PTR ; 475isLong = 1 ; 476if (* ptr == 'l' || * ptr == 'L' ) 477 { 478// If we have another 'l' or 'L', then we want to skip it too. 479ADVANCE_PTR ; 480isLong = 2 ; 481 } 482 } 483const char typeChar = * ptr ; 484ADVANCE_PTR ; 485String formatStr = UnownedStringSlice (formatStart ,ptr ); 486switch (CharUtil ::toLower (typeChar )) 487 { 488case 'd' : 489case 'x' : 490case 'i' : 491case 'u' : 492case 'o' : 493case 'c' : 494if (isLong == 2 ) 495 { 496StringUtil ::appendFormat ( 497builder , 498formatStr .getBuffer (), 499readValue < int64_t > (ptrToArgs ,argIndex )); 500 } 501else 502 { 503StringUtil ::appendFormat ( 504builder , 505formatStr .getBuffer (), 506readValue < int > (ptrToArgs ,argIndex )); 507 } 508break ; 509case 'e' : 510case 'f' : 511case 'g' : 512if (isLong != 0 ) 513 { 514StringUtil ::appendFormat ( 515builder , 516formatStr .getBuffer (), 517readValue < double > (ptrToArgs ,argIndex )); 518 } 519else 520 { 521StringUtil ::appendFormat ( 522builder , 523formatStr .getBuffer (), 524readValue < float > (ptrToArgs ,argIndex )); 525 } 526break ; 527case 'n' : 528break ; 529case '%' : 530// If we have a '%%' then we want to append a single '%' 531builder .appendChar ('%' ); 532continue ; 533 } 534 } 535else 536 { 537// Just append the character 538builder .appendChar (* ptr ); 539ptr ++ ; 540 } 541 } 542return builder .produceString (); 543} 544 545 546/* static */ UnownedStringSlice StringUtil ::getSlice (ISlangBlob * blob ) 547{ 548if (blob ) 549 { 550size_t size = blob -> getBufferSize (); 551if (size > 0 ) 552 { 553const char * contents = (const char * )blob -> getBufferPointer (); 554// Check it has terminating 0, if it has we skip it, because slices do not need zero 555// termination 556if (contents [size - 1 ]== 0 ) 557 { 558size -- ; 559 } 560return UnownedStringSlice (contents ,contents + size ); 561 } 562 } 563return UnownedStringSlice (); 564} 565 566/* static */ String StringUtil ::getString (ISlangBlob * blob ) 567{ 568return getSlice (blob ); 569} 570 571ComPtr < ISlangBlob > StringUtil ::createStringBlob (const String & string ) 572{ 573return StringBlob ::create (string ); 574} 575 576/* static */ String StringUtil ::calcCharReplaced ( 577const UnownedStringSlice & slice , 578char fromChar , 579char toChar ) 580{ 581if (fromChar == toChar ) 582 { 583return slice ; 584 } 585 586const Index numChars = slice .getLength (); 587const char * srcChars = slice .begin (); 588 589StringBuilder builder ; 590char * dstChars = builder .prepareForAppend (numChars ); 591 592for (Index i = 0 ;i < numChars ;++ i ) 593 { 594char c = srcChars [i ]; 595dstChars [i ]= (c == fromChar ) ?toChar :c ; 596 } 597 598builder .appendInPlace (dstChars ,numChars ); 599return builder ; 600} 601 602/* static */ String StringUtil ::calcCharReplaced (const String & string ,char fromChar ,char toChar ) 603{ 604return (fromChar == toChar || string .indexOf (fromChar )== Index (-1 )) 605 ?string 606 :calcCharReplaced (string .getUnownedSlice (),fromChar ,toChar ); 607} 608 609String StringUtil ::replaceAll ( 610UnownedStringSlice text , 611UnownedStringSlice subStr , 612UnownedStringSlice replacement ) 613{ 614StringBuilder builder ; 615for (Index i = 0 ;i < text .getLength ();) 616 { 617if (i + subStr .getLength ()> text .getLength ()) 618 { 619builder .append (text .subString (i ,text .getLength ()- i )); 620break ; 621 } 622if (text .subString (i ,subStr .getLength ())== subStr ) 623 { 624builder .append (replacement ); 625i += subStr .getLength (); 626 } 627else 628 { 629builder .append (text [i ]); 630i ++ ; 631 } 632 } 633return builder .produceString (); 634} 635 636 637/* static */ void StringUtil ::appendStandardLines ( 638const UnownedStringSlice & text , 639StringBuilder & out ) 640{ 641const char * cur = text .begin (); 642const char * start = cur ; 643const char * const end = text .end (); 644 645while (cur < end ) 646 { 647const char c = * cur ; 648switch (c ) 649 { 650case '\n' : 651 { 652++ cur ; 653if (cur < end && * cur == '\r' ) 654 { 655// If we have following \r, we should append with \n 656// Append (including \n) 657out .append (start ,cur ); 658// Skip the \r 659start = ++ cur ; 660 } 661else 662 { 663// If not, we don't need to append because just \n is 'standard', and everything 664// remaining is appended at the end 665 } 666break ; 667 } 668case '\r' : 669 { 670out .append (start ,cur ); 671out .appendChar ('\n' ); 672 673++ cur ; 674// If next is \n, we want to skip that 675cur += Index (cur < end && * cur == '\n' ); 676start = cur ; 677break ; 678 } 679default : 680 { 681cur ++ ; 682break ; 683 } 684 } 685 } 686 687if (start < end ) 688 { 689out .append (start ,end ); 690 } 691} 692 693/* static */ bool StringUtil ::extractLine (UnownedStringSlice & ioText ,UnownedStringSlice & outLine ) 694{ 695char const * const begin = ioText .begin (); 696char const * const end = ioText .end (); 697 698// If we have hit the end then return the 'special' terminator 699if (begin == nullptr ) 700 { 701outLine = UnownedStringSlice (nullptr ,nullptr ); 702return false; 703 } 704 705char const * cursor = begin ; 706while (cursor < end ) 707 { 708int c = * cursor ++ ; 709switch (c ) 710 { 711case '\r' : 712case '\n' : 713 { 714// Remember the end of the line 715const char * const lineEnd = cursor - 1 ; 716 717// When we see a line-break character we need 718// to record the line break, but we also need 719// to deal with the annoying issue of encodings, 720// where a multi-byte sequence might encode 721// the line break. 722if (cursor < end ) 723 { 724int d = * cursor ; 725if ((c ^d )== ('\r' ^'\n' )) 726cursor ++ ; 727 } 728 729ioText = UnownedStringSlice (cursor ,end ); 730outLine = UnownedStringSlice (begin ,lineEnd ); 731return true; 732 } 733default : 734break ; 735 } 736 } 737 738// There is nothing remaining 739ioText = UnownedStringSlice (nullptr ,nullptr ); 740 741// Could be empty, or the remaining line (without line end terminators of) 742SLANG_ASSERT (begin <=cursor ); 743 744outLine = UnownedStringSlice (begin ,cursor ); 745return true; 746} 747 748/* static */ void StringUtil ::calcLines ( 749const UnownedStringSlice & textIn , 750List < UnownedStringSlice >& outLines ) 751{ 752outLines .clear (); 753UnownedStringSlice text (textIn ),line ; 754while (extractLine (text ,line )) 755 { 756outLines .add (line ); 757 } 758} 759 760/* static */ UnownedStringSlice StringUtil ::trimEndOfLine (const UnownedStringSlice & line ) 761{ 762// Strip CR/LF from end of line if present 763 764const char * begin = line .begin (); 765const char * end = line .end (); 766 767if (end > begin ) 768 { 769const char c = end [-1 ]; 770// If last char is CR/LF move back a char 771if (c == '\n' || c == '\r' ) 772 { 773-- end ; 774// If next char is a match for the CR/LF pair move back an extra char. 775end -= Index ((end > begin )&& (c ^end [-1 ])== ('\r' ^'\n' )); 776 } 777 } 778 779return line .head (Index (end - begin )); 780} 781 782/* static */ bool StringUtil ::areLinesEqual ( 783const UnownedStringSlice & inA , 784const UnownedStringSlice & inB ) 785{ 786UnownedStringSlice a (inA ),b (inB ),lineA ,lineB ; 787 788while (true) 789 { 790const auto hasLineA = extractLine (a ,lineA ); 791const auto hasLineB = extractLine (b ,lineB ); 792 793if (!(hasLineA && hasLineB )) 794 { 795return hasLineA == hasLineB ; 796 } 797 798// The lines must be equal 799if (lineA != lineB ) 800 { 801return false; 802 } 803 } 804} 805 806/* static */ SlangResult StringUtil ::parseDouble (const UnownedStringSlice & text ,double & out ) 807{ 808const Index bufSize = 32 ; 809 810const auto len = text .getLength (); 811 812if (len > bufSize - 1 ) 813 { 814List < char > work ; 815work .setCount (len + 1 ); 816char * dst = work .getBuffer (); 817 818 ::memcpy (dst ,text .begin (),len * sizeof (char )); 819dst [len ]= 0 ; 820 821out = atof (dst ); 822 } 823else 824 { 825char buf [bufSize ]; 826 ::memcpy (buf ,text .begin (),len * sizeof (char )); 827buf [len ]= 0 ; 828out = atof (buf ); 829 } 830return SLANG_OK ; 831} 832 833/* static */ SlangResult StringUtil ::parseInt (const UnownedStringSlice & in ,Int & outValue ) 834{ 835const char * cur = in .begin (); 836const char * end = in .end (); 837 838bool negate = false; 839if (cur < end && * cur == '-' ) 840 { 841negate = true; 842cur ++ ; 843 } 844 845int radix = 10 ; 846auto getDigit = CharUtil ::getDecimalDigitValue ; 847if (cur + 1 < end && * cur == '0' && (* (cur + 1 )== 'x' || * (cur + 1 )== 'X' )) 848 { 849radix = 16 ; 850getDigit = CharUtil ::getHexDigitValue ; 851cur += 2 ; 852 } 853 854// We need at least one digit 855if (cur >=end || !CharUtil ::isDigit (* cur )) 856 { 857return SLANG_FAIL ; 858 } 859 860Int value = 0 ; 861// Do the digits 862for (;cur < end ;++ cur ) 863 { 864const auto d = getDigit (* cur ); 865if (d == -1 ) 866return SLANG_FAIL ; 867value = value * radix + d ; 868 } 869 870value = negate ?- value :value ; 871 872outValue = value ; 873return SLANG_OK ; 874} 875 876/* static */ SlangResult StringUtil ::parseInt64 (const UnownedStringSlice & text ,int64_t & out ) 877{ 878bool negate = false; 879 880const char * cur = text .begin (); 881const char * end = text .end (); 882 883if (cur < end ) 884 { 885if (* cur == '-' ) 886 { 887negate = true; 888cur ++ ; 889 } 890else if (* cur == '+' ) 891 { 892cur ++ ; 893 } 894 } 895 896// Must have at least one digit 897if (cur >=end || !CharUtil ::isDigit (* cur )) 898 { 899return SLANG_FAIL ; 900 } 901 902uint64_t value = 0 ; 903// We can have 20 digits, but the last digit can cause overflow. 904// Lets do the easy first digits first 905Index numSimple = 19 ; 906for (;cur < end && CharUtil ::isDigit (* cur )&& numSimple > 0 ;++ cur ,-- numSimple ) 907 { 908value = value * 10 + (* cur - '0' ); 909 } 910 911if (cur < end && CharUtil ::isDigit (* cur )) 912 { 913const auto prevValue = value ; 914value = value * 10 + (* cur - '0' ); 915cur ++ ; 916 917if (value < prevValue ) 918 { 919// We have overflow 920return SLANG_FAIL ; 921 } 922 } 923 924if (negate ) 925 { 926if (value > ~((~uint64_t (0 )) >>1 )) 927 { 928// Overflow 929return SLANG_FAIL ; 930 } 931out = - int64_t (value ); 932 } 933else 934 { 935if (value > ((~uint64_t (0 )) >>1 )) 936 { 937// Overflow 938return SLANG_FAIL ; 939 } 940out = value ; 941 } 942 943return (cur == end ) ?SLANG_OK :SLANG_FAIL ; 944} 945 946int StringUtil ::parseIntAndAdvancePos (UnownedStringSlice text ,Index & pos ) 947{ 948int result = 0 ; 949while (text [pos ]== ' ' && pos < text .getLength ()) 950 { 951pos ++ ; 952continue ; 953 } 954bool isNeg = false; 955if (pos < text .getLength ()&& text [pos ]== '-' ) 956 { 957pos ++ ; 958isNeg = true; 959 } 960while (pos < text .getLength ()) 961 { 962if (text [pos ] >='0' && text [pos ] <='9' ) 963 { 964result *=10 ; 965result += text [pos ]- '0' ; 966pos ++ ; 967 } 968else 969 { 970break ; 971 } 972 } 973if (isNeg ) 974result = - result ; 975return result ; 976} 977 978}// namespace Slang