PageRenderTime 56ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/runtime/internal/aaA.d

https://bitbucket.org/prokhin_alexey/ldc2/
D | 798 lines | 455 code | 87 blank | 256 comment | 83 complexity | 0cc4c7453786ca7396e4fb2244e43fea MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0
  1. //_ aaA.d
  2. /**
  3. * Part of the D programming language runtime library.
  4. * Implementation of associative arrays.
  5. */
  6. /*
  7. * Copyright (C) 2000-2008 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, subject to the following restrictions:
  17. *
  18. * o The origin of this software must not be misrepresented; you must not
  19. * claim that you wrote the original software. If you use this software
  20. * in a product, an acknowledgment in the product documentation would be
  21. * appreciated but is not required.
  22. * o Altered source versions must be plainly marked as such, and must not
  23. * be misrepresented as being the original software.
  24. * o This notice may not be removed or altered from any source
  25. * distribution.
  26. */
  27. /*
  28. * Modified by Sean Kelly <sean@f4.ca> for use with Tango.
  29. * Modified by Tomas Lindquist Olsen <tomas@famolsen.dk> for use with LDC.
  30. */
  31. private
  32. {
  33. import tango.stdc.stdarg;
  34. import tango.stdc.string;
  35. enum BlkAttr : uint
  36. {
  37. FINALIZE = 0b0000_0001,
  38. NO_SCAN = 0b0000_0010,
  39. NO_MOVE = 0b0000_0100,
  40. ALL_BITS = 0b1111_1111
  41. }
  42. extern (C) void* gc_malloc( size_t sz, uint ba = 0 );
  43. extern (C) void* gc_calloc( size_t sz, uint ba = 0 );
  44. extern (C) void gc_free( void* p );
  45. }
  46. // Auto-rehash and pre-allocate - Dave Fladebo
  47. static size_t[] prime_list = [
  48. 97UL, 389UL,
  49. 1_543UL, 6_151UL,
  50. 24_593UL, 98_317UL,
  51. 393_241UL, 1_572_869UL,
  52. 6_291_469UL, 25_165_843UL,
  53. 100_663_319UL, 402_653_189UL,
  54. 1_610_612_741UL, 4_294_967_291UL,
  55. // 8_589_934_513UL, 17_179_869_143UL
  56. ];
  57. struct aaA
  58. {
  59. aaA *left;
  60. aaA *right;
  61. hash_t hash;
  62. /* key */
  63. /* value */
  64. }
  65. struct BB
  66. {
  67. aaA*[] b;
  68. size_t nodes; // total number of aaA nodes
  69. TypeInfo keyti; // TODO: replace this with TypeInfo_AssociativeArray when available in _aaGet()
  70. }
  71. /* This is the type actually seen by the programmer, although
  72. * it is completely opaque.
  73. */
  74. // LDC doesn't pass structs in registers so no need to wrap it ...
  75. alias BB* AA;
  76. /**********************************
  77. * Align to next pointer boundary, so that
  78. * GC won't be faced with misaligned pointers
  79. * in value.
  80. */
  81. size_t aligntsize(size_t tsize)
  82. {
  83. return (tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1);
  84. }
  85. extern (C):
  86. /*************************************************
  87. * Invariant for aa.
  88. */
  89. /+
  90. void _aaInvAh(aaA*[] aa)
  91. {
  92. for (size_t i = 0; i < aa.length; i++)
  93. {
  94. if (aa[i])
  95. _aaInvAh_x(aa[i]);
  96. }
  97. }
  98. private int _aaCmpAh_x(aaA *e1, aaA *e2)
  99. { int c;
  100. c = e1.hash - e2.hash;
  101. if (c == 0)
  102. {
  103. c = e1.key.length - e2.key.length;
  104. if (c == 0)
  105. c = memcmp((char *)e1.key, (char *)e2.key, e1.key.length);
  106. }
  107. return c;
  108. }
  109. private void _aaInvAh_x(aaA *e)
  110. {
  111. hash_t key_hash;
  112. aaA *e1;
  113. aaA *e2;
  114. key_hash = getHash(e.key);
  115. assert(key_hash == e.hash);
  116. while (1)
  117. { int c;
  118. e1 = e.left;
  119. if (e1)
  120. {
  121. _aaInvAh_x(e1); // ordinary recursion
  122. do
  123. {
  124. c = _aaCmpAh_x(e1, e);
  125. assert(c < 0);
  126. e1 = e1.right;
  127. } while (e1 != null);
  128. }
  129. e2 = e.right;
  130. if (e2)
  131. {
  132. do
  133. {
  134. c = _aaCmpAh_x(e, e2);
  135. assert(c < 0);
  136. e2 = e2.left;
  137. } while (e2 != null);
  138. e = e.right; // tail recursion
  139. }
  140. else
  141. break;
  142. }
  143. }
  144. +/
  145. /****************************************************
  146. * Determine number of entries in associative array.
  147. */
  148. size_t _aaLen(AA aa)
  149. in
  150. {
  151. //printf("_aaLen()+\n");
  152. //_aaInv(aa);
  153. }
  154. out (result)
  155. {
  156. size_t len = 0;
  157. void _aaLen_x(aaA* ex)
  158. {
  159. auto e = ex;
  160. len++;
  161. while (1)
  162. {
  163. if (e.right)
  164. _aaLen_x(e.right);
  165. e = e.left;
  166. if (!e)
  167. break;
  168. len++;
  169. }
  170. }
  171. if (aa)
  172. {
  173. foreach (e; aa.b)
  174. {
  175. if (e)
  176. _aaLen_x(e);
  177. }
  178. }
  179. assert(len == result);
  180. //printf("_aaLen()-\n");
  181. }
  182. body
  183. {
  184. return aa ? aa.nodes : 0;
  185. }
  186. /*************************************************
  187. * Get pointer to value in associative array indexed by key.
  188. * Add entry for key if it is not already there.
  189. */
  190. void* _aaGet(AA* aa_arg, TypeInfo keyti, size_t valuesize, void* pkey)
  191. in
  192. {
  193. assert(aa_arg);
  194. }
  195. out (result)
  196. {
  197. assert(result);
  198. assert(*aa_arg);
  199. assert((*aa_arg).b.length);
  200. //assert(_aaInAh(*aa, key));
  201. }
  202. body
  203. {
  204. //auto pkey = cast(void *)(&valuesize + 1);
  205. size_t i;
  206. aaA *e;
  207. auto keysize = aligntsize(keyti.tsize());
  208. if (!*aa_arg)
  209. *aa_arg = new BB();
  210. auto aa = *aa_arg;
  211. aa.keyti = keyti;
  212. if (!aa.b.length)
  213. {
  214. alias aaA *pa;
  215. auto len = prime_list[0];
  216. aa.b = new pa[len];
  217. }
  218. auto key_hash = keyti.getHash(pkey);
  219. //printf("hash = %d\n", key_hash);
  220. i = key_hash % aa.b.length;
  221. auto pe = &aa.b[i];
  222. while ((e = *pe) !is null)
  223. {
  224. if (key_hash == e.hash)
  225. {
  226. auto c = keyti.compare(pkey, e + 1);
  227. if (c == 0)
  228. goto Lret;
  229. pe = (c < 0) ? &e.left : &e.right;
  230. }
  231. else
  232. pe = (key_hash < e.hash) ? &e.left : &e.right;
  233. }
  234. // Not found, create new elem
  235. //printf("create new one\n");
  236. size_t size = aaA.sizeof + keysize + valuesize;
  237. e = cast(aaA *) gc_calloc(size);
  238. memcpy(e + 1, pkey, keysize);
  239. e.hash = key_hash;
  240. *pe = e;
  241. auto nodes = ++aa.nodes;
  242. //printf("length = %d, nodes = %d\n", (*aa).length, nodes);
  243. if (nodes > aa.b.length * 4)
  244. {
  245. _aaRehash(aa_arg,keyti);
  246. }
  247. Lret:
  248. return cast(void *)(e + 1) + keysize;
  249. }
  250. /*************************************************
  251. * Get pointer to value in associative array indexed by key.
  252. * Returns null if it is not already there.
  253. * Used for both "aa[key]" and "key in aa"
  254. * Returns:
  255. * null not in aa
  256. * !=null in aa, return pointer to value
  257. */
  258. void* _aaIn(AA aa, TypeInfo keyti, void *pkey)
  259. in
  260. {
  261. }
  262. out (result)
  263. {
  264. //assert(result == 0 || result == 1);
  265. }
  266. body
  267. {
  268. if (aa)
  269. {
  270. //auto pkey = cast(void *)(&keyti + 1);
  271. //printf("_aaIn(), .length = %d, .ptr = %x\n", aa.length, cast(uint)aa.ptr);
  272. auto len = aa.b.length;
  273. if (len)
  274. {
  275. auto key_hash = keyti.getHash(pkey);
  276. //printf("hash = %d\n", key_hash);
  277. size_t i = key_hash % len;
  278. auto e = aa.b[i];
  279. while (e !is null)
  280. {
  281. if (key_hash == e.hash)
  282. {
  283. auto c = keyti.compare(pkey, e + 1);
  284. if (c == 0)
  285. return cast(void *)(e + 1) + aligntsize(keyti.tsize());
  286. e = (c < 0) ? e.left : e.right;
  287. }
  288. else
  289. e = (key_hash < e.hash) ? e.left : e.right;
  290. }
  291. }
  292. }
  293. // Not found
  294. return null;
  295. }
  296. /*************************************************
  297. * Delete key entry in aa[].
  298. * If key is not in aa[], do nothing.
  299. */
  300. void _aaDel(AA aa, TypeInfo keyti, void *pkey)
  301. {
  302. //auto pkey = cast(void *)(&keyti + 1);
  303. aaA *e;
  304. if (aa && aa.b.length)
  305. {
  306. auto key_hash = keyti.getHash(pkey);
  307. //printf("hash = %d\n", key_hash);
  308. size_t i = key_hash % aa.b.length;
  309. auto pe = &aa.b[i];
  310. while ((e = *pe) !is null) // null means not found
  311. {
  312. if (key_hash == e.hash)
  313. {
  314. auto c = keyti.compare(pkey, e + 1);
  315. if (c == 0)
  316. {
  317. if (!e.left && !e.right)
  318. {
  319. *pe = null;
  320. }
  321. else if (e.left && !e.right)
  322. {
  323. *pe = e.left;
  324. e.left = null;
  325. }
  326. else if (!e.left && e.right)
  327. {
  328. *pe = e.right;
  329. e.right = null;
  330. }
  331. else
  332. {
  333. *pe = e.left;
  334. e.left = null;
  335. do
  336. pe = &(*pe).right;
  337. while (*pe);
  338. *pe = e.right;
  339. e.right = null;
  340. }
  341. aa.nodes--;
  342. gc_free(e);
  343. break;
  344. }
  345. pe = (c < 0) ? &e.left : &e.right;
  346. }
  347. else
  348. pe = (key_hash < e.hash) ? &e.left : &e.right;
  349. }
  350. }
  351. }
  352. /********************************************
  353. * Produce array of values from aa.
  354. * The actual type is painted on the return value by the frontend
  355. * This means the returned length should be the number of elements
  356. */
  357. void[] _aaValues(AA aa, size_t keysize, size_t valuesize)
  358. in
  359. {
  360. assert(keysize == aligntsize(keysize));
  361. }
  362. body
  363. {
  364. size_t resi;
  365. void[] a;
  366. void _aaValues_x(aaA* e)
  367. {
  368. do
  369. {
  370. memcpy(a.ptr + resi * valuesize,
  371. cast(byte*)e + aaA.sizeof + keysize,
  372. valuesize);
  373. resi++;
  374. if (e.left)
  375. { if (!e.right)
  376. { e = e.left;
  377. continue;
  378. }
  379. _aaValues_x(e.left);
  380. }
  381. e = e.right;
  382. } while (e !is null);
  383. }
  384. if (aa)
  385. {
  386. auto len = _aaLen(aa);
  387. auto ptr = cast(byte*) gc_malloc(len * valuesize,
  388. valuesize < (void*).sizeof ? BlkAttr.NO_SCAN : 0);
  389. a = ptr[0 .. len];
  390. resi = 0;
  391. foreach (e; aa.b)
  392. {
  393. if (e)
  394. _aaValues_x(e);
  395. }
  396. assert(resi == a.length);
  397. }
  398. return a;
  399. }
  400. /********************************************
  401. * Rehash an array.
  402. */
  403. void* _aaRehash(AA* paa, TypeInfo keyti)
  404. in
  405. {
  406. //_aaInvAh(paa);
  407. }
  408. out (result)
  409. {
  410. //_aaInvAh(result);
  411. }
  412. body
  413. {
  414. BB newb;
  415. void _aaRehash_x(aaA* olde)
  416. {
  417. while (1)
  418. {
  419. auto left = olde.left;
  420. auto right = olde.right;
  421. olde.left = null;
  422. olde.right = null;
  423. aaA *e;
  424. //printf("rehash %p\n", olde);
  425. auto key_hash = olde.hash;
  426. size_t i = key_hash % newb.b.length;
  427. auto pe = &newb.b[i];
  428. while ((e = *pe) !is null)
  429. {
  430. //printf("\te = %p, e.left = %p, e.right = %p\n", e, e.left, e.right);
  431. assert(e.left != e);
  432. assert(e.right != e);
  433. if (key_hash == e.hash)
  434. {
  435. auto c = keyti.compare(olde + 1, e + 1);
  436. assert(c != 0);
  437. pe = (c < 0) ? &e.left : &e.right;
  438. }
  439. else
  440. pe = (key_hash < e.hash) ? &e.left : &e.right;
  441. }
  442. *pe = olde;
  443. if (right)
  444. {
  445. if (!left)
  446. { olde = right;
  447. continue;
  448. }
  449. _aaRehash_x(right);
  450. }
  451. if (!left)
  452. break;
  453. olde = left;
  454. }
  455. }
  456. //printf("Rehash\n");
  457. if (*paa)
  458. {
  459. auto aa = *paa;
  460. auto len = _aaLen(aa);
  461. if (len)
  462. { size_t i;
  463. for (i = 0; i < prime_list.length - 1; i++)
  464. {
  465. if (len <= prime_list[i])
  466. break;
  467. }
  468. len = prime_list[i];
  469. newb.b = new aaA*[len];
  470. newb.keyti = keyti;
  471. foreach (e; aa.b)
  472. {
  473. if (e)
  474. _aaRehash_x(e);
  475. }
  476. newb.nodes = (*aa).nodes;
  477. }
  478. **paa = newb;
  479. }
  480. return *paa;
  481. }
  482. /********************************************
  483. * Produce array of N byte keys from aa.
  484. * The actual type is painted on the return value by the frontend
  485. * This means the returned length should be the number of elements
  486. */
  487. void[] _aaKeys(AA aa, size_t keysize)
  488. {
  489. byte[] res;
  490. size_t resi;
  491. void _aaKeys_x(aaA* e)
  492. {
  493. do
  494. {
  495. memcpy(&res[resi * keysize], cast(byte*)(e + 1), keysize);
  496. resi++;
  497. if (e.left)
  498. { if (!e.right)
  499. { e = e.left;
  500. continue;
  501. }
  502. _aaKeys_x(e.left);
  503. }
  504. e = e.right;
  505. } while (e !is null);
  506. }
  507. auto len = _aaLen(aa);
  508. if (!len)
  509. return null;
  510. res = (cast(byte*) gc_malloc(len * keysize,
  511. !(aa.keyti.flags() & 1) ? BlkAttr.NO_SCAN : 0)) [0 .. len * keysize];
  512. resi = 0;
  513. foreach (e; aa.b)
  514. {
  515. if (e)
  516. _aaKeys_x(e);
  517. }
  518. assert(resi == len);
  519. return res.ptr[0 .. len];
  520. }
  521. /**********************************************
  522. * 'apply' for associative arrays - to support foreach
  523. */
  524. // dg is D, but _aaApply() is C
  525. extern (D) typedef int delegate(void *) dg_t;
  526. int _aaApply(AA aa, size_t keysize, dg_t dg)
  527. in
  528. {
  529. assert(aligntsize(keysize) == keysize);
  530. }
  531. body
  532. { int result;
  533. //printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa, keysize, dg);
  534. int treewalker(aaA* e)
  535. { int result;
  536. do
  537. {
  538. //printf("treewalker(e = %p, dg = x%llx)\n", e, dg);
  539. result = dg(cast(void *)(e + 1) + keysize);
  540. if (result)
  541. break;
  542. if (e.right)
  543. { if (!e.left)
  544. {
  545. e = e.right;
  546. continue;
  547. }
  548. result = treewalker(e.right);
  549. if (result)
  550. break;
  551. }
  552. e = e.left;
  553. } while (e);
  554. return result;
  555. }
  556. if (aa)
  557. {
  558. foreach (e; aa.b)
  559. {
  560. if (e)
  561. {
  562. result = treewalker(e);
  563. if (result)
  564. break;
  565. }
  566. }
  567. }
  568. return result;
  569. }
  570. // dg is D, but _aaApply2() is C
  571. extern (D) typedef int delegate(void *, void *) dg2_t;
  572. int _aaApply2(AA aa, size_t keysize, dg2_t dg)
  573. in
  574. {
  575. assert(aligntsize(keysize) == keysize);
  576. }
  577. body
  578. { int result;
  579. //printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa, keysize, dg);
  580. int treewalker(aaA* e)
  581. { int result;
  582. do
  583. {
  584. //printf("treewalker(e = %p, dg = x%llx)\n", e, dg);
  585. result = dg(cast(void *)(e + 1), cast(void *)(e + 1) + keysize);
  586. if (result)
  587. break;
  588. if (e.right)
  589. { if (!e.left)
  590. {
  591. e = e.right;
  592. continue;
  593. }
  594. result = treewalker(e.right);
  595. if (result)
  596. break;
  597. }
  598. e = e.left;
  599. } while (e);
  600. return result;
  601. }
  602. if (aa)
  603. {
  604. foreach (e; aa.b)
  605. {
  606. if (e)
  607. {
  608. result = treewalker(e);
  609. if (result)
  610. break;
  611. }
  612. }
  613. }
  614. return result;
  615. }
  616. int _aaEq(AA aa, AA ab, TypeInfo_AssociativeArray ti)
  617. {
  618. return ti.equals(&aa, &ab);
  619. }
  620. /***********************************
  621. * Construct an associative array of type ti from
  622. * length pairs of key/value pairs.
  623. */
  624. /+
  625. extern (C)
  626. BB* _d_assocarrayliteralT(TypeInfo_AssociativeArray ti, size_t length, ...)
  627. {
  628. auto valuesize = ti.next.tsize(); // value size
  629. auto keyti = ti.key;
  630. auto keysize = keyti.tsize(); // key size
  631. BB* result;
  632. //printf("_d_assocarrayliteralT(keysize = %d, valuesize = %d, length = %d)\n", keysize, valuesize, length);
  633. //printf("tivalue = %.*s\n", ti.next.classinfo.name);
  634. if (length == 0 || valuesize == 0 || keysize == 0)
  635. {
  636. ;
  637. }
  638. else
  639. {
  640. va_list q;
  641. va_start!(size_t)(q, length);
  642. result = new BB();
  643. size_t i;
  644. for (i = 0; i < prime_list.length - 1; i++)
  645. {
  646. if (length <= prime_list[i])
  647. break;
  648. }
  649. auto len = prime_list[i];
  650. result.b = new aaA*[len];
  651. size_t keystacksize = (keysize + int.sizeof - 1) & ~(int.sizeof - 1);
  652. size_t valuestacksize = (valuesize + int.sizeof - 1) & ~(int.sizeof - 1);
  653. size_t keytsize = aligntsize(keysize);
  654. for (size_t j = 0; j < length; j++)
  655. { void* pkey = q;
  656. q += keystacksize;
  657. void* pvalue = q;
  658. q += valuestacksize;
  659. aaA* e;
  660. auto key_hash = keyti.getHash(pkey);
  661. //printf("hash = %d\n", key_hash);
  662. i = key_hash % len;
  663. auto pe = &result.b[i];
  664. while (1)
  665. {
  666. e = *pe;
  667. if (!e)
  668. {
  669. // Not found, create new elem
  670. //printf("create new one\n");
  671. e = cast(aaA *) cast(void*) new void[aaA.sizeof + keytsize + valuesize];
  672. memcpy(e + 1, pkey, keysize);
  673. e.hash = key_hash;
  674. *pe = e;
  675. result.nodes++;
  676. break;
  677. }
  678. if (key_hash == e.hash)
  679. {
  680. auto c = keyti.compare(pkey, e + 1);
  681. if (c == 0)
  682. break;
  683. pe = (c < 0) ? &e.left : &e.right;
  684. }
  685. else
  686. pe = (key_hash < e.hash) ? &e.left : &e.right;
  687. }
  688. memcpy(cast(void *)(e + 1) + keytsize, pvalue, valuesize);
  689. }
  690. va_end(q);
  691. }
  692. return result;
  693. }
  694. +/