diff options
author | dgp <dgp@users.sourceforge.net> | 2017-09-11 00:12:46 (GMT) |
---|---|---|
committer | dgp <dgp@users.sourceforge.net> | 2017-09-11 00:12:46 (GMT) |
commit | 8c790d5b53020202332a522baa60ee59bf657649 (patch) | |
tree | 50dbf3d1c62757175a5d19ea964a410009a948f1 /generic/tclHAMT.c | |
parent | 5f1c3aa0f65ede5613cc06119511889663e32b76 (diff) | |
download | tcl-8c790d5b53020202332a522baa60ee59bf657649.zip tcl-8c790d5b53020202332a522baa60ee59bf657649.tar.gz tcl-8c790d5b53020202332a522baa60ee59bf657649.tar.bz2 |
It compiles! Ship it!
Diffstat (limited to 'generic/tclHAMT.c')
-rw-r--r-- | generic/tclHAMT.c | 284 |
1 files changed, 277 insertions, 7 deletions
diff --git a/generic/tclHAMT.c b/generic/tclHAMT.c index 6f57554..9a139be 100644 --- a/generic/tclHAMT.c +++ b/generic/tclHAMT.c @@ -892,7 +892,271 @@ ArrayMap AMInsert( return NULL; } + +/* + *---------------------------------------------------------------------- + * + * AMRemove -- + * + * Remove the key, value pair containing key from this subset of + * the key/value map, if present. + * + * Results: + * A new revised subset without a pair containing key. + * OR + * NULL, then hashPtr, listPtr have hash and KVList values + * written to them for the single list left. + * + * Side effects: + * If valuePtr is not NULL, write to *valuePtr the + * previous value associated with key in subset + * or NULL if the key was not there before. + *---------------------------------------------------------------------- + */ + +static +ArrayMap AMRemove( + ArrayMap am, + size_t hash, + const TclHAMTKeyType *kt, + ClientData key, + const TclHAMTValueType *vt, + size_t *hashPtr, + KVList *listPtr, + ClientData *valuePtr) +{ + size_t tally; + int numList, numSubnode, loffset, soffset, i; + ArrayMap new, sub; + ClientData *src, *dst; + KVList l; + + if ((am->mask & hash) != am->id) { + /* Hash indicates key is not in this subtree */ + + if (valuePtr) { + *valuePtr = NULL; + } + return am; + } + + /* Hash indicates key should be descendant of am */ + numList = NumBits(am->kvMap); + numSubnode = NumBits(am->amMap); + + tally = 1 << ((hash >> LSB(am->mask + 1)) & branchMask); + if (tally & am->kvMap) { + + /* Hash is consistent with one of our KVList children... */ + loffset = NumBits(am->kvMap & (tally - 1)); + + if (am->slot[loffset] != (ClientData)hash) { + /* ...but does not actually match. Key not here. */ + + if (valuePtr) { + *valuePtr = NULL; + } + return am; + } + + /* Found the right KVList. Remove the pair from it. */ + l = KVLRemove(am->slot[loffset + numList], kt, key, vt, valuePtr); + + if (l == am->slot[loffset + numList]) { + /* list unchanged -> ArrayMap unchanged. */ + return am; + } + + /* Create new ArrayMap with removed KVList */ + + if (l != NULL) { + /* Modified copy of am, list replaced. */ + new = ckalloc(AMN_SIZE(numList, numSubnode)); + + new->claim = 0; + new->mask = am->mask; + new->id = am->id; + new->kvMap = am->kvMap; + new->amMap = am->amMap; + + src = am->slot; + dst = new->slot; + /* Copy all hashes */ + for (i = 0; i < numList; i++) { + *dst++ = *src++; + } + + /* Copy list (except one we're replacing) */ + for (i = 0; i < loffset; i++) { + KVLClaim((KVList) *src); + *dst++ = *src++; + } + src++; + KVLClaim(l); + *dst++ = l; + for (i = loffset + 1; i < numList; i++) { + KVLClaim((KVList) *src); + *dst++ = *src++; + } + + /* Copy all subnodes */ + for (i = 0; i < numSubnode; i++) { + AMClaim((ArrayMap) *src); + *dst++ = *src++; + } + return new; + } + if (numList + numSubnode > 2) { + /* Modified copy of am, list removed. */ + new = ckalloc(AMN_SIZE(numList-1, numSubnode)); + + new->claim = 0; + new->mask = am->mask; + new->id = am->id; + new->kvMap = am->kvMap & ~tally; + new->amMap = am->amMap; + + src = am->slot; + dst = new->slot; + + /* Copy hashes (except one we're deleting) */ + for (i = 0; i < loffset; i++) { + *dst++ = *src++; + } + src++; + for (i = loffset + 1; i < numList; i++) { + *dst++ = *src++; + } + + /* Copy list (except one we're deleting) */ + for (i = 0; i < loffset; i++) { + KVLClaim((KVList) *src); + *dst++ = *src++; + } + src++; + for (i = loffset + 1; i < numList; i++) { + KVLClaim((KVList) *src); + *dst++ = *src++; + } + /* Copy all subnodes */ + for (i = 0; i < numSubnode; i++) { + AMClaim((ArrayMap) *src); + *dst++ = *src++; + } + return new; + } + if (numSubnode) { + /* Removal will leave the subnode. */ + return am->slot[2]; + } else { + /* Removal will leave a list. */ + *hashPtr = (size_t) am->slot[1 - loffset]; + *listPtr = (KVList) am->slot[3 - loffset]; + return NULL; + } + } + if (tally & am->amMap) { + size_t subhash; + + /* Hash is consistent with one of our subnode children... */ + soffset = NumBits(am->amMap & (tally - 1)); + sub = AMRemove((ArrayMap)am->slot[2*numList + soffset], hash, + kt, key, vt, &subhash, &l, valuePtr); + + if (sub) { + /* Modified copy of am, subnode replaced. */ + new = ckalloc(AMN_SIZE(numList, numSubnode)); + + new->claim = 0; + new->mask = am->mask; + new->id = am->id; + new->kvMap = am->kvMap; + new->amMap = am->amMap; + + src = am->slot; + dst = new->slot; + /* Copy all hashes */ + for (i = 0; i < numList; i++) { + *dst++ = *src++; + } + + /* Copy all lists */ + for (i = 0; i < numList; i++) { + KVLClaim((KVList) *src); + *dst++ = *src++; + } + + /* Copy subnodes */ + for (i = 0; i < soffset; i++) { + AMClaim((ArrayMap) *src); + *dst++ = *src++; + } + src++; + AMClaim(sub); + *dst++ = sub; + for (i = soffset + 1; i < numSubnode; i++) { + AMClaim((ArrayMap) *src); + *dst++ = *src++; + } + return new; + } else { + /* Modified copy of am, + list - sub */ + + loffset = NumBits(am->kvMap & (tally - 1)); + + new = ckalloc(AMN_SIZE(numList+1, numSubnode-1)); + new->claim = 0; + new->mask = am->mask; + new->id = am->id; + + new->kvMap = am->kvMap | tally; + new->amMap = am->amMap & ~tally; + + src = am->slot; + dst = new->slot; + /* Copy hashes (up to one we're inserting) */ + for (i = 0; i < loffset; i++) { + *dst++ = *src++; + } + *dst++ = (ClientData) subhash; + for (i = loffset; i < numList; i++) { + *dst++ = *src++; + } + + /* Copy list (except one we're deleting) */ + for (i = 0; i < loffset; i++) { + KVLClaim((KVList) *src); + *dst++ = *src++; + } + KVLClaim(l); + *dst++ = l; + for (i = loffset; i < numList; i++) { + KVLClaim((KVList) *src); + *dst++ = *src++; + } + + /* Copy subnodes and add the new one */ + for (i = 0; i < soffset; i++) { + AMClaim((ArrayMap) *src); + *dst++ = *src++; + } + src++; + for (i = soffset + 1; i < numSubnode; i++) { + AMClaim((ArrayMap) *src); + *dst++ = *src++; + } + + return new; + } + } + + /* Key is not here. */ + if (valuePtr) { + *valuePtr = NULL; + } + return am; +} /* Finally, the top level struct that puts all the pieces together */ @@ -1202,6 +1466,7 @@ TclHAMTRemove( ClientData *valuePtr) { HAMT *new, *hPtr = hamt; + size_t hash; KVList l; ArrayMap am; @@ -1247,18 +1512,23 @@ TclHAMTRemove( return hamt; } -/* TODO TODO TODO * - * Sort out case where AM drops to singleton. */ /* Map has a tree. Remove from it. */ new = ckalloc(sizeof(HAMT)); new->claim = 0; new->kt = hPtr->kt; new->vt = hPtr->vt; - new->kvl = NULL; - am = AMRemove(hPtr->x.am, ..., /* hashPtr */ NULL, - hPtr->kt, key, hPtr->vt, value, valuePtr); - AMClaim(am); - new->x.am = am; + + am = AMRemove(hPtr->x.am, Hash(hPtr, key), hPtr->kt, key, + hPtr->vt, &hash, &l, valuePtr); + if (am) { + new->kvl = NULL; + AMClaim(am); + new->x.am = am; + } else { + KVLClaim(l); + new->kvl = l; + new->x.hash = hash; + } return new; } |