PageRenderTime 32ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/runtime/internal/adi.d

https://bitbucket.org/prokhin_alexey/ldc2/
D | 610 lines | 413 code | 107 blank | 90 comment | 66 complexity | eaacc32659bfc8c4d1a6f8bce894a693 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0
  1. //_ adi.d
  2. /**
  3. * Part of the D programming language runtime library.
  4. * Dynamic array property support routines
  5. */
  6. /*
  7. * Copyright (C) 2000-2006 by Digital Mars, www.digitalmars.com
  8. * Written by Walter Bright
  9. *
  10. * This software is provided 'as-is', without any express or implied
  11. * warranty. In no event will the authors be held liable for any damages
  12. * arising from the use of this software.
  13. *
  14. * Permission is granted to anyone to use this software for any purpose,
  15. * including commercial applications, and to alter it and redistribute it
  16. * freely, in both source and binary form, subject to the following
  17. * restrictions:
  18. *
  19. * o The origin of this software must not be misrepresented; you must not
  20. * claim that you wrote the original software. If you use this software
  21. * in a product, an acknowledgment in the product documentation would be
  22. * appreciated but is not required.
  23. * o Altered source versions must be plainly marked as such, and must not
  24. * be misrepresented as being the original software.
  25. * o This notice may not be removed or altered from any source
  26. * distribution.
  27. */
  28. /*
  29. * Modified by Sean Kelly <sean@f4.ca> for use with Tango.
  30. */
  31. //debug=adi; // uncomment to turn on debugging printf's
  32. private
  33. {
  34. import tango.stdc.string;
  35. import tango.stdc.stdlib;
  36. import util.utf;
  37. enum BlkAttr : uint
  38. {
  39. FINALIZE = 0b0000_0001,
  40. NO_SCAN = 0b0000_0010,
  41. NO_MOVE = 0b0000_0100,
  42. ALL_BITS = 0b1111_1111
  43. }
  44. extern (C) void* gc_malloc( size_t sz, uint ba = 0 );
  45. extern (C) void* gc_calloc( size_t sz, uint ba = 0 );
  46. extern (C) void gc_free( void* p );
  47. }
  48. /**********************************************
  49. * Reverse array of chars.
  50. * Handled separately because embedded multibyte encodings should not be
  51. * reversed.
  52. */
  53. extern (C) char[] _adReverseChar(char[] a)
  54. {
  55. bool hadErrors = false;
  56. if (a.length > 1)
  57. {
  58. char[6] tmp;
  59. char[6] tmplo;
  60. char* lo = a.ptr;
  61. char* hi = &a[length - 1];
  62. while (lo < hi)
  63. { auto clo = *lo;
  64. auto chi = *hi;
  65. debug(adi) printf("lo = %d, hi = %d\n", lo, hi);
  66. if (clo <= 0x7F && chi <= 0x7F)
  67. {
  68. debug(adi) printf("\tascii\n");
  69. *lo = chi;
  70. *hi = clo;
  71. lo++;
  72. hi--;
  73. continue;
  74. }
  75. uint stridelo = UTF8stride[clo];
  76. if (stridelo > 6) { // invalid UTF-8 0xFF
  77. stridelo = 1;
  78. hadErrors=true;
  79. }
  80. uint stridehi = 1;
  81. while ((chi & 0xC0) == 0x80 && hi >= lo)
  82. {
  83. chi = *--hi;
  84. stridehi++;
  85. }
  86. if (lo >= hi) {
  87. if (lo > hi) {
  88. hadErrors = true;
  89. }
  90. break;
  91. }
  92. if (stridehi > 6) {
  93. hadErrors = true;
  94. stridehi = 6;
  95. }
  96. debug(adi) printf("\tstridelo = %d, stridehi = %d\n", stridelo, stridehi);
  97. if (stridelo == stridehi)
  98. {
  99. memcpy(tmp.ptr, lo, stridelo);
  100. memcpy(lo, hi, stridelo);
  101. memcpy(hi, tmp.ptr, stridelo);
  102. lo += stridelo;
  103. hi--;
  104. continue;
  105. }
  106. /* Shift the whole array. This is woefully inefficient
  107. */
  108. memcpy(tmp.ptr, hi, stridehi);
  109. memcpy(tmplo.ptr, lo, stridelo);
  110. memmove(lo + stridehi, lo + stridelo , cast(size_t)(hi - lo) - stridelo);
  111. memcpy(lo, tmp.ptr, stridehi);
  112. memcpy(hi + stridehi - stridelo, tmplo.ptr, stridelo);
  113. lo += stridehi;
  114. hi = hi - 1 + (stridehi - stridelo);
  115. }
  116. }
  117. if (hadErrors)
  118. throw new Exception("invalid UTF-8 sequence",__FILE__,__LINE__);
  119. return a;
  120. }
  121. unittest
  122. {
  123. char[] a = "abcd"c;
  124. char[] r = a.dup.reverse;
  125. //writefln(r);
  126. assert(r == "dcba");
  127. a = "a\u1235\u1234c";
  128. //writefln(a);
  129. r = a.dup.reverse;
  130. //writefln(r);
  131. assert(r == "c\u1234\u1235a");
  132. a = "ab\u1234c";
  133. //writefln(a);
  134. r = a.dup.reverse;
  135. //writefln(r);
  136. assert(r == "c\u1234ba");
  137. a = "\u3026\u2021\u3061\n";
  138. r = a.dup.reverse;
  139. assert(r == "\n\u3061\u2021\u3026");
  140. }
  141. /**********************************************
  142. * Reverse array of wchars.
  143. * Handled separately because embedded multiword encodings should not be
  144. * reversed.
  145. */
  146. extern (C) wchar[] _adReverseWchar(wchar[] a)
  147. {
  148. bool hadErrors = false;
  149. if (a.length > 1)
  150. {
  151. wchar[2] tmp;
  152. wchar* lo = a.ptr;
  153. wchar* hi = &a[length - 1];
  154. while (lo < hi)
  155. { auto clo = *lo;
  156. auto chi = *hi;
  157. if ((clo < 0xD800 || clo > 0xDFFF) &&
  158. (chi < 0xD800 || chi > 0xDFFF))
  159. {
  160. *lo = chi;
  161. *hi = clo;
  162. lo++;
  163. hi--;
  164. continue;
  165. }
  166. int stridelo = 1 + (clo >= 0xD800 && clo <= 0xDBFF);
  167. int stridehi = 1;
  168. if (chi >= 0xDC00 && chi <= 0xDFFF)
  169. {
  170. chi = *--hi;
  171. stridehi++;
  172. }
  173. if (lo >= hi) {
  174. if (lo > hi) {
  175. hadErrors = true;
  176. }
  177. break;
  178. }
  179. if (stridelo == stridehi)
  180. { int stmp;
  181. assert(stridelo == 2);
  182. assert(stmp.sizeof == 2 * (*lo).sizeof);
  183. stmp = *cast(int*)lo;
  184. *cast(int*)lo = *cast(int*)hi;
  185. *cast(int*)hi = stmp;
  186. lo += stridelo;
  187. hi--;
  188. continue;
  189. }
  190. /* Shift the whole array. This is woefully inefficient
  191. */
  192. memcpy(tmp.ptr, hi, stridehi * wchar.sizeof);
  193. memcpy(hi + stridehi - stridelo, lo, stridelo * wchar.sizeof);
  194. memmove(lo + stridehi, lo + stridelo , (hi - (lo + stridelo)) * wchar.sizeof);
  195. memcpy(lo, tmp.ptr, stridehi * wchar.sizeof);
  196. lo += stridehi;
  197. hi = hi - 1 + (stridehi - stridelo);
  198. }
  199. }
  200. if (hadErrors)
  201. throw new Exception("invalid UTF-8 sequence",__FILE__,__LINE__);
  202. return a;
  203. }
  204. unittest
  205. {
  206. wchar[] a = "abcd";
  207. wchar[] r;
  208. r = a.dup.reverse;
  209. assert(r == "dcba");
  210. a = "a\U00012356\U00012346c";
  211. r = a.dup.reverse;
  212. assert(r == "c\U00012346\U00012356a");
  213. a = "ab\U00012345c";
  214. r = a.dup.reverse;
  215. assert(r == "c\U00012345ba");
  216. }
  217. /**********************************************
  218. * Support for array.reverse property.
  219. * The actual type is painted on the return value by the frontend
  220. * Given and returned length are number of elements
  221. */
  222. extern (C) void[] _adReverse(void[] a, size_t szelem)
  223. out (result)
  224. {
  225. assert(result.ptr is a.ptr);
  226. }
  227. body
  228. {
  229. if (a.length >= 2)
  230. {
  231. byte* tmp;
  232. byte[16] buffer;
  233. void* lo = a.ptr;
  234. void* hi = a.ptr + (a.length - 1) * szelem;
  235. tmp = buffer.ptr;
  236. if (szelem > 16)
  237. {
  238. //version (Win32)
  239. //tmp = cast(byte*) alloca(szelem);
  240. //else
  241. tmp = cast(byte*) gc_malloc(szelem);
  242. }
  243. for (; lo < hi; lo += szelem, hi -= szelem)
  244. {
  245. memcpy(tmp, lo, szelem);
  246. memcpy(lo, hi, szelem);
  247. memcpy(hi, tmp, szelem);
  248. }
  249. version (Win32)
  250. {
  251. }
  252. else
  253. {
  254. //if (szelem > 16)
  255. // BUG: bad code is generate for delete pointer, tries
  256. // to call delclass.
  257. //gc_free(tmp);
  258. }
  259. }
  260. return a.ptr[0 .. a.length];
  261. }
  262. unittest
  263. {
  264. debug(adi) printf("array.reverse.unittest\n");
  265. int[] a = new int[5];
  266. int[] b;
  267. size_t i;
  268. for (i = 0; i < 5; i++)
  269. a[i] = i;
  270. b = a.reverse;
  271. assert(b is a);
  272. for (i = 0; i < 5; i++)
  273. assert(a[i] == 4 - i);
  274. struct X20
  275. { // More than 16 bytes in size
  276. int a;
  277. int b, c, d, e;
  278. }
  279. X20[] c = new X20[5];
  280. X20[] d;
  281. for (i = 0; i < 5; i++)
  282. { c[i].a = i;
  283. c[i].e = 10;
  284. }
  285. d = c.reverse;
  286. assert(d is c);
  287. for (i = 0; i < 5; i++)
  288. {
  289. assert(c[i].a == 4 - i);
  290. assert(c[i].e == 10);
  291. }
  292. }
  293. /**********************************************
  294. * Sort array of chars.
  295. */
  296. extern (C) char[] _adSortChar(char[] a)
  297. {
  298. if (a.length > 1)
  299. {
  300. dchar[] da = toUTF32(a);
  301. da.sort;
  302. size_t i = 0;
  303. foreach (dchar d; da)
  304. { char[4] buf;
  305. auto t = toUTF8(buf, d);
  306. a[i .. i + t.length] = t[];
  307. i += t.length;
  308. }
  309. delete da;
  310. }
  311. return a;
  312. }
  313. /**********************************************
  314. * Sort array of wchars.
  315. */
  316. extern (C) wchar[] _adSortWchar(wchar[] a)
  317. {
  318. if (a.length > 1)
  319. {
  320. dchar[] da = toUTF32(a);
  321. da.sort;
  322. size_t i = 0;
  323. foreach (dchar d; da)
  324. { wchar[2] buf;
  325. auto t = toUTF16(buf, d);
  326. a[i .. i + t.length] = t[];
  327. i += t.length;
  328. }
  329. delete da;
  330. }
  331. return a;
  332. }
  333. /***************************************
  334. * Support for array equality test.
  335. * The actual type is painted on the return value by the frontend
  336. * Given lengths are number of elements
  337. */
  338. extern (C) int _adEq(void[] a1, void[] a2, TypeInfo ti)
  339. {
  340. debug(adi) printf("_adEq(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
  341. if (a1.length != a2.length)
  342. return 0; // not equal
  343. else if (a1.ptr == a2.ptr)
  344. return 1; // equal
  345. // let typeinfo decide
  346. return ti.equals(&a1, &a2);
  347. }
  348. unittest
  349. {
  350. debug(adi) printf("array.Eq unittest\n");
  351. char[] a = "hello"c;
  352. assert(a != "hel");
  353. assert(a != "helloo");
  354. assert(a != "betty");
  355. assert(a == "hello");
  356. assert(a != "hxxxx");
  357. }
  358. /***************************************
  359. * Support for array compare test.
  360. * The actual type is painted on the return value by the frontend
  361. * Given lengths are number of elements
  362. */
  363. extern (C) int _adCmp(void[] a1, void[] a2, TypeInfo ti)
  364. {
  365. debug(adi) printf("adCmp()\n");
  366. if (a1.ptr == a2.ptr &&
  367. a1.length == a2.length)
  368. return 0;
  369. auto len = a1.length;
  370. if (a2.length < len)
  371. len = a2.length;
  372. // let typeinfo decide
  373. return ti.compare(&a1, &a2);
  374. }
  375. unittest
  376. {
  377. debug(adi) printf("array.Cmp unittest\n");
  378. char[] a = "hello"c;
  379. assert(a > "hel");
  380. assert(a >= "hel");
  381. assert(a < "helloo");
  382. assert(a <= "helloo");
  383. assert(a > "betty");
  384. assert(a >= "betty");
  385. assert(a == "hello");
  386. assert(a <= "hello");
  387. assert(a >= "hello");
  388. }
  389. /***************************************
  390. * Support for array compare test.
  391. * The actual type is painted on the return value by the frontend
  392. * Given lengths are number of elements
  393. */
  394. extern (C) int _adCmpChar(void[] a1, void[] a2)
  395. {
  396. version(D_InlineAsm_X86)
  397. {
  398. //version = Asm86;
  399. }
  400. version (Asm86)
  401. {
  402. asm
  403. { naked ;
  404. push EDI ;
  405. push ESI ;
  406. mov ESI,a1+4[4+ESP] ;
  407. mov EDI,a2+4[4+ESP] ;
  408. mov ECX,a1[4+ESP] ;
  409. mov EDX,a2[4+ESP] ;
  410. cmp ECX,EDX ;
  411. jb GotLength ;
  412. mov ECX,EDX ;
  413. GotLength:
  414. cmp ECX,4 ;
  415. jb DoBytes ;
  416. // Do alignment if neither is dword aligned
  417. test ESI,3 ;
  418. jz Aligned ;
  419. test EDI,3 ;
  420. jz Aligned ;
  421. DoAlign:
  422. mov AL,[ESI] ; //align ESI to dword bounds
  423. mov DL,[EDI] ;
  424. cmp AL,DL ;
  425. jnz Unequal ;
  426. inc ESI ;
  427. inc EDI ;
  428. test ESI,3 ;
  429. lea ECX,[ECX-1] ;
  430. jnz DoAlign ;
  431. Aligned:
  432. mov EAX,ECX ;
  433. // do multiple of 4 bytes at a time
  434. shr ECX,2 ;
  435. jz TryOdd ;
  436. repe ;
  437. cmpsd ;
  438. jnz UnequalQuad ;
  439. TryOdd:
  440. mov ECX,EAX ;
  441. DoBytes:
  442. // if still equal and not end of string, do up to 3 bytes slightly
  443. // slower.
  444. and ECX,3 ;
  445. jz Equal ;
  446. repe ;
  447. cmpsb ;
  448. jnz Unequal ;
  449. Equal:
  450. mov EAX,a1[4+ESP] ;
  451. mov EDX,a2[4+ESP] ;
  452. sub EAX,EDX ;
  453. pop ESI ;
  454. pop EDI ;
  455. ret ;
  456. UnequalQuad:
  457. mov EDX,[EDI-4] ;
  458. mov EAX,[ESI-4] ;
  459. cmp AL,DL ;
  460. jnz Unequal ;
  461. cmp AH,DH ;
  462. jnz Unequal ;
  463. shr EAX,16 ;
  464. shr EDX,16 ;
  465. cmp AL,DL ;
  466. jnz Unequal ;
  467. cmp AH,DH ;
  468. Unequal:
  469. sbb EAX,EAX ;
  470. pop ESI ;
  471. or EAX,1 ;
  472. pop EDI ;
  473. ret ;
  474. }
  475. }
  476. else
  477. {
  478. int len;
  479. int c;
  480. debug(adi) printf("adCmpChar()\n");
  481. len = cast(int)a1.length;
  482. if (a2.length < len)
  483. len = cast(int)a2.length;
  484. c = memcmp(cast(char *)a1.ptr, cast(char *)a2.ptr, len);
  485. if (!c)
  486. c = cast(int)a1.length - cast(int)a2.length;
  487. return c;
  488. }
  489. }
  490. unittest
  491. {
  492. debug(adi) printf("array.CmpChar unittest\n");
  493. char[] a = "hello"c;
  494. assert(a > "hel");
  495. assert(a >= "hel");
  496. assert(a < "helloo");
  497. assert(a <= "helloo");
  498. assert(a > "betty");
  499. assert(a >= "betty");
  500. assert(a == "hello");
  501. assert(a <= "hello");
  502. assert(a >= "hello");
  503. }