private void Compact(CharVector kx, TernaryTree map, char p) { int k; if (p == 0) { return; } if (m_sc[p] == 0xFFFF) { k = map.Find(m_kv.Array, m_lo[p]); if (k < 0) { k = kx.Alloc(StrLen(m_kv.Array, m_lo[p]) + 1); StrCpy(kx.Array, k, m_kv.Array, m_lo[p]); map.Insert(kx.Array, k, (char)k); } m_lo[p] = (char)k; } else { Compact(kx, map, m_lo[p]); if (m_sc[p] != 0) { Compact(kx, map, m_eq[p]); } Compact(kx, map, m_hi[p]); } }
/// <summary> /// Each node stores a character (splitchar) which is part of some key(s). In a /// compressed branch (one that only contain a single string key) the trailer /// of the key which is not already in nodes is stored externally in the kv /// array. As items are inserted, key substrings decrease. Some substrings may /// completely disappear when the whole branch is totally decompressed. The /// tree is traversed to find the key substrings actually used. In addition, /// duplicate substrings are removed using a map (implemented with a /// TernaryTree!). /// /// </summary> public virtual void TrimToSize() { // first balance the tree for best performance Balance(); // redimension the node arrays RedimNodeArrays(m_freenode); // ok, compact kv array CharVector kx = new CharVector(); kx.Alloc(1); TernaryTree map = new TernaryTree(); Compact(kx, map, m_root); m_kv = kx; m_kv.TrimToSize(); }
/// <summary> /// The actual insertion function, recursive version. /// </summary> private char Insert(char p, char[] key, int start, char val) { int len = StrLen(key, start); if (p == 0) { // this means there is no branch, this node will start a new branch. // Instead of doing that, we store the key somewhere else and create // only one node with a pointer to the key p = m_freenode++; m_eq[p] = val; // holds data m_length++; m_hi[p] = (char)0; if (len > 0) { m_sc[p] = (char)0xFFFF; // indicates branch is compressed m_lo[p] = (char)m_kv.Alloc(len + 1); // use 'lo' to hold pointer to key StrCpy(m_kv.Array, m_lo[p], key, start); } else { m_sc[p] = (char)0; m_lo[p] = (char)0; } return(p); } if (m_sc[p] == 0xFFFF) { // branch is compressed: need to decompress // this will generate garbage in the external key array // but we can do some garbage collection later char pp = m_freenode++; m_lo[pp] = m_lo[p]; // previous pointer to key m_eq[pp] = m_eq[p]; // previous pointer to data m_lo[p] = (char)0; if (len > 0) { m_sc[p] = m_kv[m_lo[pp]]; m_eq[p] = pp; m_lo[pp]++; if (m_kv[m_lo[pp]] == 0) { // key completly decompressed leaving garbage in key array m_lo[pp] = (char)0; m_sc[pp] = (char)0; m_hi[pp] = (char)0; } else { // we only got first char of key, rest is still there m_sc[pp] = (char)0xFFFF; } } else { // In this case we can save a node by swapping the new node // with the compressed node m_sc[pp] = (char)0xFFFF; m_hi[p] = pp; m_sc[p] = (char)0; m_eq[p] = val; m_length++; return(p); } } char s = key[start]; if (s < m_sc[p]) { m_lo[p] = Insert(m_lo[p], key, start, val); } else if (s == m_sc[p]) { if (s != 0) { m_eq[p] = Insert(m_eq[p], key, start + 1, val); } else { // key already in tree, overwrite data m_eq[p] = val; } } else { m_hi[p] = Insert(m_hi[p], key, start, val); } return(p); }