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

/lphobos/internal/aaA.d

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