summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordgp <dgp@users.sourceforge.net>2017-10-03 15:33:52 (GMT)
committerdgp <dgp@users.sourceforge.net>2017-10-03 15:33:52 (GMT)
commit204ff1026e05331da7eee7197dbb64ff1ad6d369 (patch)
tree5bf121877a8b7586b6431483494e6407a035c2f7
parent87d8441c7bf7b2b2de6f80166e4f2fa9dca9da49 (diff)
downloadtcl-204ff1026e05331da7eee7197dbb64ff1ad6d369.zip
tcl-204ff1026e05331da7eee7197dbb64ff1ad6d369.tar.gz
tcl-204ff1026e05331da7eee7197dbb64ff1ad6d369.tar.bz2
Completion of the merge machinery.
-rw-r--r--generic/tclHAMT.c99
1 files changed, 99 insertions, 0 deletions
diff --git a/generic/tclHAMT.c b/generic/tclHAMT.c
index 7415d53..1273726 100644
--- a/generic/tclHAMT.c
+++ b/generic/tclHAMT.c
@@ -955,7 +955,106 @@ ArrayMap AMMergeContents(
ArrayMap one,
ArrayMap two)
{
+ ArrayMap new;
+ int numList, numSubnode;
+ /* If either tree has a particular subnode, the merger must too */
+ size_t amMap = one->amMap | two->amMap;
+
+ /* If only one of two has list child, the merge will too, providing
+ * there's not already a subnode claiming the slot. */
+ size_t kvMap = (one->kvMap ^ two->kvMap) & ~amMap;
+
+ size_t tally;
+ ClientData *src1= one->slot;
+ ClientData *src2 = two->slot;
+ ClientData *dst;
+
+ for (tally = (size_t)1; tally; tally = tally << 1) {
+ if (!(tally & (amMap | kvMap))) {
+ assert ((one->amMap & tally)== 0); /* would be in amMap */
+ assert ((two->amMap & tally)== 0); /* would be in amMap */
+ assert ((one->kvMap & tally) == (two->kvMap & tally));
+
+ /* Remaining case is when both have list child @ tally ... */
+ if (tally & one->kvMap) {
+ if (*src1 == *src2) {
+ /* When hashes same, this will make a merged list in merge. */
+ kvMap = kvMap | tally;
+ } else {
+ /* When hashes differ, this will make a subnode child in merge. */
+ amMap = amMap | tally;
+ }
+ }
+ }
+ if (tally & one->kvMap) {
+ src1++;
+ }
+ if (tally & two->kvMap) {
+ src2++;
+ }
+ }
+
+ /* We now have the maps for the merged node. */
+ numList = NumBits(kvMap);
+ numSubnode = NumBits(amMap);
+ new = AMNew(numList, numSubnode, one->mask, one->id);
+
+ new->kvMap = kvMap;
+ new->amMap = amMap;
+ dst = new->slot;
+
+ /* Copy the hashes */
+ src1 = one->slot;
+ src2 = two->slot;
+ for (tally = (size_t)1; tally; tally = tally << 1) {
+ if (tally & kvMap) {
+ if (tally & one->kvMap) {
+ *dst = *src1++;
+ }
+ if (tally & two->kvMap) {
+ *dst = *src2++;
+ }
+ dst++;
+ }
+ }
+
+ /* Copy/merge the lists */
+ for (tally = (size_t)1; tally; tally = tally << 1) {
+ if (tally & kvMap) {
+ if ((tally & one->kvMap) && (tally & two->kvMap)) {
+ KVList l = KVLMerge(kt, vt, *src1++, *src2++, NULL);
+ KVLClaim(l);
+ *dst++ = l;
+ } else if (tally & one->kvMap) {
+ KVLClaim(*src1);
+ *dst++ = *src1++;
+ } else {
+ assert (tally & two->kvMap);
+ KVLClaim(*src2);
+ *dst++ = *src2++;
+ }
+ }
+ }
+
+ /* Copy/merge the subnodes */
+ for (tally = (size_t)1; tally; tally = tally << 1) {
+ if (tally & amMap) {
+ if ((tally & one->amMap) && (tally & two->amMap)) {
+ ArrayMap am = AMMerge(kt, vt, *src1++, *src2++);
+ AMClaim(am);
+ *dst++ = am;
+ } else if (tally & one->amMap) {
+ AMClaim(*src1);
+ *dst++ = *src1++;
+ } else {
+ assert (tally & two->amMap);
+ AMClaim(*src2);
+ *dst++ = *src2++;
+ }
+ }
+ }
+ return new;
}
/*