PageRenderTime 1742ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/d/phobos/internal/aaA.d

https://bitbucket.org/goshawk/gdc/
D | 864 lines | 550 code | 101 blank | 213 comment | 102 complexity | 2a603efb62b2a944aef9feca2b599e7a MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0
  1. //_ aaA.d
  2. /**
  3. * Part of the D programming language runtime library.
  4. * Implementation of associative arrays.
  5. */
  6. /*
  7. *
  8. * Copyright: Copyright Digital Mars 2000 - 2010.
  9. * License: <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
  10. * Authors: Walter Bright, Sean Kelly
  11. *
  12. * Distributed under the Boost Software License, Version 1.0.
  13. * (See accompanying file LICENSE_1_0.txt or copy at
  14. * http://www.boost.org/LICENSE_1_0.txt)
  15. */
  16. /* NOTE: This file has been patched from the original DMD distribution to
  17. work with the GDC compiler.
  18. Modified by David Friedman, September 2004
  19. */
  20. //import std.stdio;
  21. import std.c.stdarg;
  22. import std.c.stdio;
  23. import std.c.stdlib;
  24. import std.c.string;
  25. import std.string;
  26. import std.gc;
  27. import std.outofmemory;
  28. // Auto-rehash and pre-allocate - Dave Fladebo
  29. static size_t[] prime_list = [
  30. 97UL, 389UL,
  31. 1_543UL, 6_151UL,
  32. 24_593UL, 98_317UL,
  33. 393_241UL, 1_572_869UL,
  34. 6_291_469UL, 25_165_843UL,
  35. 100_663_319UL, 402_653_189UL,
  36. 1_610_612_741UL, 4_294_967_291UL,
  37. // 8_589_934_513UL, 17_179_869_143UL
  38. ];
  39. /* This is the type of the return value for dynamic arrays.
  40. * It should be a type that is returned in registers.
  41. * Although DMD will return types of Array in registers,
  42. * gcc will not, so we instead use a 'long'.
  43. */
  44. alias void[] ArrayRet_t;
  45. struct Array
  46. {
  47. size_t length;
  48. void* ptr;
  49. }
  50. struct aaA
  51. {
  52. aaA *next;
  53. hash_t hash;
  54. /* key */
  55. /* value */
  56. }
  57. struct BB
  58. {
  59. aaA*[] b;
  60. size_t nodes; // total number of aaA nodes
  61. aaA*[5] binit; // initial value of b[]
  62. }
  63. /* This is the type actually seen by the programmer, although
  64. * it is completely opaque.
  65. */
  66. struct AA
  67. {
  68. BB* a;
  69. }
  70. /**********************************
  71. * Align to next pointer boundary, so that
  72. * GC won't be faced with misaligned pointers
  73. * in value.
  74. */
  75. size_t aligntsize(size_t tsize)
  76. {
  77. version (X86_64)
  78. // Size of key needed to align value on 16 bytes
  79. return (tsize + 15) & ~(15);
  80. else
  81. return (tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1);
  82. }
  83. extern (C):
  84. /*************************************************
  85. * Invariant for aa.
  86. */
  87. /+
  88. void _aaInvAh(aaA*[] aa)
  89. {
  90. for (size_t i = 0; i < aa.length; i++)
  91. {
  92. if (aa[i])
  93. _aaInvAh_x(aa[i]);
  94. }
  95. }
  96. private int _aaCmpAh_x(aaA *e1, aaA *e2)
  97. { int c;
  98. c = e1.hash - e2.hash;
  99. if (c == 0)
  100. {
  101. c = e1.key.length - e2.key.length;
  102. if (c == 0)
  103. c = memcmp((char *)e1.key, (char *)e2.key, e1.key.length);
  104. }
  105. return c;
  106. }
  107. private void _aaInvAh_x(aaA *e)
  108. {
  109. hash_t key_hash;
  110. aaA *e1;
  111. aaA *e2;
  112. key_hash = getHash(e.key);
  113. assert(key_hash == e.hash);
  114. while (1)
  115. { int c;
  116. e1 = e.left;
  117. if (e1)
  118. {
  119. _aaInvAh_x(e1); // ordinary recursion
  120. do
  121. {
  122. c = _aaCmpAh_x(e1, e);
  123. assert(c < 0);
  124. e1 = e1.right;
  125. } while (e1 != null);
  126. }
  127. e2 = e.right;
  128. if (e2)
  129. {
  130. do
  131. {
  132. c = _aaCmpAh_x(e, e2);
  133. assert(c < 0);
  134. e2 = e2.left;
  135. } while (e2 != null);
  136. e = e.right; // tail recursion
  137. }
  138. else
  139. break;
  140. }
  141. }
  142. +/
  143. /****************************************************
  144. * Determine number of entries in associative array.
  145. */
  146. size_t _aaLen(AA aa)
  147. in
  148. {
  149. //printf("_aaLen()+\n");
  150. //_aaInv(aa);
  151. }
  152. out (result)
  153. {
  154. size_t len = 0;
  155. if (aa.a)
  156. {
  157. foreach (e; aa.a.b)
  158. {
  159. while (e)
  160. { len++;
  161. e = e.next;
  162. }
  163. }
  164. }
  165. assert(len == result);
  166. //printf("_aaLen()-\n");
  167. }
  168. body
  169. {
  170. return aa.a ? aa.a.nodes : 0;
  171. }
  172. /*************************************************
  173. * Get pointer to value in associative array indexed by key.
  174. * Add entry for key if it is not already there.
  175. */
  176. /* Retained for binary backwards compatibility
  177. */
  178. void* _aaGet(AA* aa, TypeInfo keyti, size_t valuesize, ...)
  179. {
  180. return _aaGetp(aa, keyti, valuesize, cast(void *)(&valuesize + 1));
  181. }
  182. void* _aaGetp(AA* aa, TypeInfo keyti, size_t valuesize, void* pkey)
  183. in
  184. {
  185. assert(aa);
  186. }
  187. out (result)
  188. {
  189. assert(result);
  190. assert(aa.a);
  191. assert(aa.a.b.length);
  192. //assert(_aaInAh(*aa.a, key));
  193. }
  194. body
  195. {
  196. //printf("aaGet()\n");
  197. size_t i;
  198. aaA* e;
  199. auto keysize = aligntsize(keyti.tsize());
  200. //printf("keysize = %d\n", keysize);
  201. if (!aa.a)
  202. { aa.a = new BB();
  203. aa.a.b = aa.a.binit;
  204. }
  205. auto key_hash = keyti.getHash(pkey);
  206. //printf("hash = %d\n", key_hash);
  207. i = key_hash % aa.a.b.length;
  208. auto pe = &aa.a.b[i];
  209. while ((e = *pe) !is null)
  210. {
  211. if (key_hash == e.hash)
  212. {
  213. auto c = keyti.compare(pkey, e + 1);
  214. if (c == 0)
  215. goto Lret;
  216. }
  217. pe = &e.next;
  218. }
  219. // Not found, create new elem
  220. //printf("create new one\n");
  221. std.gc.disable();
  222. e = cast(aaA *) cast(void*) new void[aaA.sizeof + keysize + valuesize];
  223. std.gc.enable();
  224. memcpy(e + 1, pkey, keysize);
  225. e.hash = key_hash;
  226. *pe = e;
  227. auto nodes = ++aa.a.nodes;
  228. //printf("length = %d, nodes = %d\n", (*aa.a).length, nodes);
  229. if (nodes > aa.a.b.length * 4)
  230. {
  231. _aaRehash(aa,keyti);
  232. }
  233. Lret:
  234. return cast(void *)(e + 1) + keysize;
  235. }
  236. /*************************************************
  237. * Get pointer to value in associative array indexed by key.
  238. * Returns null if it is not already there.
  239. */
  240. void* _aaGetRvalue(AA aa, TypeInfo keyti, size_t valuesize, ...)
  241. {
  242. return _aaGetRvaluep(aa, keyti, valuesize, cast(void *)(&valuesize + 1));
  243. }
  244. void* _aaGetRvaluep(AA aa, TypeInfo keyti, size_t valuesize, void *pkey)
  245. {
  246. //printf("_aaGetRvalue(valuesize = %u)\n", valuesize);
  247. if (!aa.a)
  248. return null;
  249. auto keysize = aligntsize(keyti.tsize());
  250. auto len = aa.a.b.length;
  251. if (len)
  252. {
  253. auto key_hash = keyti.getHash(pkey);
  254. //printf("hash = %d\n", key_hash);
  255. size_t i = key_hash % len;
  256. auto e = aa.a.b[i];
  257. while (e !is null)
  258. {
  259. if (key_hash == e.hash)
  260. {
  261. auto c = keyti.compare(pkey, e + 1);
  262. if (c == 0)
  263. return cast(void *)(e + 1) + keysize;
  264. }
  265. e = e.next;
  266. }
  267. }
  268. return null; // not found, caller will throw exception
  269. }
  270. /*************************************************
  271. * Determine if key is in aa.
  272. * Returns:
  273. * null not in aa
  274. * !=null in aa, return pointer to value
  275. */
  276. void* _aaIn(AA aa, TypeInfo keyti, ...)
  277. {
  278. return _aaInp(aa, keyti, cast(void *)(&keyti + 1));
  279. }
  280. void* _aaInp(AA aa, TypeInfo keyti, void* pkey)
  281. in
  282. {
  283. }
  284. out (result)
  285. {
  286. //assert(result == 0 || result == 1);
  287. }
  288. body
  289. {
  290. if (aa.a)
  291. {
  292. //printf("_aaIn(), .length = %d, .ptr = %x\n", aa.a.length, cast(uint)aa.a.ptr);
  293. auto len = aa.a.b.length;
  294. if (len)
  295. {
  296. auto key_hash = keyti.getHash(pkey);
  297. //printf("hash = %d\n", key_hash);
  298. size_t i = key_hash % len;
  299. auto e = aa.a.b[i];
  300. while (e !is null)
  301. {
  302. if (key_hash == e.hash)
  303. {
  304. auto c = keyti.compare(pkey, e + 1);
  305. if (c == 0)
  306. return cast(void *)(e + 1) + aligntsize(keyti.tsize());
  307. }
  308. e = e.next;
  309. }
  310. }
  311. }
  312. // Not found
  313. return null;
  314. }
  315. /*************************************************
  316. * Delete key entry in aa[].
  317. * If key is not in aa[], do nothing.
  318. */
  319. void _aaDel(AA aa, TypeInfo keyti, ...)
  320. {
  321. return _aaDelp(aa, keyti, cast(void *)(&keyti + 1));
  322. }
  323. void _aaDelp(AA aa, TypeInfo keyti, void* pkey)
  324. {
  325. aaA* e;
  326. if (aa.a && aa.a.b.length)
  327. {
  328. auto key_hash = keyti.getHash(pkey);
  329. //printf("hash = %d\n", key_hash);
  330. size_t i = key_hash % aa.a.b.length;
  331. auto pe = &aa.a.b[i];
  332. while ((e = *pe) !is null) // null means not found
  333. {
  334. if (key_hash == e.hash)
  335. {
  336. auto c = keyti.compare(pkey, e + 1);
  337. if (c == 0)
  338. {
  339. *pe = e.next;
  340. aa.a.nodes--;
  341. // Should notify GC that e can be free'd now
  342. delete e;
  343. break;
  344. }
  345. }
  346. pe = &e.next;
  347. }
  348. }
  349. }
  350. /********************************************
  351. * Produce array of values from aa.
  352. */
  353. ArrayRet_t _aaValues(AA aa, size_t keysize, size_t valuesize)
  354. in
  355. {
  356. assert(keysize == aligntsize(keysize));
  357. }
  358. body
  359. {
  360. size_t resi;
  361. Array a;
  362. if (aa.a)
  363. {
  364. a.length = _aaLen(aa);
  365. a.ptr = (new void[a.length * valuesize]).ptr;
  366. resi = 0;
  367. foreach (e; aa.a.b)
  368. {
  369. while (e)
  370. {
  371. memcpy(a.ptr + resi * valuesize,
  372. cast(byte*)e + aaA.sizeof + keysize,
  373. valuesize);
  374. resi++;
  375. e = e.next;
  376. }
  377. }
  378. assert(resi == a.length);
  379. }
  380. return *cast(ArrayRet_t*)(&a);
  381. }
  382. /********************************************
  383. * Rehash an array.
  384. */
  385. void* _aaRehash(AA* paa, TypeInfo keyti)
  386. in
  387. {
  388. //_aaInvAh(paa);
  389. }
  390. out (result)
  391. {
  392. //_aaInvAh(result);
  393. }
  394. body
  395. {
  396. //printf("Rehash\n");
  397. if (paa.a)
  398. {
  399. BB newb;
  400. auto aa = paa.a;
  401. auto len = _aaLen(*paa);
  402. if (len)
  403. { size_t i;
  404. for (i = 0; i < prime_list.length - 1; i++)
  405. {
  406. if (len <= prime_list[i])
  407. break;
  408. }
  409. //printf("rehash %d x%x\n", len, len);
  410. len = prime_list[i];
  411. newb.b = new aaA*[len];
  412. foreach (e; aa.b)
  413. {
  414. while (e)
  415. { auto enext = e.next;
  416. auto j = e.hash % len;
  417. e.next = newb.b[j];
  418. newb.b[j] = e;
  419. e = enext;
  420. }
  421. }
  422. if (aa.b.ptr == aa.binit.ptr)
  423. aa.binit[] = null;
  424. else
  425. delete aa.b;
  426. newb.nodes = aa.nodes;
  427. }
  428. *paa.a = newb;
  429. }
  430. return (*paa).a;
  431. }
  432. /********************************************
  433. * Produce array of N byte keys from aa.
  434. */
  435. ArrayRet_t _aaKeys(AA aa, size_t keysize)
  436. {
  437. auto len = _aaLen(aa);
  438. if (!len)
  439. return null;
  440. auto res = cast(byte[])new void[len * keysize];
  441. size_t resi = 0;
  442. foreach (e; aa.a.b)
  443. {
  444. while (e)
  445. {
  446. memcpy(&res[resi * keysize], cast(byte*)(e + 1), keysize);
  447. resi++;
  448. e = e.next;
  449. }
  450. }
  451. assert(resi == len);
  452. Array a;
  453. a.length = len;
  454. a.ptr = res.ptr;
  455. return *cast(ArrayRet_t*)(&a);
  456. }
  457. /**********************************************
  458. * 'apply' for associative arrays - to support foreach
  459. */
  460. // dg is D, but _aaApply() is C
  461. extern (D) typedef int delegate(void *) dg_t;
  462. int _aaApply(AA aa, size_t keysize, dg_t dg)
  463. in
  464. {
  465. assert(aligntsize(keysize) == keysize);
  466. }
  467. body
  468. { int result;
  469. //printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa.a, keysize, dg);
  470. if (aa.a)
  471. {
  472. Loop:
  473. foreach (e; aa.a.b)
  474. {
  475. while (e)
  476. {
  477. result = dg(cast(void *)(e + 1) + keysize);
  478. if (result)
  479. break Loop;
  480. e = e.next;
  481. }
  482. }
  483. }
  484. return result;
  485. }
  486. // dg is D, but _aaApply2() is C
  487. extern (D) typedef int delegate(void *, void *) dg2_t;
  488. int _aaApply2(AA aa, size_t keysize, dg2_t dg)
  489. in
  490. {
  491. assert(aligntsize(keysize) == keysize);
  492. }
  493. body
  494. { int result;
  495. //printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa.a, keysize, dg);
  496. if (aa.a)
  497. {
  498. Loop:
  499. foreach (e; aa.a.b)
  500. {
  501. while (e)
  502. {
  503. result = dg(cast(void *)(e + 1), cast(void *)(e + 1) + keysize);
  504. if (result)
  505. break Loop;
  506. e = e.next;
  507. }
  508. }
  509. }
  510. return result;
  511. }
  512. /***********************************
  513. * Construct an associative array of type ti from
  514. * length pairs of key/value pairs.
  515. */
  516. version (GNU) {} else
  517. extern (C)
  518. BB* _d_assocarrayliteralT(TypeInfo_AssociativeArray ti, size_t length, ...)
  519. {
  520. auto valuesize = ti.next.tsize(); // value size
  521. auto keyti = ti.key;
  522. auto keysize = keyti.tsize(); // key size
  523. BB* result;
  524. //printf("_d_assocarrayliteralT(keysize = %d, valuesize = %d, length = %d)\n", keysize, valuesize, length);
  525. //printf("tivalue = %.*s\n", ti.next.classinfo.name);
  526. if (length == 0 || valuesize == 0 || keysize == 0)
  527. {
  528. ;
  529. }
  530. else
  531. {
  532. va_list q;
  533. version (X86_64) va_start(q, __va_argsave); else va_start(q, length);
  534. result = new BB();
  535. size_t i;
  536. for (i = 0; i < prime_list.length - 1; i++)
  537. {
  538. if (length <= prime_list[i])
  539. break;
  540. }
  541. auto len = prime_list[i];
  542. result.b = new aaA*[len];
  543. size_t keystacksize = (keysize + size_t.sizeof - 1) & ~(size_t.sizeof - 1);
  544. size_t valuestacksize = (valuesize + size_t.sizeof - 1) & ~(size_t.sizeof - 1);
  545. size_t keytsize = aligntsize(keysize);
  546. aaA* ne;
  547. for (size_t j = 0; j < length; j++)
  548. {
  549. if (!ne)
  550. ne = cast(aaA *) cast(void*) new void[aaA.sizeof + keytsize + valuesize];
  551. void* pkey = ne + 1;
  552. va_arg(q, keyti, pkey);
  553. //q += keystacksize;
  554. aaA* e;
  555. auto key_hash = keyti.getHash(pkey);
  556. //printf("hash = %d\n", key_hash);
  557. i = key_hash % len;
  558. auto pe = &result.b[i];
  559. while (1)
  560. {
  561. e = *pe;
  562. if (!e)
  563. {
  564. // Not found, create new elem
  565. //printf("create new one\n");
  566. //e = cast(aaA *) cast(void*) new void[aaA.sizeof + keytsize + valuesize];
  567. //memcpy(e + 1, pkey, keysize);
  568. e = ne;
  569. e.hash = key_hash;
  570. *pe = e;
  571. ne = null;
  572. result.nodes++;
  573. break;
  574. }
  575. if (key_hash == e.hash)
  576. {
  577. auto c = keyti.compare(pkey, e + 1);
  578. if (c == 0)
  579. break;
  580. }
  581. pe = &e.next;
  582. }
  583. //memcpy(cast(void *)(e + 1) + keytsize, q, valuesize);
  584. //q += valuestacksize;
  585. version (X86)
  586. va_arg(q, ti.next, cast(void *)(e + 1) + keytsize);
  587. else
  588. {
  589. TypeInfo tis = cast(TypeInfo_StaticArray)ti.next;
  590. if (tis)
  591. {
  592. /* Special handling for static arrays because we put their contents
  593. * on the stack, which isn't the ABI for D1 static arrays.
  594. * (It is for D2, though.)
  595. * The code here is ripped from std.c.stdarg, and initializes
  596. * assuming the data is always passed on the stack.
  597. */
  598. __va_list* vap = cast(__va_list*)q;
  599. auto talign = tis.talign();
  600. auto tsize = tis.tsize();
  601. void* parmn = cast(void *)(e + 1) + keytsize;
  602. auto p = cast(void*)((cast(size_t)vap.stack_args + talign - 1) & ~(talign - 1));
  603. vap.stack_args = cast(void*)(cast(size_t)p + ((tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1)));
  604. parmn[0..tsize] = p[0..tsize];
  605. }
  606. else
  607. {
  608. va_arg(q, ti.next, cast(void *)(e + 1) + keytsize);
  609. }
  610. }
  611. }
  612. if (ne)
  613. delete ne;
  614. va_end(q);
  615. }
  616. return result;
  617. }
  618. extern (C)
  619. BB* _d_assocarrayliteralTp(TypeInfo_AssociativeArray ti, void[] keys, void[] values)
  620. {
  621. auto valueti = ti.next;
  622. auto valuesize = valueti.tsize(); // value size
  623. auto keyti = ti.key;
  624. auto keysize = keyti.tsize(); // key size
  625. auto length = keys.length;
  626. BB* result;
  627. //printf("_d_assocarrayliteralTp(keysize = %d, valuesize = %d, length = %d)\n", keysize, valuesize, length);
  628. //printf("tivalue = %.*s\n", ti.next.classinfo.name);
  629. assert(length == values.length);
  630. if (length == 0 || valuesize == 0 || keysize == 0)
  631. {
  632. ;
  633. }
  634. else
  635. {
  636. result = new BB();
  637. size_t i;
  638. for (i = 0; i < prime_list.length - 1; i++)
  639. {
  640. if (length <= prime_list[i])
  641. break;
  642. }
  643. auto len = prime_list[i];
  644. result.b = new aaA*[len];
  645. size_t keytsize = aligntsize(keysize);
  646. for (size_t j = 0; j < length; j++)
  647. { auto pkey = keys.ptr + j * keysize;
  648. auto pvalue = values.ptr + j * valuesize;
  649. aaA* e;
  650. auto key_hash = keyti.getHash(pkey);
  651. //printf("hash = %d\n", key_hash);
  652. i = key_hash % len;
  653. auto pe = &result.b[i];
  654. while (1)
  655. {
  656. e = *pe;
  657. if (!e)
  658. {
  659. // Not found, create new elem
  660. //printf("create new one\n");
  661. e = cast(aaA *) cast(void*) new void[aaA.sizeof + keytsize + valuesize];
  662. memcpy(e + 1, pkey, keysize);
  663. e.hash = key_hash;
  664. *pe = e;
  665. result.nodes++;
  666. break;
  667. }
  668. if (key_hash == e.hash)
  669. {
  670. auto c = keyti.compare(pkey, e + 1);
  671. if (c == 0)
  672. break;
  673. }
  674. pe = &e.next;
  675. }
  676. memcpy(cast(void *)(e + 1) + keytsize, pvalue, valuesize);
  677. }
  678. }
  679. return result;
  680. }
  681. /***********************************
  682. * Compare AA contents for equality.
  683. * Returns:
  684. * 1 equal
  685. * 0 not equal
  686. */
  687. int _aaEqual(TypeInfo_AssociativeArray ti, AA e1, AA e2)
  688. {
  689. //printf("_aaEqual()\n");
  690. //printf("keyti = %.*s\n", ti.key.classinfo.name);
  691. //printf("valueti = %.*s\n", ti.next.classinfo.name);
  692. if (e1.a is e2.a)
  693. return 1;
  694. size_t len = _aaLen(e1);
  695. if (len != _aaLen(e2))
  696. return 0;
  697. /* Algorithm: Visit each key/value pair in e1. If that key doesn't exist
  698. * in e2, or if the value in e1 doesn't match the one in e2, the arrays
  699. * are not equal, and exit early.
  700. * After all pairs are checked, the arrays must be equal.
  701. */
  702. auto keyti = ti.key;
  703. auto valueti = ti.next;
  704. auto keysize = aligntsize(keyti.tsize());
  705. auto len2 = e2.a.b.length;
  706. int _aaKeys_x(aaA* e)
  707. {
  708. do
  709. {
  710. auto pkey = cast(void*)(e + 1);
  711. auto pvalue = pkey + keysize;
  712. //printf("key = %d, value = %g\n", *cast(int*)pkey, *cast(double*)pvalue);
  713. // We have key/value for e1. See if they exist in e2
  714. auto key_hash = keyti.getHash(pkey);
  715. //printf("hash = %d\n", key_hash);
  716. auto i = key_hash % len2;
  717. auto f = e2.a.b[i];
  718. while (1)
  719. {
  720. //printf("f is %p\n", f);
  721. if (f is null)
  722. return 0; // key not found, so AA's are not equal
  723. if (key_hash == f.hash)
  724. {
  725. //printf("hash equals\n");
  726. auto c = keyti.compare(pkey, f + 1);
  727. if (c == 0)
  728. { // Found key in e2. Compare values
  729. //printf("key equals\n");
  730. auto pvalue2 = cast(void *)(f + 1) + keysize;
  731. if (valueti.equals(pvalue, pvalue2))
  732. {
  733. //printf("value equals\n");
  734. break;
  735. }
  736. else
  737. return 0; // values don't match, so AA's are not equal
  738. }
  739. }
  740. f = f.next;
  741. }
  742. // Look at next entry in e1
  743. e = e.next;
  744. } while (e !is null);
  745. return 1; // this subtree matches
  746. }
  747. foreach (e; e1.a.b)
  748. {
  749. if (e)
  750. { if (_aaKeys_x(e) == 0)
  751. return 0;
  752. }
  753. }
  754. return 1; // equal
  755. }