From 478a78dcd9d12580cebe1dd34696a98c0acaee15 Mon Sep 17 00:00:00 2001 From: ping-ke Date: Tue, 6 Jan 2026 17:31:48 +0800 Subject: [PATCH] bug fix --- trie/hash.py | 69 ++++++++++++++++++++++++++------------------------ trie/path.py | 71 +++++++++++++++++++++++++++++----------------------- 2 files changed, 75 insertions(+), 65 deletions(-) diff --git a/trie/hash.py b/trie/hash.py index 01a93a2..2598666 100644 --- a/trie/hash.py +++ b/trie/hash.py @@ -14,10 +14,13 @@ def __init__(self, kind, data): self.kind = kind self.data = data + def hash(self): + return hash_func(self.data) def get_nbit(key, pos): - b = pos // 8 - return (key[b] >> (pos % 8)) % 2 + b = pos >> 3 # pos // 8 + shift = 7 - (pos & 7) # 7 - (pos % 8) + return (key[b] >> shift) & 1 # a), initial tree @@ -52,13 +55,13 @@ def __init__(self): def __createInternal(self, value): node = Node(KIND_INTERNAL, value) - key = hash_func(value) + key = node.hash() self.kv[key] = node return key, node def __createLeaf(self, key, value): node = Node(KIND_LEAF, key + value) # TODO: only store the part of the key not used in path - hkey = hash_func(key + value) + hkey = node.hash() self.kv[hkey] = node return hkey, node @@ -83,12 +86,12 @@ def put(self, key, value): if get_nbit(key, depth) != get_nbit(existing_leaf_key, depth): break - if get_nbit(key, depth) == 0: + if get_nbit(key, common) == 0: inode_data = leaf_hash + node_key else: inode_data = node_key + leaf_hash inode_key, _ = self.__createInternal(inode_data) - for i in range(common-1, depth, -1): + for i in range(common-1, depth - 1, -1): if get_nbit(key, i) == 0: inode_data = inode_key + KEY_NIL else: @@ -141,35 +144,35 @@ def setRoot(self, root): t = Tree() -t.put(b'\2'+b'\1'*31, b'\0') -assert t.get(b'\2'+b'\1'*31) == b'\0' -t.put(b'\0'+b'\1'*31, b'\1') -assert t.get(b'\2'+b'\1'*31) == b'\0' -assert t.get(b'\0'+b'\1'*31) == b'\1' -t.put(b'\3'+b'\1'*31, b'\2') -assert t.get(b'\2'+b'\1'*31) == b'\0' -assert t.get(b'\0'+b'\1'*31) == b'\1' -assert t.get(b'\3'+b'\1'*31) == b'\2' +t.put(b'\x40'+b'\1'*31, b'\0') # b'\x40' -> 0100 0000 +assert t.get(b'\x40'+b'\1'*31) == b'\0' +t.put(b'\x00'+b'\1'*31, b'\1') # b'\x00' -> 0000 0000 +assert t.get(b'\x40'+b'\1'*31) == b'\0' +assert t.get(b'\x00'+b'\1'*31) == b'\1' +t.put(b'\xc0'+b'\1'*31, b'\2') # b'\xc0' -> 1100 0000 +assert t.get(b'\x40'+b'\1'*31) == b'\0' +assert t.get(b'\x00'+b'\1'*31) == b'\1' +assert t.get(b'\xc0'+b'\1'*31) == b'\2' root = t.root -t.put(b'\131'+b'\1'*31, b'\3') -assert t.get(b'\2'+b'\1'*31) == b'\0' -assert t.get(b'\0'+b'\1'*31) == b'\1' -assert t.get(b'\3'+b'\1'*31) == b'\2' -assert t.get(b'\131'+b'\1'*31) == b'\3' +t.put(b'\x60'+b'\1'*31, b'\3') # b'\x60' -> 0110 0000 +assert t.get(b'\x40'+b'\1'*31) == b'\0' +assert t.get(b'\x00'+b'\1'*31) == b'\1' +assert t.get(b'\xc0'+b'\1'*31) == b'\2' +assert t.get(b'\x60'+b'\1'*31) == b'\3' t.setRoot(root) -assert t.get(b'\2'+b'\1'*31) == b'\0' -assert t.get(b'\0'+b'\1'*31) == b'\1' -assert t.get(b'\3'+b'\1'*31) == b'\2' -assert t.get(b'\131'+b'\1'*31) == None +assert t.get(b'\x40'+b'\1'*31) == b'\0' +assert t.get(b'\x00'+b'\1'*31) == b'\1' +assert t.get(b'\xc0'+b'\1'*31) == b'\2' +assert t.get(b'\x60'+b'\1'*31) == None # test multi-version -t.put(b'\0'+b'\1'*31, b'\3') -assert t.get(b'\2'+b'\1'*31) == b'\0' -assert t.get(b'\0'+b'\1'*31) == b'\3' -assert t.get(b'\3'+b'\1'*31) == b'\2' -assert t.get(b'\131'+b'\1'*31) == None +t.put(b'\x00'+b'\1'*31, b'\3') +assert t.get(b'\x40'+b'\1'*31) == b'\0' +assert t.get(b'\x00'+b'\1'*31) == b'\3' +assert t.get(b'\xc0'+b'\1'*31) == b'\2' +assert t.get(b'\x60'+b'\1'*31) == None t.setRoot(root) -assert t.get(b'\2'+b'\1'*31) == b'\0' -assert t.get(b'\0'+b'\1'*31) == b'\1' -assert t.get(b'\3'+b'\1'*31) == b'\2' -assert t.get(b'\131'+b'\1'*31) == None \ No newline at end of file +assert t.get(b'\x40'+b'\1'*31) == b'\0' +assert t.get(b'\x00'+b'\1'*31) == b'\1' +assert t.get(b'\xc0'+b'\1'*31) == b'\2' +assert t.get(b'\x60'+b'\1'*31) == None \ No newline at end of file diff --git a/trie/path.py b/trie/path.py index 30fdcf5..57f7771 100644 --- a/trie/path.py +++ b/trie/path.py @@ -19,8 +19,9 @@ def hash(self): return hash_func(self.data) def get_nbit(key, pos): - b = pos // 8 - return (key[b] >> (pos % 8)) % 2 + b = pos >> 3 # pos // 8 + shift = 7 - (pos & 7) # 7 - (pos % 8) + return (key[b] >> shift) & 1 # a), initial tree # root=internal('0'*32 + '0'*32) @@ -57,9 +58,11 @@ def get_nbit(key, pos): # n0=leaf(h0+d0), n1=leaf(h1+d1) # key '' => root # key '0' => inode0 +# key '00' => n1 # key '01' => inode1 -# key '010' => n1 -# key '011' => n0 +# key '010' => n0 +# key '011' => n3 +# key '1' => n2 class Tree: def __init__(self, kv=None): @@ -195,46 +198,50 @@ def root(self): def test_tree(tree_func): t = tree_func() t1 = hash.Tree() - t.put(b'\2'+b'\1'*31, b'\0') - t1.put(b'\2'+b'\1'*31, b'\0') - assert t.get(b'\2'+b'\1'*31) == b'\0' + # b'\x40' -> 0100 0000 + t.put(b'\x40'+b'\1'*31, b'\0') + t1.put(b'\x40'+b'\1'*31, b'\0') + assert t.get(b'\x40'+b'\1'*31) == b'\0' assert t.root == t1.root - t.put(b'\0'+b'\1'*31, b'\1') - t1.put(b'\0'+b'\1'*31, b'\1') - assert t.get(b'\2'+b'\1'*31) == b'\0' - assert t.get(b'\0'+b'\1'*31) == b'\1' + # b'\x00' -> 0000 0000 + t.put(b'\x00'+b'\1'*31, b'\1') + t1.put(b'\x00'+b'\1'*31, b'\1') + assert t.get(b'\x40'+b'\1'*31) == b'\0' + assert t.get(b'\x00'+b'\1'*31) == b'\1' assert t.root == t1.root - t.put(b'\3'+b'\1'*31, b'\2') - t1.put(b'\3'+b'\1'*31, b'\2') - assert t.get(b'\2'+b'\1'*31) == b'\0' - assert t.get(b'\0'+b'\1'*31) == b'\1' - assert t.get(b'\3'+b'\1'*31) == b'\2' + # b'\xc0' -> 1100 0000 + t.put(b'\xc0'+b'\1'*31, b'\2') + t1.put(b'\xc0'+b'\1'*31, b'\2') + assert t.get(b'\x40'+b'\1'*31) == b'\0' + assert t.get(b'\x00'+b'\1'*31) == b'\1' + assert t.get(b'\xc0'+b'\1'*31) == b'\2' snapshot = dict(t.kv) root1 = t1.root assert t.root == t1.root - t.put(b'\131'+b'\1'*31, b'\3') - t1.put(b'\131'+b'\1'*31, b'\3') - assert t.get(b'\2'+b'\1'*31) == b'\0' - assert t.get(b'\0'+b'\1'*31) == b'\1' - assert t.get(b'\3'+b'\1'*31) == b'\2' - assert t.get(b'\131'+b'\1'*31) == b'\3' + # b'\x60' -> 0110 0000 + t.put(b'\x60'+b'\1'*31, b'\3') + t1.put(b'\x60'+b'\1'*31, b'\3') + assert t.get(b'\x40'+b'\1'*31) == b'\0' + assert t.get(b'\x00'+b'\1'*31) == b'\1' + assert t.get(b'\xc0'+b'\1'*31) == b'\2' + assert t.get(b'\x60'+b'\1'*31) == b'\3' assert t.root == t1.root t = tree_func(snapshot) t1.setRoot(root1) - assert t.get(b'\2'+b'\1'*31) == b'\0' - assert t.get(b'\0'+b'\1'*31) == b'\1' - assert t.get(b'\3'+b'\1'*31) == b'\2' - assert t.get(b'\131'+b'\1'*31) == None + assert t.get(b'\x40'+b'\1'*31) == b'\0' + assert t.get(b'\x00'+b'\1'*31) == b'\1' + assert t.get(b'\xc0'+b'\1'*31) == b'\2' + assert t.get(b'\x60'+b'\1'*31) == None assert t.root == t1.root # test multi-version - t.put(b'\0'+b'\1'*31, b'\3') - t1.put(b'\0'+b'\1'*31, b'\3') - assert t.get(b'\2'+b'\1'*31) == b'\0' - assert t.get(b'\0'+b'\1'*31) == b'\3' - assert t.get(b'\3'+b'\1'*31) == b'\2' - assert t.get(b'\131'+b'\1'*31) == None + t.put(b'\x00'+b'\1'*31, b'\3') + t1.put(b'\x00'+b'\1'*31, b'\3') + assert t.get(b'\x40'+b'\1'*31) == b'\0' + assert t.get(b'\x00'+b'\1'*31) == b'\3' + assert t.get(b'\xc0'+b'\1'*31) == b'\2' + assert t.get(b'\x60'+b'\1'*31) == None assert t.root == t1.root test_tree(Tree)