blitz_string.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. #include "blitz.h"
  2. #include "bdwgc/libatomic_ops/src/atomic_ops.h"
  3. #include "blitz_unicode.h"
  4. static void bbStringFree( BBObject *o );
  5. static BBDebugScope debugScope={
  6. BBDEBUGSCOPE_USERTYPE,
  7. "String",
  8. BBDEBUGDECL_END
  9. };
  10. BBClass bbStringClass={
  11. &bbObjectClass, //super
  12. bbStringFree, //free
  13. &debugScope, //DebugScope
  14. 0, //instance_size
  15. 0, //ctor
  16. 0, //dtor
  17. (BBString*(*)(BBObject*))bbStringToString,
  18. (int(*)(BBObject*,BBObject*))bbStringCompare,
  19. bbObjectSendMessage,
  20. bbObjectReserved,
  21. bbObjectReserved,
  22. bbObjectReserved,
  23. bbStringFind,
  24. bbStringFindLast,
  25. bbStringTrim,
  26. bbStringReplace,
  27. bbStringToLower,
  28. bbStringToUpper,
  29. bbStringToInt,
  30. bbStringToLong,
  31. bbStringToFloat,
  32. bbStringToDouble,
  33. bbStringToCString,
  34. bbStringToWString,
  35. bbStringFromInt,
  36. bbStringFromLong,
  37. bbStringFromFloat,
  38. bbStringFromDouble,
  39. bbStringFromCString,
  40. bbStringFromWString,
  41. bbStringFromBytes,
  42. bbStringFromShorts,
  43. bbStringStartsWith,
  44. bbStringEndsWith,
  45. bbStringContains,
  46. bbStringSplit,
  47. bbStringJoin,
  48. bbStringFromUTF8String,
  49. bbStringToUTF8String
  50. };
  51. BBString bbEmptyString={
  52. &bbStringClass, //clas
  53. 0 //length
  54. };
  55. static int wstrlen( const BBChar *p ){
  56. const BBChar *t=p;
  57. while( *t ) ++t;
  58. return t-p;
  59. }
  60. static int charsEqual( unsigned short *a,unsigned short *b,int n ){
  61. while( n-- ){
  62. if (*a!=*b) return 0;
  63. a++;b++;
  64. }
  65. return 1;
  66. }
  67. //***** Note: Not called in THREADED mode.
  68. static void bbStringFree( BBObject *o ){
  69. #ifdef BB_GC_RC
  70. BBString *str=(BBString*)o;
  71. if( str==&bbEmptyString ){
  72. //str->refs=BBGC_MANYREFS;
  73. return;
  74. }
  75. bbGCDeallocObject( str,sizeof(BBString)+str->length*sizeof(BBChar) );
  76. #endif
  77. }
  78. BBString *bbStringNew( int len ){
  79. int flags;
  80. BBString *str;
  81. if( !len ) return &bbEmptyString;
  82. str=(BBString*)bbGCAllocObject( sizeof(BBString)+len*sizeof(BBChar),&bbStringClass,BBGC_ATOMIC );
  83. str->length=len;
  84. return str;
  85. }
  86. BBString *bbStringFromChar( int c ){
  87. BBString *str=bbStringNew(1);
  88. str->buf[0]=c;
  89. return str;
  90. }
  91. BBString *bbStringFromInt( int n ){
  92. char buf[64],*p=buf+64;
  93. int neg=n<0;
  94. if( neg ){
  95. n=-n;if( n<0 ) return bbStringFromBytes( "-2147483648",11 );
  96. }
  97. do{
  98. *--p=n%10+'0';
  99. }while(n/=10);
  100. if( neg ) *--p='-';
  101. return bbStringFromBytes( p,buf+64-p );
  102. }
  103. BBString *bbStringFromLong( BBInt64 n ){
  104. char buf[64],*p=buf+64;
  105. int neg=n<0;
  106. if( neg ){
  107. n=-n;if( n<0 ) return bbStringFromBytes( "-9223372036854775808",20 );
  108. }
  109. do{
  110. *--p=n%10+'0';
  111. }while(n/=10);
  112. if( neg ) *--p='-';
  113. return bbStringFromBytes( p,buf+64-p );
  114. }
  115. BBString *bbStringFromFloat( float n ){
  116. char buf[64];
  117. sprintf( buf,"%#.9g",n );
  118. return bbStringFromCString(buf);
  119. }
  120. BBString *bbStringFromDouble( double n ){
  121. char buf[64];
  122. sprintf( buf,"%#.17lg",n );
  123. return bbStringFromCString(buf);
  124. }
  125. BBString *bbStringFromBytes( const char *p,int n ){
  126. int k;
  127. BBString *str;
  128. if( !n ) return &bbEmptyString;
  129. str=bbStringNew( n );
  130. for( k=0;k<n;++k ) str->buf[k]=(unsigned char)p[k];
  131. return str;
  132. }
  133. BBString *bbStringFromShorts( const unsigned short *p,int n ){
  134. BBString *str;
  135. if( !n ) return &bbEmptyString;
  136. str=bbStringNew( n );
  137. bbMemCopy( str->buf,p,n*sizeof(short) );
  138. return str;
  139. }
  140. BBString *bbStringFromInts( const int *p,int n ){
  141. int k;
  142. BBString *str;
  143. if( !n ) return &bbEmptyString;
  144. str=bbStringNew( n );
  145. for( k=0;k<n;++k ) str->buf[k]=p[k];
  146. return str;
  147. }
  148. BBString *bbStringFromArray( BBArray *arr ){
  149. int n;
  150. void *p;
  151. if( arr->dims!=1 ) return &bbEmptyString;
  152. n=arr->scales[0];
  153. p=BBARRAYDATA(arr,arr->dims);
  154. switch( arr->type[0] ){
  155. case 'b':return bbStringFromBytes( p,n );
  156. case 's':return bbStringFromShorts( p,n );
  157. case 'i':return bbStringFromInts( p,n );
  158. }
  159. return &bbEmptyString;
  160. }
  161. BBString *bbStringFromCString( const char *p ){
  162. return p ? bbStringFromBytes( p,strlen(p) ) : &bbEmptyString;
  163. }
  164. BBString *bbStringFromWString( const BBChar *p ){
  165. return p ? bbStringFromShorts( p,wstrlen(p) ) : &bbEmptyString;
  166. }
  167. BBString *bbStringFromUTF8String( const char *p ){
  168. int c,n;
  169. short *d,*q;
  170. BBString *str;
  171. if( !p ) return &bbEmptyString;
  172. n=strlen(p);
  173. d=(short*)malloc( n*2 );
  174. q=d;
  175. while( c=*p++ & 0xff ){
  176. if( c<0x80 ){
  177. *q++=c;
  178. }else{
  179. int d=*p++ & 0x3f;
  180. if( c<0xe0 ){
  181. *q++=((c&31)<<6) | d;
  182. }else{
  183. int e=*p++ & 0x3f;
  184. if( c<0xf0 ){
  185. *q++=((c&15)<<12) | (d<<6) | e;
  186. }else{
  187. int f=*p++ & 0x3f;
  188. int v=((c&7)<<18) | (d<<12) | (e<<6) | f;
  189. if( v & 0xffff0000 ) bbExThrowCString( "Unicode character out of UCS-2 range" );
  190. *q++=v;
  191. }
  192. }
  193. }
  194. }
  195. str=bbStringFromShorts( d,q-d );
  196. free( d );
  197. return str;
  198. }
  199. BBString *bbStringToString( BBString *t ){
  200. return t;
  201. }
  202. int bbStringCompare( BBString *x,BBString *y ){
  203. int k,n,sz;
  204. sz=x->length<y->length ? x->length : y->length;
  205. for( k=0;k<sz;++k ) if( n=x->buf[k]-y->buf[k] ) return n;
  206. return x->length-y->length;
  207. }
  208. int bbStringStartsWith( BBString *x,BBString *y ){
  209. BBChar *p,*q;
  210. int k,sz=y->length;
  211. if( x->length<sz ) return 0;
  212. p=x->buf;
  213. q=y->buf;
  214. for( k=0;k<sz;++k ) if( *p++!=*q++ ) return 0;
  215. return 1;
  216. }
  217. int bbStringEndsWith( BBString *x,BBString *y ){
  218. BBChar *p,*q;
  219. int k,sz=y->length;
  220. if( x->length<sz ) return 0;
  221. p=x->buf+x->length-sz;
  222. q=y->buf;
  223. for( k=0;k<sz;++k ) if( *p++!=*q++ ) return 0;
  224. return 1;
  225. }
  226. int bbStringContains( BBString *x,BBString *y ){
  227. return bbStringFind( x,y,0 )!=-1;
  228. }
  229. BBString *bbStringConcat( BBString *x,BBString *y ){
  230. int len=x->length+y->length;
  231. BBString *t=bbStringNew(len);
  232. memcpy( t->buf,x->buf,x->length*sizeof(BBChar) );
  233. memcpy( t->buf+x->length,y->buf,y->length*sizeof(BBChar) );
  234. return t;
  235. }
  236. BBString *bbStringSlice( BBString *in,int beg,int end ){
  237. BBChar *p;
  238. BBString *out;
  239. int k,n,len,inlen;
  240. len=end-beg;
  241. if( len<=0 ) return &bbEmptyString;
  242. out=bbStringNew( len );
  243. p=out->buf;
  244. inlen=in->length;
  245. if( (n=-beg)>0 ){
  246. if( beg+n>end ) n=end-beg;
  247. for( k=0;k<n;++k ) *p++=' ';
  248. if( (beg+=n)==end ) return out;
  249. }
  250. if( (n=inlen-beg)>0 ){
  251. BBChar *q=in->buf+beg;
  252. if( beg+n>end ) n=end-beg;
  253. for( k=0;k<n;++k ) *p++=*q++;
  254. if( (beg+=n)==end ) return out;
  255. }
  256. if( (n=end-beg)>0 ){
  257. for( k=0;k<n;++k ) *p++=' ';
  258. }
  259. return out;
  260. }
  261. BBString *bbStringTrim( BBString *str ){
  262. int b=0,e=str->length;
  263. while( b<e && str->buf[b]<=' ' ) ++b;
  264. if( b==e ) return &bbEmptyString;
  265. while( str->buf[e-1]<=' ' ) --e;
  266. if( e-b==str->length ) return str;
  267. return bbStringFromShorts( str->buf+b,e-b );
  268. }
  269. BBString *bbStringReplace( BBString *str,BBString *sub,BBString *rep ){
  270. int i,d,n,j,p;
  271. if( !sub->length ) return str;
  272. i=0;n=0;
  273. while( (i=bbStringFind(str,sub,i))!=-1 ) {i+=sub->length;n++;}
  274. if (!n) return str;
  275. d=rep->length-sub->length;
  276. BBString *t=bbStringNew( str->length+d*n );
  277. i=0;p=0;
  278. while( (j=bbStringFind(str,sub,i))!=-1 )
  279. {
  280. n=j-i;if (n) {memcpy( t->buf+p,str->buf+i,n*sizeof(BBChar) );p+=n;}
  281. n=rep->length;memcpy( t->buf+p,rep->buf,n*sizeof(BBChar) );p+=n;
  282. i=j+sub->length;
  283. }
  284. n=str->length-i;
  285. if (n) memcpy( t->buf+p,str->buf+i,n*sizeof(BBChar) );
  286. return t;
  287. }
  288. int bbStringAsc( BBString *t ){
  289. return t->length ? t->buf[0] : -1;
  290. }
  291. int bbStringFind( BBString *x,BBString *y,int i ){
  292. if( i<0 ) i=0;
  293. while( i+y->length<=x->length ){
  294. if( charsEqual( x->buf+i,y->buf,y->length ) ) return i;
  295. ++i;
  296. }
  297. return -1;
  298. }
  299. int bbStringFindLast( BBString *x,BBString *y,int i ){
  300. bbassert( i>=0 );
  301. i=x->length-i;
  302. if (i+y->length>x->length) i=x->length-y->length;
  303. while (i>=0)
  304. {
  305. if( charsEqual( x->buf+i,y->buf,y->length ) ) return i;
  306. --i;
  307. }
  308. return -1;
  309. }
  310. int bbStringToInt( BBString *t ){
  311. int i=0,neg=0,n=0;
  312. while( i<t->length && isspace(t->buf[i]) ) ++i;
  313. if( i==t->length ) return 0;
  314. if( t->buf[i]=='+' ) ++i;
  315. else if( neg=(t->buf[i]=='-') ) ++i;
  316. if( i==t->length ) return 0;
  317. if( t->buf[i]=='%' ){
  318. for( ++i;i<t->length;++i ){
  319. int c=t->buf[i];
  320. if( c!='0' && c!='1' ) break;
  321. n=n*2+(c-'0');
  322. }
  323. }else if( t->buf[i]=='$' ){
  324. for( ++i;i<t->length;++i ){
  325. int c=toupper(t->buf[i]);
  326. if( !isxdigit(c) ) break;
  327. if( c>='A' ) c-=('A'-'0'-10);
  328. n=n*16+(c-'0');
  329. }
  330. }else{
  331. for( ;i<t->length;++i ){
  332. int c=t->buf[i];
  333. if( !isdigit(c) ) break;
  334. n=n*10+(c-'0');
  335. }
  336. }
  337. return neg ? -n : n;
  338. }
  339. BBInt64 bbStringToLong( BBString *t ){
  340. int i=0,neg=0;
  341. BBInt64 n=0;
  342. while( i<t->length && isspace(t->buf[i]) ) ++i;
  343. if( i==t->length ){ return 0; }
  344. if( t->buf[i]=='+' ) ++i;
  345. else if( neg=(t->buf[i]=='-') ) ++i;
  346. if( i==t->length ){ return 0; }
  347. if( t->buf[i]=='%' ){
  348. for( ++i;i<t->length;++i ){
  349. int c=t->buf[i];
  350. if( c!='0' && c!='1' ) break;
  351. n=n*2+(c-'0');
  352. }
  353. }else if( t->buf[i]=='$' ){
  354. for( ++i;i<t->length;++i ){
  355. int c=toupper(t->buf[i]);
  356. if( !isxdigit(c) ) break;
  357. if( c>='A' ) c-=('A'-'0'-10);
  358. n=n*16+(c-'0');
  359. }
  360. }else{
  361. for( ;i<t->length;++i ){
  362. int c=t->buf[i];
  363. if( !isdigit(c) ) break;
  364. n=n*10+(c-'0');
  365. }
  366. }
  367. //*r=neg ? -n : n;
  368. return neg ? -n : n;
  369. }
  370. float bbStringToFloat( BBString *t ){
  371. char *p=bbStringToCString( t );
  372. float n=atof( p );
  373. bbMemFree( p );
  374. return n;
  375. }
  376. double bbStringToDouble( BBString *t ){
  377. char *p=bbStringToCString( t );
  378. double n=atof( p );
  379. bbMemFree( p );
  380. return n;
  381. }
  382. BBString *bbStringToLower( BBString *str ){
  383. int k;
  384. BBString *t;
  385. t=bbStringNew( str->length );
  386. for( k=0;k<str->length;++k ){
  387. int c=str->buf[k];
  388. if( c<192 ){
  389. c=(c>='A' && c<='Z') ? (c|32) : c;
  390. }else{
  391. int lo=0,hi=3828/4-1; // sizeof(bbToLowerData)=3828
  392. while( lo<=hi ){
  393. int mid=(lo+hi)/2;
  394. if( c<bbToLowerData[mid*2] ){
  395. hi=mid-1;
  396. }else if( c>bbToLowerData[mid*2] ){
  397. lo=mid+1;
  398. }else{
  399. c=bbToLowerData[mid*2+1];
  400. break;
  401. }
  402. }
  403. }
  404. t->buf[k]=c;
  405. }
  406. return t;
  407. }
  408. BBString *bbStringToUpper( BBString *str ){
  409. int k;
  410. BBString *t;
  411. t=bbStringNew( str->length );
  412. for( k=0;k<str->length;++k ){
  413. int c=str->buf[k];
  414. if( c<181 ){
  415. c=(c>='a' && c<='z') ? (c&~32) : c;
  416. }else{
  417. int lo=0,hi= 3860/4-1; // sizeof(bbToUpperData)= 3860
  418. while( lo<=hi ){
  419. int mid=(lo+hi)/2;
  420. if( c<bbToUpperData[mid*2] ){
  421. hi=mid-1;
  422. }else if( c>bbToUpperData[mid*2] ){
  423. lo=mid+1;
  424. }else{
  425. c=bbToUpperData[mid*2+1];
  426. break;
  427. }
  428. }
  429. }
  430. t->buf[k]=c;
  431. }
  432. return t;
  433. }
  434. char *bbStringToCString( BBString *str ){
  435. char *p;
  436. int k,sz=str->length;
  437. p=(char*)bbMemAlloc( sz+1 );
  438. for( k=0;k<sz;++k ) p[k]=str->buf[k];
  439. p[sz]=0;
  440. return p;
  441. }
  442. BBChar *bbStringToWString( BBString *str ){
  443. BBChar *p;
  444. int k,sz=str->length;
  445. p=(BBChar*)bbMemAlloc( (sz+1)*sizeof(BBChar) );
  446. memcpy(p,str->buf,sz*sizeof(BBChar));
  447. p[sz]=0;
  448. return p;
  449. }
  450. char *bbStringToUTF8String( BBString *str ){
  451. int i,len=str->length;
  452. char *buf=(char*)bbMemAlloc( len*3+1 );
  453. char *q=buf;
  454. unsigned short *p=str->buf;
  455. for( i=0;i<len;++i ){
  456. unsigned int c=*p++;
  457. if( c<0x80 ){
  458. *q++=c;
  459. }else if( c<0x800 ){
  460. *q++=0xc0|(c>>6);
  461. *q++=0x80|(c&0x3f);
  462. }else{
  463. *q++=0xe0|(c>>12);
  464. *q++=0x80|((c>>6)&0x3f);
  465. *q++=0x80|(c&0x3f);
  466. }
  467. }
  468. *q=0;
  469. return buf;
  470. }
  471. BBArray *bbStringSplit( BBString *str,BBString *sep ){
  472. int i,i2,n;
  473. BBString **p,*bit;
  474. BBArray *bits;
  475. if( sep->length ){
  476. i=0;n=1;
  477. while( (i2=bbStringFind( str,sep,i ))!=-1 ){
  478. ++n;
  479. i=i2+sep->length;
  480. }
  481. bits=bbArrayNew1D( "$",n );
  482. p=(BBString**)BBARRAYDATA( bits,1 );
  483. i=0;
  484. while( n-- ){
  485. i2=bbStringFind( str,sep,i );
  486. if( i2==-1 ) i2=str->length;
  487. bit=bbStringSlice( str,i,i2 );
  488. //BBINCREFS( bit );
  489. *p++=bit;
  490. i=i2+sep->length;
  491. }
  492. return bits;
  493. }
  494. i=0;n=0;
  495. for(;;){
  496. while( i!=str->length && str->buf[i]<33 ) ++i;
  497. if( i++==str->length ) break;
  498. while( i!=str->length && str->buf[i]>32 ) ++i;
  499. ++n;
  500. }
  501. if( !n ) return &bbEmptyArray;
  502. bits=bbArrayNew1D( "$",n );
  503. p=(BBString**)BBARRAYDATA( bits,1 );
  504. i=0;
  505. while( n-- ){
  506. while( str->buf[i]<33 ) ++i;
  507. i2=i++;
  508. while( i!=str->length && str->buf[i]>32 ) ++i;
  509. bit=bbStringSlice( str,i2,i );
  510. //BBINCREFS( bit );
  511. *p++=bit;
  512. }
  513. return bits;
  514. }
  515. BBString *bbStringJoin( BBString *sep,BBArray *bits ){
  516. int i,sz=0;
  517. int n_bits=bits->scales[0];
  518. BBString **p,*str;
  519. BBChar *t;
  520. if( bits==&bbEmptyArray ){
  521. return &bbEmptyString;
  522. }
  523. p=(BBString**)BBARRAYDATA( bits,1 );
  524. for( i=0;i<n_bits;++i ){
  525. BBString *bit=*p++;
  526. sz+=bit->length;
  527. }
  528. sz+=(n_bits-1)*sep->length;
  529. str=bbStringNew( sz );
  530. t=str->buf;
  531. p=(BBString**)BBARRAYDATA( bits,1 );
  532. for( i=0;i<n_bits;++i ){
  533. if( i ){
  534. memcpy( t,sep->buf,sep->length*sizeof(BBChar) );
  535. t+=sep->length;
  536. }
  537. BBString *bit=*p++;
  538. memcpy( t,bit->buf,bit->length*sizeof(BBChar) );
  539. t+=bit->length;
  540. }
  541. return str;
  542. }
  543. #ifndef __ANDROID__
  544. #ifndef __EMSCRIPTEN__
  545. static void mktmp( void *p ){
  546. static AO_t i;
  547. static void *bufs[32];
  548. int n=AO_fetch_and_add1( &i ) & 31;
  549. bbMemFree( bufs[n] );
  550. bufs[n]=p;
  551. }
  552. #else
  553. static void mktmp( void *p ){
  554. static int i;
  555. static void *bufs[32];
  556. int n=++i & 31;
  557. bbMemFree( bufs[n] );
  558. bufs[n]=p;
  559. }
  560. #endif
  561. #else
  562. static void mktmp( void *p ){
  563. static int i;
  564. static void *bufs[32];
  565. int n= __sync_fetch_and_add( &i, 1 ) & 31;
  566. bbMemFree( bufs[n] );
  567. bufs[n]=p;
  568. }
  569. #endif
  570. char *bbTmpCString( BBString *str ){
  571. char *p=bbStringToCString( str );
  572. mktmp( p );
  573. return p;
  574. }
  575. BBChar *bbTmpWString( BBString *str ){
  576. BBChar *p=bbStringToWString( str );
  577. mktmp( p );
  578. return p;
  579. }
  580. char *bbTmpUTF8String( BBString *str ){
  581. char *p=bbStringToUTF8String( str );
  582. mktmp( p );
  583. return p;
  584. }