tricu

An interpreted language for exploring Tree Calculus
Log | Files | Refs | README | LICENSE

bundle_dag.py (3594B)


      1 """Exact constructor/child-ID interning of verified portable DAGs; no expansion."""
      2 import struct,sys
      3 from pathlib import Path
      4 from stable_bundle import assembled,sections
      5 
      6 def read(path):
      7  m,n=sections(Path(path));off=12
      8  def word():
      9   nonlocal off
     10   v=struct.unpack_from('>I',m,off)[0];off+=4;return v
     11  def string():
     12   nonlocal off
     13   size=word();v=m[off:off+size];off+=size;return v
     14  for _ in range(9):string()
     15  for _ in range(word()):string()
     16  off+=1
     17  locations={}
     18  for _ in range(word()):
     19   pos=off;word();name=string().decode();locations.setdefault(name,[]).append(pos)
     20  exports={}
     21  for _ in range(word()):
     22   name=string().decode();locations.setdefault(name,[]).append(off);exports[name]=word();string();string()
     23  for _ in range(word()):
     24   off+=2;string()
     25  assert word()==0
     26  assert off==len(m)
     27  nodes=[];at=8
     28  for i in range(struct.unpack_from('>Q',n,0)[0]):
     29   size=struct.unpack_from('>I',n,at)[0];at+=4;p=n[at:at+size];at+=size
     30   tag=p[0];assert tag in (0,1,2)
     31   children=() if tag==0 else struct.unpack('>I' if tag==1 else '>II',p[1:])
     32   assert all(c<i for c in children)
     33   nodes.append((tag,*children))
     34  assert at==len(n)
     35  return m,n,nodes,exports,locations
     36 
     37 class Intern:
     38  def __init__(self):self.nodes=[];self.table={}
     39  def node(self,key):
     40   if key not in self.table:self.table[key]=len(self.nodes);self.nodes.append(key)
     41   return self.table[key]
     42  def graph(self,nodes):
     43   ids=[]
     44   for tag,*children in nodes:ids.append(self.node((tag,*[ids[c] for c in children])))
     45   return ids
     46  def encoded(self):
     47   rows=[]
     48   for tag,*children in self.nodes:
     49    p=bytes([tag])+b''.join(struct.pack('>I',c) for c in children);rows.append(struct.pack('>I',len(p))+p)
     50   return struct.pack('>Q',len(rows))+b''.join(rows)
     51 
     52 def contains(nodes,root,target):
     53  seen=set();todo=[root]
     54  while todo:
     55   cur=todo.pop()
     56   if cur in seen:continue
     57   if cur==target:return True
     58   seen.add(cur);todo.extend(nodes[cur][1:])
     59  return False
     60 
     61 def merge_bundles(destination, selections, *, prune_unreachable=False):
     62  """Intern selected complete public roots; retain order, validate exact structure.
     63  Each selection is (bundle_path, [(old_export_name, new_export_name), ...]).
     64  """
     65  intern=Intern();named=[];seen=set();first=read(selections[0][0])[0]
     66  at=12
     67  def word():
     68   nonlocal at
     69   v=struct.unpack_from('>I',first,at)[0];at+=4;return v
     70  def string():
     71   nonlocal at
     72   n=word();at+=n
     73  for _ in range(9):string()
     74  for _ in range(word()):string()
     75  at+=1;prefix=first[:at]
     76  for _ in range(word()):word();string()
     77  for _ in range(word()):string();word();string();string()
     78  suffix=first[at:]
     79  def text(v):
     80   b=v.encode();return struct.pack('>I',len(b))+b
     81  for path,names in selections:
     82   bundle=read(path)
     83   if prune_unreachable:
     84    reachable=set();todo=[bundle[3][old] for old,_ in names]
     85    while todo:
     86     root=todo.pop()
     87     if root in reachable:continue
     88     reachable.add(root);todo.extend(bundle[2][root][1:])
     89    ids={}
     90    for index in sorted(reachable):
     91     tag,*children=bundle[2][index]
     92     ids[index]=intern.node((tag,*[ids[c] for c in children]))
     93   else:
     94    ids=intern.graph(bundle[2])
     95   for old,new in names:
     96    assert new not in seen;seen.add(new);named.append((new,ids[bundle[3][old]]))
     97  roots=struct.pack('>I',len(named))+b''.join(struct.pack('>I',v)+text(k) for k,v in named)
     98  exports=struct.pack('>I',len(named))+b''.join(text(k)+struct.pack('>I',v)+text('term')+text('arboricx.abi.tree.v1') for k,v in named)
     99  Path(destination).write_bytes(assembled(prefix+roots+exports+suffix,intern.encoded()))
    100  check=read(destination);ids=intern.graph(check[2]);assert {k:ids[v] for k,v in check[3].items()}==dict(named)