scripts: Changed most tree renderers to be pseudo-standalone

I'm trying to avoid having classes with different implementations across
scripts, as it makes updating things error-prone, but at same time
copying all the tree renderers to all dbg scripts would be a bit much.

Monkey-patching the TreeArt class in relevant scripts seems like a
reasonable compromise.
This commit is contained in:
Christopher Haster
2025-04-01 13:54:37 -05:00
parent 682f12a953
commit f550fa9a80
3 changed files with 608 additions and 590 deletions
+136 -132
View File
@@ -1516,151 +1516,155 @@ class TreeArt:
return '%s ' % ''.join(trunk) return '%s ' % ''.join(trunk)
# some more renderers # some more renderers
# render a btree rbyd tree for debugging # render a btree rbyd tree for debugging
@classmethod @classmethod
def _frombtreertree(cls, btree, *, def _treeartfrombtreertree(cls, btree, *,
depth=None, depth=None,
inner=False, inner=False,
**args): **args):
# precompute rbyd trees so we know the max depth at each layer # precompute rbyd trees so we know the max depth at each layer
# to nicely align trees # to nicely align trees
rtrees = {} rtrees = {}
rdepths = {} rdepths = {}
for bid, rbyd, path in btree.traverse(path=True, depth=depth): for bid, rbyd, path in btree.traverse(path=True, depth=depth):
if not rbyd: if not rbyd:
continue continue
rtree = cls.fromrbyd(rbyd, **args) rtree = cls.fromrbyd(rbyd, **args)
rtrees[rbyd] = rtree rtrees[rbyd] = rtree
rdepths[len(path)] = max(rdepths.get(len(path), 0), rtree.depth) rdepths[len(path)] = max(rdepths.get(len(path), 0), rtree.depth)
# map rbyd branches into our btree space # map rbyd branches into our btree space
tree = set() tree = set()
for bid, rbyd, path in btree.traverse(path=True, depth=depth): for bid, rbyd, path in btree.traverse(path=True, depth=depth):
if not rbyd: if not rbyd:
continue continue
# yes we can find new rbyds if disk is being mutated, just # yes we can find new rbyds if disk is being mutated, just
# ignore these # ignore these
if rbyd not in rtrees: if rbyd not in rtrees:
continue continue
rtree = rtrees[rbyd] rtree = rtrees[rbyd]
rz = max((t.z+1 for t in rtree), default=0) rz = max((t.z+1 for t in rtree), default=0)
d = sum(rdepths[d]+1 for d in range(len(path))) d = sum(rdepths[d]+1 for d in range(len(path)))
# map into our btree space # map into our btree space
for t in rtree: for t in rtree:
# note we adjust our bid to be left-leaning, this allows
# a global order and makes tree rendering quite a bit easier
a_rid, a_tag = t.a
b_rid, b_tag = t.b
_, (_, a_w, _) = rbyd.lookupnext(a_rid)
_, (_, b_w, _) = rbyd.lookupnext(b_rid)
tree.add(cls.Branch(
(bid-(rbyd.weight-1)+a_rid-(a_w-1), len(path), a_tag),
(bid-(rbyd.weight-1)+b_rid-(b_w-1), len(path), b_tag),
d + rdepths[len(path)]-rz + t.z,
t.color))
# connect rbyd branches to rbyd roots
if path:
l_bid, l_rbyd, l_rid, l_name = path[-1]
l_branch = l_rbyd.lookup(l_rid, TAG_BRANCH, 0x3)
if rtree:
r_rid, r_tag = min(rtree, key=lambda t: t.z).a
_, (_, r_w, _) = rbyd.lookupnext(r_rid)
else:
r_rid, (r_tag, r_w, _) = rbyd.lookupnext(-1)
tree.add(cls.Branch(
(l_bid-(l_name.weight-1), len(path)-1, l_branch.tag),
(bid-(rbyd.weight-1)+r_rid-(r_w-1), len(path), r_tag),
d-1))
# remap branches to leaves if we aren't showing inner branches
if not inner:
# step through each btree layer backwards
b_depth = max((t.a[1]+1 for t in tree), default=0)
for d in reversed(range(b_depth-1)):
# find bid ranges at this level
bids = set()
for t in tree:
if t.b[1] == d:
bids.add(t.b[0])
bids = sorted(bids)
# find the best root for each bid range
roots = {}
for i in range(len(bids)):
for t in tree:
if (t.a[1] > d
and t.a[0] >= bids[i]
and (i == len(bids)-1 or t.a[0] < bids[i+1])
and (bids[i] not in roots
or t < roots[bids[i]])):
roots[bids[i]] = t
# remap branches to leaf-roots
tree = {t.map(
lambda x: x[1] == d and x[0] in roots,
lambda x: roots[x[0]].a)
for t in tree}
return cls(tree)
# render a btree btree tree for debugging
@classmethod
def _frombtreebtree(cls, btree, *,
depth=None,
inner=False,
**args):
# find all branches
tree = set()
root = None
branches = {}
for bid, name, path in btree.bids(
path=True,
depth=depth):
# create branch for each jump in path
#
# note we adjust our bid to be left-leaning, this allows # note we adjust our bid to be left-leaning, this allows
# a global order and makes tree rendering quite a bit easier # a global order and makes tree rendering quite a bit easier
a = root a_rid, a_tag = t.a
for d, (bid_, rbyd_, rid_, name_) in enumerate(path): b_rid, b_tag = t.b
# map into our btree space _, (_, a_w, _) = rbyd.lookupnext(a_rid)
bid__ = bid_-(name_.weight-1) _, (_, b_w, _) = rbyd.lookupnext(b_rid)
b = (bid__, d, name_.tag) tree.add(cls.Branch(
(bid-(rbyd.weight-1)+a_rid-(a_w-1), len(path), a_tag),
(bid-(rbyd.weight-1)+b_rid-(b_w-1), len(path), b_tag),
d + rdepths[len(path)]-rz + t.z,
t.color))
# remap branches to leaves if we aren't showing inner # connect rbyd branches to rbyd roots
# branches if path:
if not inner: l_bid, l_rbyd, l_rid, l_name = path[-1]
if b not in branches: l_branch = l_rbyd.lookup(l_rid, TAG_BRANCH, 0x3)
bid_, rbyd_, rid_, name_ = path[-1]
bid__ = bid_-(name_.weight-1)
branches[b] = (bid__, len(path)-1, name_.tag)
b = branches[b]
# render the root path on first rid, this is arbitrary if rtree:
if root is None: r_rid, r_tag = min(rtree, key=lambda t: t.z).a
root, a = b, b _, (_, r_w, _) = rbyd.lookupnext(r_rid)
else:
r_rid, (r_tag, r_w, _) = rbyd.lookupnext(-1)
tree.add(cls.Branch(a, b, d)) tree.add(cls.Branch(
a = b (l_bid-(l_name.weight-1), len(path)-1, l_branch.tag),
(bid-(rbyd.weight-1)+r_rid-(r_w-1), len(path), r_tag),
d-1))
return cls(tree) # remap branches to leaves if we aren't showing inner branches
if not inner:
# step through each btree layer backwards
b_depth = max((t.a[1]+1 for t in tree), default=0)
# render a btree tree for debugging for d in reversed(range(b_depth-1)):
@classmethod # find bid ranges at this level
def frombtree(cls, btree, **args): bids = set()
if args.get('tree_btree'): for t in tree:
return cls._frombtreebtree(btree, **args) if t.b[1] == d:
else: bids.add(t.b[0])
return cls._frombtreertree(btree, **args) bids = sorted(bids)
# find the best root for each bid range
roots = {}
for i in range(len(bids)):
for t in tree:
if (t.a[1] > d
and t.a[0] >= bids[i]
and (i == len(bids)-1 or t.a[0] < bids[i+1])
and (bids[i] not in roots
or t < roots[bids[i]])):
roots[bids[i]] = t
# remap branches to leaf-roots
tree = {t.map(
lambda x: x[1] == d and x[0] in roots,
lambda x: roots[x[0]].a)
for t in tree}
return cls(tree)
# render a btree btree tree for debugging
@classmethod
def _treeartfrombtreebtree(cls, btree, *,
depth=None,
inner=False,
**args):
# find all branches
tree = set()
root = None
branches = {}
for bid, name, path in btree.bids(
path=True,
depth=depth):
# create branch for each jump in path
#
# note we adjust our bid to be left-leaning, this allows
# a global order and makes tree rendering quite a bit easier
a = root
for d, (bid_, rbyd_, rid_, name_) in enumerate(path):
# map into our btree space
bid__ = bid_-(name_.weight-1)
b = (bid__, d, name_.tag)
# remap branches to leaves if we aren't showing inner
# branches
if not inner:
if b not in branches:
bid_, rbyd_, rid_, name_ = path[-1]
bid__ = bid_-(name_.weight-1)
branches[b] = (bid__, len(path)-1, name_.tag)
b = branches[b]
# render the root path on first rid, this is arbitrary
if root is None:
root, a = b, b
tree.add(cls.Branch(a, b, d))
a = b
return cls(tree)
# render a btree tree for debugging
@classmethod
def treeartfrombtree(cls, btree, **args):
if args.get('tree_btree'):
return cls._frombtreebtree(btree, **args)
else:
return cls._frombtreertree(btree, **args)
TreeArt._frombtreertree = _treeartfrombtreertree
TreeArt._frombtreebtree = _treeartfrombtreebtree
TreeArt.frombtree = treeartfrombtree
+158 -152
View File
@@ -3750,174 +3750,180 @@ class TreeArt:
# some more renderers # some more renderers
# render a btree rbyd tree for debugging # render a btree rbyd tree for debugging
@classmethod @classmethod
def _frombtreertree(cls, btree, *, def _treeartfrombtreertree(cls, btree, *,
depth=None, depth=None,
inner=False, inner=False,
**args): **args):
# precompute rbyd trees so we know the max depth at each layer # precompute rbyd trees so we know the max depth at each layer
# to nicely align trees # to nicely align trees
rtrees = {} rtrees = {}
rdepths = {} rdepths = {}
for bid, rbyd, path in btree.traverse(path=True, depth=depth): for bid, rbyd, path in btree.traverse(path=True, depth=depth):
if not rbyd: if not rbyd:
continue continue
rtree = cls.fromrbyd(rbyd, **args) rtree = cls.fromrbyd(rbyd, **args)
rtrees[rbyd] = rtree rtrees[rbyd] = rtree
rdepths[len(path)] = max(rdepths.get(len(path), 0), rtree.depth) rdepths[len(path)] = max(rdepths.get(len(path), 0), rtree.depth)
# map rbyd branches into our btree space # map rbyd branches into our btree space
tree = set() tree = set()
for bid, rbyd, path in btree.traverse(path=True, depth=depth): for bid, rbyd, path in btree.traverse(path=True, depth=depth):
if not rbyd: if not rbyd:
continue continue
# yes we can find new rbyds if disk is being mutated, just # yes we can find new rbyds if disk is being mutated, just
# ignore these # ignore these
if rbyd not in rtrees: if rbyd not in rtrees:
continue continue
rtree = rtrees[rbyd] rtree = rtrees[rbyd]
rz = max((t.z+1 for t in rtree), default=0) rz = max((t.z+1 for t in rtree), default=0)
d = sum(rdepths[d]+1 for d in range(len(path))) d = sum(rdepths[d]+1 for d in range(len(path)))
# map into our btree space # map into our btree space
for t in rtree: for t in rtree:
# note we adjust our bid to be left-leaning, this allows
# a global order and makes tree rendering quite a bit easier
a_rid, a_tag = t.a
b_rid, b_tag = t.b
_, (_, a_w, _) = rbyd.lookupnext(a_rid)
_, (_, b_w, _) = rbyd.lookupnext(b_rid)
tree.add(cls.Branch(
(bid-(rbyd.weight-1)+a_rid-(a_w-1), len(path), a_tag),
(bid-(rbyd.weight-1)+b_rid-(b_w-1), len(path), b_tag),
d + rdepths[len(path)]-rz + t.z,
t.color))
# connect rbyd branches to rbyd roots
if path:
l_bid, l_rbyd, l_rid, l_name = path[-1]
l_branch = l_rbyd.lookup(l_rid, TAG_BRANCH, 0x3)
if rtree:
r_rid, r_tag = min(rtree, key=lambda t: t.z).a
_, (_, r_w, _) = rbyd.lookupnext(r_rid)
else:
r_rid, (r_tag, r_w, _) = rbyd.lookupnext(-1)
tree.add(cls.Branch(
(l_bid-(l_name.weight-1), len(path)-1, l_branch.tag),
(bid-(rbyd.weight-1)+r_rid-(r_w-1), len(path), r_tag),
d-1))
# remap branches to leaves if we aren't showing inner branches
if not inner:
# step through each btree layer backwards
b_depth = max((t.a[1]+1 for t in tree), default=0)
for d in reversed(range(b_depth-1)):
# find bid ranges at this level
bids = set()
for t in tree:
if t.b[1] == d:
bids.add(t.b[0])
bids = sorted(bids)
# find the best root for each bid range
roots = {}
for i in range(len(bids)):
for t in tree:
if (t.a[1] > d
and t.a[0] >= bids[i]
and (i == len(bids)-1 or t.a[0] < bids[i+1])
and (bids[i] not in roots
or t < roots[bids[i]])):
roots[bids[i]] = t
# remap branches to leaf-roots
tree = {t.map(
lambda x: x[1] == d and x[0] in roots,
lambda x: roots[x[0]].a)
for t in tree}
return cls(tree)
# render a btree btree tree for debugging
@classmethod
def _frombtreebtree(cls, btree, *,
depth=None,
inner=False,
**args):
# find all branches
tree = set()
root = None
branches = {}
for bid, name, path in btree.bids(
path=True,
depth=depth):
# create branch for each jump in path
#
# note we adjust our bid to be left-leaning, this allows # note we adjust our bid to be left-leaning, this allows
# a global order and makes tree rendering quite a bit easier # a global order and makes tree rendering quite a bit easier
a = root a_rid, a_tag = t.a
for d, (bid_, rbyd_, rid_, name_) in enumerate(path): b_rid, b_tag = t.b
# map into our btree space _, (_, a_w, _) = rbyd.lookupnext(a_rid)
bid__ = bid_-(name_.weight-1) _, (_, b_w, _) = rbyd.lookupnext(b_rid)
b = (bid__, d, name_.tag) tree.add(cls.Branch(
(bid-(rbyd.weight-1)+a_rid-(a_w-1), len(path), a_tag),
(bid-(rbyd.weight-1)+b_rid-(b_w-1), len(path), b_tag),
d + rdepths[len(path)]-rz + t.z,
t.color))
# remap branches to leaves if we aren't showing inner # connect rbyd branches to rbyd roots
# branches if path:
if not inner: l_bid, l_rbyd, l_rid, l_name = path[-1]
if b not in branches: l_branch = l_rbyd.lookup(l_rid, TAG_BRANCH, 0x3)
bid_, rbyd_, rid_, name_ = path[-1]
bid__ = bid_-(name_.weight-1)
branches[b] = (bid__, len(path)-1, name_.tag)
b = branches[b]
# render the root path on first rid, this is arbitrary if rtree:
if root is None: r_rid, r_tag = min(rtree, key=lambda t: t.z).a
root, a = b, b _, (_, r_w, _) = rbyd.lookupnext(r_rid)
else:
r_rid, (r_tag, r_w, _) = rbyd.lookupnext(-1)
tree.add(cls.Branch(a, b, d)) tree.add(cls.Branch(
a = b (l_bid-(l_name.weight-1), len(path)-1, l_branch.tag),
(bid-(rbyd.weight-1)+r_rid-(r_w-1), len(path), r_tag),
d-1))
return cls(tree) # remap branches to leaves if we aren't showing inner branches
if not inner:
# step through each btree layer backwards
b_depth = max((t.a[1]+1 for t in tree), default=0)
# render a btree tree for debugging for d in reversed(range(b_depth-1)):
@classmethod # find bid ranges at this level
def frombtree(cls, btree, **args): bids = set()
if args.get('tree_btree'): for t in tree:
return cls._frombtreebtree(btree, **args) if t.b[1] == d:
else: bids.add(t.b[0])
return cls._frombtreertree(btree, **args) bids = sorted(bids)
# render a file tree for debugging # find the best root for each bid range
@classmethod roots = {}
def fromfile(cls, file, **args): for i in range(len(bids)):
tree = cls.frombtree(file.bshrub, **args) for t in tree:
t_depth = tree.depth if (t.a[1] > d
and t.a[0] >= bids[i]
and (i == len(bids)-1 or t.a[0] < bids[i+1])
and (bids[i] not in roots
or t < roots[bids[i]])):
roots[bids[i]] = t
# connect bptr tags to bptrs # remap branches to leaf-roots
tree = set(tree) tree = {t.map(
bptrs = {} lambda x: x[1] == d and x[0] in roots,
for pos, data, path in file.datas( lambda x: roots[x[0]].a)
path=True, for t in tree}
depth=args.get('depth')):
if isinstance(data, Bptr):
a = (pos, len(path)-1, data.tag)
b = (pos, len(path), data.tag)
bptrs[a] = b
tree.add(cls.Branch(a, b, t_depth))
# if we're not showing inner branches, nudge bptr tags to return cls(tree)
# their bptrs
if not args.get('inner'):
tree = {t.map(lambda x: bptrs.get(x, x)) for t in tree}
return cls(tree) # render a btree btree tree for debugging
@classmethod
def _treeartfrombtreebtree(cls, btree, *,
depth=None,
inner=False,
**args):
# find all branches
tree = set()
root = None
branches = {}
for bid, name, path in btree.bids(
path=True,
depth=depth):
# create branch for each jump in path
#
# note we adjust our bid to be left-leaning, this allows
# a global order and makes tree rendering quite a bit easier
a = root
for d, (bid_, rbyd_, rid_, name_) in enumerate(path):
# map into our btree space
bid__ = bid_-(name_.weight-1)
b = (bid__, d, name_.tag)
# remap branches to leaves if we aren't showing inner
# branches
if not inner:
if b not in branches:
bid_, rbyd_, rid_, name_ = path[-1]
bid__ = bid_-(name_.weight-1)
branches[b] = (bid__, len(path)-1, name_.tag)
b = branches[b]
# render the root path on first rid, this is arbitrary
if root is None:
root, a = b, b
tree.add(cls.Branch(a, b, d))
a = b
return cls(tree)
# render a btree tree for debugging
@classmethod
def treeartfrombtree(cls, btree, **args):
if args.get('tree_btree'):
return cls._frombtreebtree(btree, **args)
else:
return cls._frombtreertree(btree, **args)
TreeArt._frombtreertree = _treeartfrombtreertree
TreeArt._frombtreebtree = _treeartfrombtreebtree
TreeArt.frombtree = treeartfrombtree
# render a file tree for debugging
@classmethod
def treeartfromfile(cls, file, **args):
tree = cls.frombtree(file.bshrub, **args)
t_depth = tree.depth
# connect bptr tags to bptrs
tree = set(tree)
bptrs = {}
for pos, data, path in file.datas(
path=True,
depth=args.get('depth')):
if isinstance(data, Bptr):
a = (pos, len(path)-1, data.tag)
b = (pos, len(path), data.tag)
bptrs[a] = b
tree.add(cls.Branch(a, b, t_depth))
# if we're not showing inner branches, nudge bptr tags to
# their bptrs
if not args.get('inner'):
tree = {t.map(lambda x: bptrs.get(x, x)) for t in tree}
return cls(tree)
TreeArt.fromfile = treeartfromfile
+314 -306
View File
@@ -2433,342 +2433,350 @@ class TreeArt:
return '%s ' % ''.join(trunk) return '%s ' % ''.join(trunk)
# some more renderers # some more renderers
# render a btree rbyd tree for debugging # render a btree rbyd tree for debugging
@classmethod @classmethod
def _frombtreertree(cls, btree, *, def _treeartfrombtreertree(cls, btree, *,
depth=None, depth=None,
inner=False, inner=False,
**args): **args):
# precompute rbyd trees so we know the max depth at each layer # precompute rbyd trees so we know the max depth at each layer
# to nicely align trees # to nicely align trees
rtrees = {} rtrees = {}
rdepths = {} rdepths = {}
for bid, rbyd, path in btree.traverse(path=True, depth=depth): for bid, rbyd, path in btree.traverse(path=True, depth=depth):
if not rbyd: if not rbyd:
continue continue
rtree = cls.fromrbyd(rbyd, **args) rtree = cls.fromrbyd(rbyd, **args)
rtrees[rbyd] = rtree rtrees[rbyd] = rtree
rdepths[len(path)] = max(rdepths.get(len(path), 0), rtree.depth) rdepths[len(path)] = max(rdepths.get(len(path), 0), rtree.depth)
# map rbyd branches into our btree space # map rbyd branches into our btree space
tree = set() tree = set()
for bid, rbyd, path in btree.traverse(path=True, depth=depth): for bid, rbyd, path in btree.traverse(path=True, depth=depth):
if not rbyd: if not rbyd:
continue continue
# yes we can find new rbyds if disk is being mutated, just # yes we can find new rbyds if disk is being mutated, just
# ignore these # ignore these
if rbyd not in rtrees: if rbyd not in rtrees:
continue continue
rtree = rtrees[rbyd] rtree = rtrees[rbyd]
rz = max((t.z+1 for t in rtree), default=0) rz = max((t.z+1 for t in rtree), default=0)
d = sum(rdepths[d]+1 for d in range(len(path))) d = sum(rdepths[d]+1 for d in range(len(path)))
# map into our btree space # map into our btree space
for t in rtree: for t in rtree:
# note we adjust our bid to be left-leaning, this allows
# a global order and makes tree rendering quite a bit easier
a_rid, a_tag = t.a
b_rid, b_tag = t.b
_, (_, a_w, _) = rbyd.lookupnext(a_rid)
_, (_, b_w, _) = rbyd.lookupnext(b_rid)
tree.add(cls.Branch(
(bid-(rbyd.weight-1)+a_rid-(a_w-1), len(path), a_tag),
(bid-(rbyd.weight-1)+b_rid-(b_w-1), len(path), b_tag),
d + rdepths[len(path)]-rz + t.z,
t.color))
# connect rbyd branches to rbyd roots
if path:
l_bid, l_rbyd, l_rid, l_name = path[-1]
l_branch = l_rbyd.lookup(l_rid, TAG_BRANCH, 0x3)
if rtree:
r_rid, r_tag = min(rtree, key=lambda t: t.z).a
_, (_, r_w, _) = rbyd.lookupnext(r_rid)
else:
r_rid, (r_tag, r_w, _) = rbyd.lookupnext(-1)
tree.add(cls.Branch(
(l_bid-(l_name.weight-1), len(path)-1, l_branch.tag),
(bid-(rbyd.weight-1)+r_rid-(r_w-1), len(path), r_tag),
d-1))
# remap branches to leaves if we aren't showing inner branches
if not inner:
# step through each btree layer backwards
b_depth = max((t.a[1]+1 for t in tree), default=0)
for d in reversed(range(b_depth-1)):
# find bid ranges at this level
bids = set()
for t in tree:
if t.b[1] == d:
bids.add(t.b[0])
bids = sorted(bids)
# find the best root for each bid range
roots = {}
for i in range(len(bids)):
for t in tree:
if (t.a[1] > d
and t.a[0] >= bids[i]
and (i == len(bids)-1 or t.a[0] < bids[i+1])
and (bids[i] not in roots
or t < roots[bids[i]])):
roots[bids[i]] = t
# remap branches to leaf-roots
tree = {t.map(
lambda x: x[1] == d and x[0] in roots,
lambda x: roots[x[0]].a)
for t in tree}
return cls(tree)
# render a btree btree tree for debugging
@classmethod
def _frombtreebtree(cls, btree, *,
depth=None,
inner=False,
**args):
# find all branches
tree = set()
root = None
branches = {}
for bid, name, path in btree.bids(
path=True,
depth=depth):
# create branch for each jump in path
#
# note we adjust our bid to be left-leaning, this allows # note we adjust our bid to be left-leaning, this allows
# a global order and makes tree rendering quite a bit easier # a global order and makes tree rendering quite a bit easier
a = root a_rid, a_tag = t.a
for d, (bid_, rbyd_, rid_, name_) in enumerate(path): b_rid, b_tag = t.b
# map into our btree space _, (_, a_w, _) = rbyd.lookupnext(a_rid)
bid__ = bid_-(name_.weight-1) _, (_, b_w, _) = rbyd.lookupnext(b_rid)
b = (bid__, d, name_.tag) tree.add(cls.Branch(
(bid-(rbyd.weight-1)+a_rid-(a_w-1), len(path), a_tag),
(bid-(rbyd.weight-1)+b_rid-(b_w-1), len(path), b_tag),
d + rdepths[len(path)]-rz + t.z,
t.color))
# remap branches to leaves if we aren't showing inner # connect rbyd branches to rbyd roots
# branches if path:
if not inner: l_bid, l_rbyd, l_rid, l_name = path[-1]
if b not in branches: l_branch = l_rbyd.lookup(l_rid, TAG_BRANCH, 0x3)
bid_, rbyd_, rid_, name_ = path[-1]
bid__ = bid_-(name_.weight-1)
branches[b] = (bid__, len(path)-1, name_.tag)
b = branches[b]
# render the root path on first rid, this is arbitrary if rtree:
if root is None: r_rid, r_tag = min(rtree, key=lambda t: t.z).a
root, a = b, b _, (_, r_w, _) = rbyd.lookupnext(r_rid)
else:
r_rid, (r_tag, r_w, _) = rbyd.lookupnext(-1)
tree.add(cls.Branch(a, b, d)) tree.add(cls.Branch(
a = b (l_bid-(l_name.weight-1), len(path)-1, l_branch.tag),
(bid-(rbyd.weight-1)+r_rid-(r_w-1), len(path), r_tag),
d-1))
return cls(tree) # remap branches to leaves if we aren't showing inner branches
if not inner:
# step through each btree layer backwards
b_depth = max((t.a[1]+1 for t in tree), default=0)
# render a btree tree for debugging for d in reversed(range(b_depth-1)):
@classmethod # find bid ranges at this level
def frombtree(cls, btree, **args): bids = set()
if args.get('tree_btree'): for t in tree:
return cls._frombtreebtree(btree, **args) if t.b[1] == d:
bids.add(t.b[0])
bids = sorted(bids)
# find the best root for each bid range
roots = {}
for i in range(len(bids)):
for t in tree:
if (t.a[1] > d
and t.a[0] >= bids[i]
and (i == len(bids)-1 or t.a[0] < bids[i+1])
and (bids[i] not in roots
or t < roots[bids[i]])):
roots[bids[i]] = t
# remap branches to leaf-roots
tree = {t.map(
lambda x: x[1] == d and x[0] in roots,
lambda x: roots[x[0]].a)
for t in tree}
return cls(tree)
# render a btree btree tree for debugging
@classmethod
def _treeartfrombtreebtree(cls, btree, *,
depth=None,
inner=False,
**args):
# find all branches
tree = set()
root = None
branches = {}
for bid, name, path in btree.bids(
path=True,
depth=depth):
# create branch for each jump in path
#
# note we adjust our bid to be left-leaning, this allows
# a global order and makes tree rendering quite a bit easier
a = root
for d, (bid_, rbyd_, rid_, name_) in enumerate(path):
# map into our btree space
bid__ = bid_-(name_.weight-1)
b = (bid__, d, name_.tag)
# remap branches to leaves if we aren't showing inner
# branches
if not inner:
if b not in branches:
bid_, rbyd_, rid_, name_ = path[-1]
bid__ = bid_-(name_.weight-1)
branches[b] = (bid__, len(path)-1, name_.tag)
b = branches[b]
# render the root path on first rid, this is arbitrary
if root is None:
root, a = b, b
tree.add(cls.Branch(a, b, d))
a = b
return cls(tree)
# render a btree tree for debugging
@classmethod
def treeartfrombtree(cls, btree, **args):
if args.get('tree_btree'):
return cls._frombtreebtree(btree, **args)
else:
return cls._frombtreertree(btree, **args)
TreeArt._frombtreertree = _treeartfrombtreertree
TreeArt._frombtreebtree = _treeartfrombtreebtree
TreeArt.frombtree = treeartfrombtree
# render an mtree tree for debugging
@classmethod
def _treeartfrommtreertree(cls, mtree, *,
depth=None,
inner=False,
**args):
# precompute rbyd trees so we know the max depth at each layer
# to nicely align trees
rtrees = {}
rdepths = {}
for mdir, path in mtree.traverse(path=True, depth=depth):
if isinstance(mdir, Mdir):
if not mdir:
continue
rbyd = mdir.rbyd
else: else:
return cls._frombtreertree(btree, **args) bid, rbyd = mdir
if not rbyd:
# render an mtree tree for debugging
@classmethod
def _frommtreertree(cls, mtree, *,
depth=None,
inner=False,
**args):
# precompute rbyd trees so we know the max depth at each layer
# to nicely align trees
rtrees = {}
rdepths = {}
for mdir, path in mtree.traverse(path=True, depth=depth):
if isinstance(mdir, Mdir):
if not mdir:
continue
rbyd = mdir.rbyd
else:
bid, rbyd = mdir
if not rbyd:
continue
rtree = cls.fromrbyd(rbyd, **args)
rtrees[rbyd] = rtree
rdepths[len(path)] = max(rdepths.get(len(path), 0), rtree.depth)
# map rbyd branches into our mtree space
tree = set()
branches = {}
for mdir, path in mtree.traverse(path=True, depth=depth):
if isinstance(mdir, Mdir):
if not mdir:
continue
rbyd = mdir.rbyd
else:
bid, rbyd = mdir
if not rbyd:
continue
# yes we can find new rbyds if disk is being mutated, just
# ignore these
if rbyd not in rtrees:
continue continue
rtree = rtrees[rbyd] rtree = cls.fromrbyd(rbyd, **args)
rz = max((t.z+1 for t in rtree), default=0) rtrees[rbyd] = rtree
d = sum(rdepths[d]+1 for d, p in enumerate(path)) rdepths[len(path)] = max(rdepths.get(len(path), 0), rtree.depth)
# map into our mtree space # map rbyd branches into our mtree space
for t in rtree: tree = set()
# note we adjust our mid/bid to be left-leaning, this allows branches = {}
# a global order and makes tree rendering quite a bit easier for mdir, path in mtree.traverse(path=True, depth=depth):
# if isinstance(mdir, Mdir):
# we also need to give btree nodes mrid=-1 so they come if not mdir:
# before and mrid=-1 mdir attrs continue
a_rid, a_tag = t.a rbyd = mdir.rbyd
b_rid, b_tag = t.b else:
_, (_, a_w, _) = rbyd.lookupnext(a_rid) bid, rbyd = mdir
_, (_, b_w, _) = rbyd.lookupnext(b_rid) if not rbyd:
if isinstance(mdir, Mdir): continue
a_mid = mtree.mid(mdir.mid, a_rid)
b_mid = mtree.mid(mdir.mid, b_rid)
else:
a_mid = mtree.mid(bid-(rbyd.weight-1)+a_rid-(a_w-1), -1)
b_mid = mtree.mid(bid-(rbyd.weight-1)+b_rid-(b_w-1), -1)
tree.add(cls.Branch( # yes we can find new rbyds if disk is being mutated, just
(a_mid, len(path), a_tag), # ignore these
(b_mid, len(path), b_tag), if rbyd not in rtrees:
d + rdepths[len(path)]-rz + t.z, continue
t.color))
# connect rbyd branches to rbyd roots rtree = rtrees[rbyd]
if path: rz = max((t.z+1 for t in rtree), default=0)
# figure out branch mid/attr d = sum(rdepths[d]+1 for d, p in enumerate(path))
if isinstance(path[-1][1], Mdir):
l_mid, l_mdir, l_name = path[-1]
l_branch = (l_mdir.lookup(l_mid, TAG_MROOT, 0x3)
or l_mdir.lookup(l_mid, TAG_MTREE, 0x3))
else:
l_bid, l_rbyd, l_rid, l_name = path[-1]
l_mid = mtree.mid(l_bid-(l_name.weight-1), -1)
l_branch = (l_rbyd.lookup(l_rid, TAG_BRANCH, 0x3)
or l_rbyd.lookup(l_rid, TAG_MDIR, 0x3))
# figure out root mid/rattr # map into our mtree space
if rtree: for t in rtree:
r_rid, r_tag = min(rtree, key=lambda t: t.z).a
_, (_, r_w, _) = rbyd.lookupnext(r_rid)
else:
r_rid, (r_tag, r_w, _) = rbyd.lookupnext(-1)
if isinstance(mdir, Mdir):
r_mid = mtree.mid(mdir.mid, r_rid)
else:
r_mid = mtree.mid(bid-(rbyd.weight-1)+r_rid-(r_w-1), -1)
tree.add(cls.Branch(
(l_mid, len(path)-1, l_branch.tag),
(r_mid, len(path), r_tag),
d-1))
# remap branches to leaves if we aren't showing inner branches
if not inner:
# step through each btree layer backwards
b_depth = max((t.a[1]+1 for t in tree), default=0)
for d in reversed(range(len(mtree.mrootchain), b_depth-1)):
# find mid ranges at this level
mids = set()
for t in tree:
if t.b[1] == d:
mids.add(t.b[0])
mids = sorted(mids)
# find the best root for each mid range
roots = {}
for i in range(len(mids)):
for t in tree:
if (t.a[1] > d
and t.a[0] >= mids[i]
and (i == len(mids)-1 or t.a[0] < mids[i+1])
and (mids[i] not in roots
or t < roots[mids[i]])):
roots[mids[i]] = t
# remap branches to leaf-roots
tree = {t.map(
lambda x: x[1] == d and x[0] in roots,
lambda x: roots[x[0]].a)
for t in tree}
return cls(tree)
# render an mtree tree for debugging
@classmethod
def _frommtreebtree(cls, mtree, *,
depth=None,
inner=False,
**args):
tree = set()
root = None
branches = {}
for mid, mdir, name, path in mtree.mids(
mdirs_only=False,
path=True,
depth=depth):
# create branch for each jump in path
#
# note we adjust our mid/bid to be left-leaning, this allows # note we adjust our mid/bid to be left-leaning, this allows
# a global order and makes tree rendering quite a bit easier # a global order and makes tree rendering quite a bit easier
# #
# we also need to give btree nodes mrid=-1 so they come # we also need to give btree nodes mrid=-1 so they come
# before and mrid=-1 mdir attrs # before and mrid=-1 mdir attrs
a = root a_rid, a_tag = t.a
for d, p in enumerate(path): b_rid, b_tag = t.b
# map into our mtree space _, (_, a_w, _) = rbyd.lookupnext(a_rid)
if isinstance(p[1], Mdir): _, (_, b_w, _) = rbyd.lookupnext(b_rid)
mid_, mdir_, name_ = p if isinstance(mdir, Mdir):
else: a_mid = mtree.mid(mdir.mid, a_rid)
bid_, rbyd_, rid_, name_ = p b_mid = mtree.mid(mdir.mid, b_rid)
mid_ = mtree.mid(bid_-(name_.weight-1), -1) else:
b = (mid_, d, name_.tag) a_mid = mtree.mid(bid-(rbyd.weight-1)+a_rid-(a_w-1), -1)
b_mid = mtree.mid(bid-(rbyd.weight-1)+b_rid-(b_w-1), -1)
# remap branches to leaves if we aren't showing inner tree.add(cls.Branch(
# branches (a_mid, len(path), a_tag),
if not inner: (b_mid, len(path), b_tag),
if b not in branches: d + rdepths[len(path)]-rz + t.z,
if isinstance(path[-1][1], Mdir): t.color))
mid_, mdir_, name_ = path[-1]
else:
bid_, rbyd_, rid_, name_ = path[-1]
mid_ = mtree.mid(bid_-(name_.weight-1), -1)
branches[b] = (mid_, len(path)-1, name_.tag)
b = branches[b]
# render the root path on first rid, this is arbitrary # connect rbyd branches to rbyd roots
if root is None: if path:
root, a = b, b # figure out branch mid/attr
if isinstance(path[-1][1], Mdir):
l_mid, l_mdir, l_name = path[-1]
l_branch = (l_mdir.lookup(l_mid, TAG_MROOT, 0x3)
or l_mdir.lookup(l_mid, TAG_MTREE, 0x3))
else:
l_bid, l_rbyd, l_rid, l_name = path[-1]
l_mid = mtree.mid(l_bid-(l_name.weight-1), -1)
l_branch = (l_rbyd.lookup(l_rid, TAG_BRANCH, 0x3)
or l_rbyd.lookup(l_rid, TAG_MDIR, 0x3))
tree.add(cls.Branch(a, b, d)) # figure out root mid/rattr
a = b if rtree:
r_rid, r_tag = min(rtree, key=lambda t: t.z).a
_, (_, r_w, _) = rbyd.lookupnext(r_rid)
else:
r_rid, (r_tag, r_w, _) = rbyd.lookupnext(-1)
return cls(tree) if isinstance(mdir, Mdir):
r_mid = mtree.mid(mdir.mid, r_rid)
else:
r_mid = mtree.mid(bid-(rbyd.weight-1)+r_rid-(r_w-1), -1)
# render an mtree tree for debugging tree.add(cls.Branch(
@classmethod (l_mid, len(path)-1, l_branch.tag),
def frommtree(cls, mtree, **args): (r_mid, len(path), r_tag),
if args.get('tree_btree'): d-1))
return cls._frommtreebtree(mtree, **args)
else: # remap branches to leaves if we aren't showing inner branches
return cls._frommtreertree(mtree, **args) if not inner:
# step through each btree layer backwards
b_depth = max((t.a[1]+1 for t in tree), default=0)
for d in reversed(range(len(mtree.mrootchain), b_depth-1)):
# find mid ranges at this level
mids = set()
for t in tree:
if t.b[1] == d:
mids.add(t.b[0])
mids = sorted(mids)
# find the best root for each mid range
roots = {}
for i in range(len(mids)):
for t in tree:
if (t.a[1] > d
and t.a[0] >= mids[i]
and (i == len(mids)-1 or t.a[0] < mids[i+1])
and (mids[i] not in roots
or t < roots[mids[i]])):
roots[mids[i]] = t
# remap branches to leaf-roots
tree = {t.map(
lambda x: x[1] == d and x[0] in roots,
lambda x: roots[x[0]].a)
for t in tree}
return cls(tree)
# render an mtree tree for debugging
@classmethod
def _treeartfrommtreebtree(cls, mtree, *,
depth=None,
inner=False,
**args):
tree = set()
root = None
branches = {}
for mid, mdir, name, path in mtree.mids(
mdirs_only=False,
path=True,
depth=depth):
# create branch for each jump in path
#
# note we adjust our mid/bid to be left-leaning, this allows
# a global order and makes tree rendering quite a bit easier
#
# we also need to give btree nodes mrid=-1 so they come
# before and mrid=-1 mdir attrs
a = root
for d, p in enumerate(path):
# map into our mtree space
if isinstance(p[1], Mdir):
mid_, mdir_, name_ = p
else:
bid_, rbyd_, rid_, name_ = p
mid_ = mtree.mid(bid_-(name_.weight-1), -1)
b = (mid_, d, name_.tag)
# remap branches to leaves if we aren't showing inner
# branches
if not inner:
if b not in branches:
if isinstance(path[-1][1], Mdir):
mid_, mdir_, name_ = path[-1]
else:
bid_, rbyd_, rid_, name_ = path[-1]
mid_ = mtree.mid(bid_-(name_.weight-1), -1)
branches[b] = (mid_, len(path)-1, name_.tag)
b = branches[b]
# render the root path on first rid, this is arbitrary
if root is None:
root, a = b, b
tree.add(cls.Branch(a, b, d))
a = b
return cls(tree)
# render an mtree tree for debugging
@classmethod
def treeartfrommtree(cls, mtree, **args):
if args.get('tree_btree'):
return cls._frommtreebtree(mtree, **args)
else:
return cls._frommtreertree(mtree, **args)
TreeArt._frommtreertree = _treeartfrommtreertree
TreeArt._frommtreebtree = _treeartfrommtreebtree
TreeArt.frommtree = treeartfrommtree