PageRenderTime 48ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/lphobos/internal/adi.d

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