PageRenderTime 29ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/d/phobos/internal/adi.d

https://bitbucket.org/goshawk/gdc/
D | 831 lines | 581 code | 135 blank | 115 comment | 103 complexity | af18aebdaf5aec77c12d8eb5dede9ff2 MD5 | raw file
Possible License(s): GPL-2.0, 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. /* NOTE: This file has been patched from the original DMD distribution to
  29. work with the GDC compiler.
  30. Modified by David Friedman, April 2005
  31. */
  32. //debug=adi; // uncomment to turn on debugging printf's
  33. import std.stdio;
  34. import std.c.stdio;
  35. import std.c.stdlib;
  36. import std.c.string;
  37. import std.string;
  38. import std.outofmemory;
  39. import std.utf;
  40. struct Array
  41. {
  42. size_t length;
  43. void* ptr;
  44. }
  45. /**********************************************
  46. * Reverse array of chars.
  47. * Handled separately because embedded multibyte encodings should not be
  48. * reversed.
  49. */
  50. extern (C) char[] _adReverseChar(char[] a)
  51. {
  52. if (a.length > 1)
  53. {
  54. char[6] tmp;
  55. char[6] tmplo;
  56. char* lo = a.ptr;
  57. char* hi = &a[length - 1];
  58. while (lo < hi)
  59. { auto clo = *lo;
  60. auto chi = *hi;
  61. //printf("lo = %d, hi = %d\n", lo, hi);
  62. if (clo <= 0x7F && chi <= 0x7F)
  63. {
  64. //printf("\tascii\n");
  65. *lo = chi;
  66. *hi = clo;
  67. lo++;
  68. hi--;
  69. continue;
  70. }
  71. uint stridelo = std.utf.UTF8stride[clo];
  72. uint stridehi = 1;
  73. while ((chi & 0xC0) == 0x80)
  74. {
  75. chi = *--hi;
  76. stridehi++;
  77. assert(hi >= lo);
  78. }
  79. if (lo == hi)
  80. break;
  81. //printf("\tstridelo = %d, stridehi = %d\n", stridelo, stridehi);
  82. if (stridelo == stridehi)
  83. {
  84. memcpy(tmp.ptr, lo, stridelo);
  85. memcpy(lo, hi, stridelo);
  86. memcpy(hi, tmp.ptr, stridelo);
  87. lo += stridelo;
  88. hi--;
  89. continue;
  90. }
  91. /* Shift the whole array. This is woefully inefficient
  92. */
  93. memcpy(tmp.ptr, hi, stridehi);
  94. memcpy(tmplo.ptr, lo, stridelo);
  95. memmove(lo + stridehi, lo + stridelo , cast(size_t)((hi - lo) - stridelo));
  96. memcpy(lo, tmp.ptr, stridehi);
  97. memcpy(hi + stridehi - stridelo, tmplo.ptr, stridelo);
  98. lo += stridehi;
  99. hi = hi - 1 + cast(int)(stridehi - stridelo);
  100. }
  101. }
  102. return a;
  103. }
  104. unittest
  105. {
  106. string a = "abcd";
  107. string r;
  108. r = a.dup.reverse;
  109. //writefln(r);
  110. assert(r == "dcba");
  111. a = "a\u1235\u1234c";
  112. //writefln(a);
  113. r = a.dup.reverse;
  114. //writefln(r);
  115. assert(r == "c\u1234\u1235a");
  116. a = "ab\u1234c";
  117. //writefln(a);
  118. r = a.dup.reverse;
  119. //writefln(r);
  120. assert(r == "c\u1234ba");
  121. a = "\u3026\u2021\u3061\n";
  122. r = a.dup.reverse;
  123. assert(r == "\n\u3061\u2021\u3026");
  124. }
  125. /**********************************************
  126. * Reverse array of wchars.
  127. * Handled separately because embedded multiword encodings should not be
  128. * reversed.
  129. */
  130. extern (C) wchar[] _adReverseWchar(wchar[] a)
  131. {
  132. //printf("adReverseWchar(%d %p)\n", a.length, a.ptr);
  133. if (a.length > 1)
  134. {
  135. wchar[2] tmp;
  136. wchar* lo = a.ptr;
  137. wchar* hi = &a[length - 1];
  138. while (lo < hi)
  139. { auto clo = *lo;
  140. auto chi = *hi;
  141. if ((clo < 0xD800 || clo > 0xDFFF) &&
  142. (chi < 0xD800 || chi > 0xDFFF))
  143. {
  144. *lo = chi;
  145. *hi = clo;
  146. lo++;
  147. hi--;
  148. continue;
  149. }
  150. int stridelo = 1 + (clo >= 0xD800 && clo <= 0xDBFF);
  151. int stridehi = 1;
  152. if (chi >= 0xDC00 && chi <= 0xDFFF)
  153. {
  154. chi = *--hi;
  155. stridehi++;
  156. assert(hi >= lo);
  157. }
  158. if (lo == hi)
  159. break;
  160. if (stridelo == stridehi)
  161. { int stmp;
  162. assert(stridelo == 2);
  163. assert(stmp.sizeof == 2 * (*lo).sizeof);
  164. stmp = *cast(int*)lo;
  165. *cast(int*)lo = *cast(int*)hi;
  166. *cast(int*)hi = stmp;
  167. lo += stridelo;
  168. hi--;
  169. continue;
  170. }
  171. /* Shift the whole array. This is woefully inefficient
  172. */
  173. memcpy(tmp.ptr, hi, stridehi * wchar.sizeof);
  174. memcpy(hi + stridehi - stridelo, lo, stridelo * wchar.sizeof);
  175. memmove(lo + stridehi, lo + stridelo , (hi - (lo + stridelo)) * wchar.sizeof);
  176. memcpy(lo, tmp.ptr, stridehi * wchar.sizeof);
  177. lo += stridehi;
  178. hi = hi - 1 + (stridehi - stridelo);
  179. }
  180. }
  181. return *cast(wchar[]*)(&a);
  182. }
  183. unittest
  184. {
  185. wstring a = "abcd";
  186. wstring r;
  187. r = a.dup.reverse;
  188. assert(r == "dcba");
  189. a = "a\U00012356\U00012346c";
  190. r = a.dup.reverse;
  191. assert(r == "c\U00012346\U00012356a");
  192. a = "ab\U00012345c";
  193. r = a.dup.reverse;
  194. assert(r == "c\U00012345ba");
  195. }
  196. // %% Had to move _adCmpChar to the beginning of the file
  197. // due to a extern/static symbol conflict on darwin...
  198. /***************************************
  199. * Support for array compare test.
  200. */
  201. extern (C) int _adCmpChar(Array a1, Array a2)
  202. {
  203. version (D_InlineAsm_X86)
  204. {
  205. asm
  206. { naked ;
  207. push EDI ;
  208. push ESI ;
  209. mov ESI,a1+4[4+ESP] ;
  210. mov EDI,a2+4[4+ESP] ;
  211. mov ECX,a1[4+ESP] ;
  212. mov EDX,a2[4+ESP] ;
  213. cmp ECX,EDX ;
  214. jb GotLength ;
  215. mov ECX,EDX ;
  216. GotLength:
  217. cmp ECX,4 ;
  218. jb DoBytes ;
  219. // Do alignment if neither is dword aligned
  220. test ESI,3 ;
  221. jz Aligned ;
  222. test EDI,3 ;
  223. jz Aligned ;
  224. DoAlign:
  225. mov AL,[ESI] ; //align ESI to dword bounds
  226. mov DL,[EDI] ;
  227. cmp AL,DL ;
  228. jnz Unequal ;
  229. inc ESI ;
  230. inc EDI ;
  231. test ESI,3 ;
  232. lea ECX,[ECX-1] ;
  233. jnz DoAlign ;
  234. Aligned:
  235. mov EAX,ECX ;
  236. // do multiple of 4 bytes at a time
  237. shr ECX,2 ;
  238. jz TryOdd ;
  239. repe ;
  240. cmpsd ;
  241. jnz UnequalQuad ;
  242. TryOdd:
  243. mov ECX,EAX ;
  244. DoBytes:
  245. // if still equal and not end of string, do up to 3 bytes slightly
  246. // slower.
  247. and ECX,3 ;
  248. jz Equal ;
  249. repe ;
  250. cmpsb ;
  251. jnz Unequal ;
  252. Equal:
  253. mov EAX,a1[4+ESP] ;
  254. mov EDX,a2[4+ESP] ;
  255. sub EAX,EDX ;
  256. pop ESI ;
  257. pop EDI ;
  258. ret ;
  259. UnequalQuad:
  260. mov EDX,[EDI-4] ;
  261. mov EAX,[ESI-4] ;
  262. cmp AL,DL ;
  263. jnz Unequal ;
  264. cmp AH,DH ;
  265. jnz Unequal ;
  266. shr EAX,16 ;
  267. shr EDX,16 ;
  268. cmp AL,DL ;
  269. jnz Unequal ;
  270. cmp AH,DH ;
  271. Unequal:
  272. sbb EAX,EAX ;
  273. pop ESI ;
  274. or EAX,1 ;
  275. pop EDI ;
  276. ret ;
  277. }
  278. }
  279. else
  280. {
  281. int c;
  282. //printf("adCmpChar()\n");
  283. size_t len = a1.length;
  284. if (a2.length < len)
  285. len = a2.length;
  286. c = std.c.string.memcmp(cast(char *)a1.ptr, cast(char *)a2.ptr, len);
  287. if (!c)
  288. c = cast(int)a1.length - cast(int)a2.length;
  289. return c;
  290. }
  291. }
  292. unittest
  293. {
  294. debug(adi) printf("array.CmpChar unittest\n");
  295. string a = "hello";
  296. assert(a > "hel");
  297. assert(a >= "hel");
  298. assert(a < "helloo");
  299. assert(a <= "helloo");
  300. assert(a > "betty");
  301. assert(a >= "betty");
  302. assert(a == "hello");
  303. assert(a <= "hello");
  304. assert(a >= "hello");
  305. }
  306. /**********************************************
  307. * Support for array.reverse property.
  308. */
  309. extern (C) void[] _adReverse(Array a, size_t szelem)
  310. out (result)
  311. {
  312. assert(result is *cast(void[]*)(&a));
  313. }
  314. body
  315. {
  316. if (a.length >= 2)
  317. {
  318. byte* tmp;
  319. byte[16] buffer;
  320. void* lo = a.ptr;
  321. void* hi = a.ptr + (a.length - 1) * szelem;
  322. tmp = buffer.ptr;
  323. if (szelem > 16)
  324. {
  325. //version (Win32)
  326. tmp = cast(byte*) alloca(szelem);
  327. //else
  328. //tmp = new byte[szelem];
  329. }
  330. for (; lo < hi; lo += szelem, hi -= szelem)
  331. {
  332. memcpy(tmp, lo, szelem);
  333. memcpy(lo, hi, szelem);
  334. memcpy(hi, tmp, szelem);
  335. }
  336. version (Win32)
  337. {
  338. }
  339. else
  340. {
  341. //if (szelem > 16)
  342. // BUG: bad code is generate for delete pointer, tries
  343. // to call delclass.
  344. //delete tmp;
  345. }
  346. }
  347. return *cast(void[]*)(&a);
  348. }
  349. unittest
  350. {
  351. debug(adi) printf("array.reverse.unittest\n");
  352. int[] a = new int[5];
  353. int[] b;
  354. size_t i;
  355. for (i = 0; i < 5; i++)
  356. a[i] = cast(int)i;
  357. b = a.reverse;
  358. assert(b is a);
  359. for (i = 0; i < 5; i++)
  360. assert(a[i] == 4 - i);
  361. struct X20
  362. { // More than 16 bytes in size
  363. int a;
  364. int b, c, d, e;
  365. }
  366. X20[] c = new X20[5];
  367. X20[] d;
  368. for (i = 0; i < 5; i++)
  369. { c[i].a = cast(int)i;
  370. c[i].e = 10;
  371. }
  372. d = c.reverse;
  373. assert(d is c);
  374. for (i = 0; i < 5; i++)
  375. {
  376. assert(c[i].a == 4 - i);
  377. assert(c[i].e == 10);
  378. }
  379. }
  380. /**********************************************
  381. * Support for array.reverse property for bit[].
  382. */
  383. version (none)
  384. {
  385. extern (C) bit[] _adReverseBit(bit[] a)
  386. out (result)
  387. {
  388. assert(result is a);
  389. }
  390. body
  391. {
  392. if (a.length >= 2)
  393. {
  394. bit t;
  395. int lo, hi;
  396. lo = 0;
  397. hi = a.length - 1;
  398. for (; lo < hi; lo++, hi--)
  399. {
  400. t = a[lo];
  401. a[lo] = a[hi];
  402. a[hi] = t;
  403. }
  404. }
  405. return a;
  406. }
  407. unittest
  408. {
  409. debug(adi) printf("array.reverse_Bit[].unittest\n");
  410. bit[] b;
  411. b = new bit[5];
  412. static bit[5] data = [1,0,1,1,0];
  413. int i;
  414. b[] = data[];
  415. b.reverse;
  416. for (i = 0; i < 5; i++)
  417. {
  418. assert(b[i] == data[4 - i]);
  419. }
  420. }
  421. }
  422. /**********************************************
  423. * Sort array of chars.
  424. */
  425. extern (C) char[] _adSortChar(char[] a)
  426. {
  427. if (a.length > 1)
  428. {
  429. dstring da = toUTF32(a);
  430. da.sort;
  431. size_t i = 0;
  432. foreach (dchar d; da)
  433. { char[4] buf;
  434. string t = toUTF8(buf, d);
  435. a[i .. i + t.length] = t[];
  436. i += t.length;
  437. }
  438. delete da;
  439. }
  440. return *cast(char[]*)(&a);
  441. }
  442. /**********************************************
  443. * Sort array of wchars.
  444. */
  445. extern (C) wchar[] _adSortWchar(wchar[] a)
  446. {
  447. if (a.length > 1)
  448. {
  449. dstring da = toUTF32(a);
  450. da.sort;
  451. size_t i = 0;
  452. foreach (dchar d; da)
  453. { wchar[2] buf;
  454. wstring t = toUTF16(buf, d);
  455. a[i .. i + t.length] = t[];
  456. i += t.length;
  457. }
  458. delete da;
  459. }
  460. return *cast(wchar[]*)(&a);
  461. }
  462. /**********************************************
  463. * Support for array.sort property for bit[].
  464. */
  465. version (none)
  466. {
  467. extern (C) bit[] _adSortBit(bit[] a)
  468. out (result)
  469. {
  470. assert(result is a);
  471. }
  472. body
  473. {
  474. if (a.length >= 2)
  475. {
  476. size_t lo, hi;
  477. lo = 0;
  478. hi = a.length - 1;
  479. while (1)
  480. {
  481. while (1)
  482. {
  483. if (lo >= hi)
  484. goto Ldone;
  485. if (a[lo] == true)
  486. break;
  487. lo++;
  488. }
  489. while (1)
  490. {
  491. if (lo >= hi)
  492. goto Ldone;
  493. if (a[hi] == false)
  494. break;
  495. hi--;
  496. }
  497. a[lo] = false;
  498. a[hi] = true;
  499. lo++;
  500. hi--;
  501. }
  502. Ldone:
  503. ;
  504. }
  505. return a;
  506. }
  507. unittest
  508. {
  509. debug(adi) printf("array.sort_Bit[].unittest\n");
  510. }
  511. }
  512. /***************************************
  513. * Support for array equality test.
  514. * Returns:
  515. * 1 equal
  516. * 0 not equal
  517. */
  518. extern (C) int _adEq(Array a1, Array a2, TypeInfo ti)
  519. {
  520. //printf("_adEq(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
  521. if (a1.length != a2.length)
  522. return 0; // not equal
  523. auto sz = ti.tsize();
  524. auto p1 = a1.ptr;
  525. auto p2 = a2.ptr;
  526. /+
  527. for (int i = 0; i < a1.length; i++)
  528. {
  529. printf("%4x %4x\n", (cast(short*)p1)[i], (cast(short*)p2)[i]);
  530. }
  531. +/
  532. if (sz == 1)
  533. // We should really have a ti.isPOD() check for this
  534. return (memcmp(p1, p2, a1.length) == 0);
  535. for (size_t i = 0; i < a1.length; i++)
  536. {
  537. if (!ti.equals(p1 + i * sz, p2 + i * sz))
  538. return 0; // not equal
  539. }
  540. return 1; // equal
  541. }
  542. extern (C) int _adEq2(Array a1, Array a2, TypeInfo ti)
  543. {
  544. //printf("_adEq2(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
  545. if (a1.length != a2.length)
  546. return 0; // not equal
  547. if (!ti.equals(&a1, &a2))
  548. return 0;
  549. return 1;
  550. }
  551. unittest
  552. {
  553. debug(adi) printf("array.Eq unittest\n");
  554. string a = "hello";
  555. assert(a != "hel");
  556. assert(a != "helloo");
  557. assert(a != "betty");
  558. assert(a == "hello");
  559. assert(a != "hxxxx");
  560. }
  561. /***************************************
  562. * Support for array equality test for bit arrays.
  563. */
  564. version (none)
  565. {
  566. extern (C) int _adEqBit(Array a1, Array a2)
  567. { size_t i;
  568. if (a1.length != a2.length)
  569. return 0; // not equal
  570. auto p1 = cast(byte*)a1.ptr;
  571. auto p2 = cast(byte*)a2.ptr;
  572. auto n = a1.length / 8;
  573. for (i = 0; i < n; i++)
  574. {
  575. if (p1[i] != p2[i])
  576. return 0; // not equal
  577. }
  578. ubyte mask;
  579. n = a1.length & 7;
  580. mask = cast(ubyte)((1 << n) - 1);
  581. //printf("i = %d, n = %d, mask = %x, %x, %x\n", i, n, mask, p1[i], p2[i]);
  582. return (mask == 0) || (p1[i] & mask) == (p2[i] & mask);
  583. }
  584. unittest
  585. {
  586. debug(adi) printf("array.EqBit unittest\n");
  587. static bit[] a = [1,0,1,0,1];
  588. static bit[] b = [1,0,1];
  589. static bit[] c = [1,0,1,0,1,0,1];
  590. static bit[] d = [1,0,1,1,1];
  591. static bit[] e = [1,0,1,0,1];
  592. assert(a != b);
  593. assert(a != c);
  594. assert(a != d);
  595. assert(a == e);
  596. }
  597. }
  598. /***************************************
  599. * Support for array compare test.
  600. */
  601. extern (C) int _adCmp(Array a1, Array a2, TypeInfo ti)
  602. {
  603. //printf("adCmp()\n");
  604. auto len = a1.length;
  605. if (a2.length < len)
  606. len = a2.length;
  607. auto sz = ti.tsize();
  608. void *p1 = a1.ptr;
  609. void *p2 = a2.ptr;
  610. if (sz == 1)
  611. { // We should really have a ti.isPOD() check for this
  612. auto c = memcmp(p1, p2, len);
  613. if (c)
  614. return c;
  615. }
  616. else
  617. {
  618. for (size_t i = 0; i < len; i++)
  619. {
  620. auto c = ti.compare(p1 + i * sz, p2 + i * sz);
  621. if (c)
  622. return c;
  623. }
  624. }
  625. if (a1.length == a2.length)
  626. return 0;
  627. return (a1.length > a2.length) ? 1 : -1;
  628. }
  629. extern (C) int _adCmp2(Array a1, Array a2, TypeInfo ti)
  630. {
  631. //printf("_adCmp2(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
  632. return ti.compare(&a1, &a2);
  633. }
  634. unittest
  635. {
  636. debug(adi) printf("array.Cmp unittest\n");
  637. string a = "hello";
  638. assert(a > "hel");
  639. assert(a >= "hel");
  640. assert(a < "helloo");
  641. assert(a <= "helloo");
  642. assert(a > "betty");
  643. assert(a >= "betty");
  644. assert(a == "hello");
  645. assert(a <= "hello");
  646. assert(a >= "hello");
  647. }
  648. /***************************************
  649. * Support for array compare test.
  650. */
  651. version (none)
  652. {
  653. extern (C) int _adCmpBit(Array a1, Array a2)
  654. {
  655. int len;
  656. uint i;
  657. len = a1.length;
  658. if (a2.length < len)
  659. len = a2.length;
  660. ubyte *p1 = cast(ubyte*)a1.ptr;
  661. ubyte *p2 = cast(ubyte*)a2.ptr;
  662. uint n = len / 8;
  663. for (i = 0; i < n; i++)
  664. {
  665. if (p1[i] != p2[i])
  666. break; // not equal
  667. }
  668. for (uint j = i * 8; j < len; j++)
  669. { ubyte mask = cast(ubyte)(1 << j);
  670. int c;
  671. c = cast(int)(p1[i] & mask) - cast(int)(p2[i] & mask);
  672. if (c)
  673. return c;
  674. }
  675. return cast(int)a1.length - cast(int)a2.length;
  676. }
  677. unittest
  678. {
  679. debug(adi) printf("array.CmpBit unittest\n");
  680. static bit[] a = [1,0,1,0,1];
  681. static bit[] b = [1,0,1];
  682. static bit[] c = [1,0,1,0,1,0,1];
  683. static bit[] d = [1,0,1,1,1];
  684. static bit[] e = [1,0,1,0,1];
  685. assert(a > b);
  686. assert(a >= b);
  687. assert(a < c);
  688. assert(a <= c);
  689. assert(a < d);
  690. assert(a <= d);
  691. assert(a == e);
  692. assert(a <= e);
  693. assert(a >= e);
  694. }
  695. }