go-hep.org/x/hep@v0.38.1/groot/rtree/branch.go (about)

     1  // Copyright ©2017 The go-hep Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package rtree
     6  
     7  import (
     8  	"fmt"
     9  	"reflect"
    10  	"strings"
    11  
    12  	"go-hep.org/x/hep/groot/rbase"
    13  	"go-hep.org/x/hep/groot/rbytes"
    14  	"go-hep.org/x/hep/groot/rcont"
    15  	"go-hep.org/x/hep/groot/rdict"
    16  	"go-hep.org/x/hep/groot/riofs"
    17  	"go-hep.org/x/hep/groot/root"
    18  	"go-hep.org/x/hep/groot/rtypes"
    19  	"go-hep.org/x/hep/groot/rvers"
    20  )
    21  
    22  const (
    23  	defaultBasketSize = 32 * 1024 // default basket size in bytes
    24  	defaultSplitLevel = 99        // default split-level for branches
    25  	defaultMaxBaskets = 10        // default number of baskets
    26  )
    27  
    28  type tbranch struct {
    29  	named          rbase.Named
    30  	attfill        rbase.AttFill
    31  	compress       int         // compression level and algorithm
    32  	basketSize     int         // initial size of Basket buffer
    33  	entryOffsetLen int         // initial length of entryOffset table in the basket buffers
    34  	writeBasket    int         // last basket number written
    35  	entryNumber    int64       // current entry number (last one filled in this branch)
    36  	iobits         tioFeatures // IO features for newly-created baskets
    37  	offset         int         // offset of this branch
    38  	maxBaskets     int         // maximum number of baskets so far
    39  	splitLevel     int         // branch split level
    40  	entries        int64       // number of entries
    41  	firstEntry     int64       // number of the first entry in this branch
    42  	totBytes       int64       // total number of bytes in all leaves before compression
    43  	zipBytes       int64       // total number of bytes in all leaves after compression
    44  	branches       []Branch    // list of branches of this branch
    45  	leaves         []Leaf      // list of leaves of this branch
    46  	baskets        []Basket    // list of baskets of this branch
    47  
    48  	basketBytes []int32 // length of baskets on file
    49  	basketEntry []int64 // table of first entry in each basket
    50  	basketSeek  []int64 // addresses of baskets on file
    51  
    52  	fname string // named of file where buffers are stored (empty if in same file as Tree header)
    53  
    54  	ctx basketCtx // basket context for the current basket
    55  
    56  	tree *ttree          // tree header
    57  	btop Branch          // top-level parent branch in the tree
    58  	bup  Branch          // parent branch
    59  	dir  riofs.Directory // directory where this branch's buffers are stored
    60  }
    61  
    62  func newBranchFromWVar(w *wtree, name string, wvar WriteVar, parent Branch, lvl int, cfg wopt) (Branch, error) {
    63  	base := &tbranch{
    64  		named:    *rbase.NewNamed(name, ""),
    65  		attfill:  *rbase.NewAttFill(),
    66  		compress: int(cfg.compress),
    67  
    68  		iobits:      w.ttree.iobits,
    69  		basketSize:  int(cfg.bufsize),
    70  		maxBaskets:  defaultMaxBaskets,
    71  		basketBytes: make([]int32, 0, defaultMaxBaskets),
    72  		basketEntry: make([]int64, 1, defaultMaxBaskets),
    73  		basketSeek:  make([]int64, 0, defaultMaxBaskets),
    74  
    75  		tree: &w.ttree,
    76  		btop: btopOf(parent),
    77  		bup:  parent,
    78  		dir:  w.dir,
    79  	}
    80  
    81  	var (
    82  		b Branch = base
    83  
    84  		title = new(strings.Builder)
    85  		rt    = reflect.TypeOf(wvar.Value).Elem()
    86  	)
    87  
    88  	title.WriteString(wvar.Name)
    89  	switch k := rt.Kind(); k {
    90  	case reflect.Array:
    91  		et, shape := flattenArrayType(rt)
    92  		for _, dim := range shape {
    93  			fmt.Fprintf(title, "[%d]", dim)
    94  		}
    95  		rt = et
    96  
    97  	case reflect.Slice:
    98  		switch wvar.Count {
    99  		case "":
   100  			// write as a std::vector<T>
   101  			return newBranchElementFromWVar(w, base, wvar, parent, lvl, cfg)
   102  		default:
   103  			fmt.Fprintf(title, "[%s]", wvar.Count)
   104  			rt = rt.Elem()
   105  		}
   106  		base.entryOffsetLen = 1000 // slice, so we need an offset array
   107  
   108  	case reflect.String:
   109  		base.entryOffsetLen = 1000 // string, so we need an offset array
   110  
   111  	case reflect.Struct:
   112  		return newBranchElementFromWVar(w, base, wvar, parent, lvl, cfg)
   113  	}
   114  
   115  	isBranchElem := false
   116  	if parent != nil {
   117  		if parent, ok := parent.(*tbranchElement); ok {
   118  			isBranchElem = true
   119  			be := &tbranchElement{
   120  				tbranch: *base,
   121  				class:   parent.class,
   122  				parent:  parent.class,
   123  			}
   124  			b = be
   125  			base = &be.tbranch
   126  		}
   127  	}
   128  
   129  	if !isBranchElem && rt.Kind() != reflect.Struct {
   130  		code := gotypeToROOTTypeCode(rt)
   131  		fmt.Fprintf(title, "/%s", code)
   132  	}
   133  
   134  	_, err := newLeafFromWVar(w, b, wvar, lvl, cfg)
   135  	if err != nil {
   136  		return nil, err
   137  	}
   138  
   139  	base.named.SetTitle(title.String())
   140  	base.createNewBasket()
   141  
   142  	return b, nil
   143  }
   144  
   145  func (b *tbranch) RVersion() int16 {
   146  	return rvers.Branch
   147  }
   148  
   149  func (b *tbranch) Name() string {
   150  	return b.named.Name()
   151  }
   152  
   153  func (b *tbranch) Title() string {
   154  	return b.named.Title()
   155  }
   156  
   157  func (b *tbranch) Class() string {
   158  	return "TBranch"
   159  }
   160  
   161  func (b *tbranch) getTree() *ttree {
   162  	return b.tree
   163  }
   164  
   165  func (b *tbranch) setTree(t *ttree) {
   166  	b.tree = t
   167  	for _, sub := range b.branches {
   168  		sub.setTree(t)
   169  	}
   170  }
   171  
   172  func (b *tbranch) Branches() []Branch {
   173  	return b.branches
   174  }
   175  
   176  func (b *tbranch) Leaves() []Leaf {
   177  	return b.leaves
   178  }
   179  
   180  func (b *tbranch) Branch(name string) Branch {
   181  	for _, bb := range b.Branches() {
   182  		if bb.Name() == name {
   183  			return bb
   184  		}
   185  	}
   186  	return nil
   187  }
   188  
   189  func (b *tbranch) Leaf(name string) Leaf {
   190  	for _, lf := range b.Leaves() {
   191  		if lf.Name() == name {
   192  			return lf
   193  		}
   194  	}
   195  	switch {
   196  	case b.bup != nil:
   197  		return b.bup.Leaf(name)
   198  	case b.btop != nil:
   199  		return b.btop.Leaf(name)
   200  	case b.tree != nil:
   201  		return b.tree.Leaf(name)
   202  	}
   203  	return nil
   204  }
   205  
   206  func (b *tbranch) GoType() reflect.Type {
   207  	if len(b.Leaves()) == 1 {
   208  		return b.leaves[0].Type()
   209  	}
   210  	fields := make([]reflect.StructField, len(b.leaves))
   211  	for i, leaf := range b.leaves {
   212  		ft := &fields[i]
   213  		ft.Name = "ROOT_" + leaf.Name()
   214  		etype := leaf.Type()
   215  		switch {
   216  		case leaf.LeafCount() != nil:
   217  			etype = reflect.SliceOf(etype)
   218  		case leaf.Len() > 1 && leaf.Kind() != reflect.String:
   219  			etype = reflect.ArrayOf(leaf.Len(), etype)
   220  		}
   221  		ft.Type = etype
   222  	}
   223  	return reflect.StructOf(fields)
   224  }
   225  
   226  func (b *tbranch) getReadEntry() int64 {
   227  	return b.ctx.entry
   228  }
   229  
   230  func (b *tbranch) getEntry(i int64) {
   231  	if b.ctx.entry == i {
   232  		return
   233  	}
   234  	err := b.loadEntry(i)
   235  	if err != nil {
   236  		panic(fmt.Errorf("rtree: branch [%s] failed to load entry %d: %w", b.Name(), i, err))
   237  	}
   238  }
   239  
   240  func (b *tbranch) MarshalROOT(w *rbytes.WBuffer) (int, error) {
   241  	if w.Err() != nil {
   242  		return 0, w.Err()
   243  	}
   244  
   245  	maxBaskets := b.maxBaskets
   246  	defer func() { b.maxBaskets = maxBaskets }()
   247  	b.maxBaskets = max(b.writeBasket+1, defaultMaxBaskets)
   248  
   249  	hdr := w.WriteHeader(b.Class(), b.RVersion())
   250  	w.WriteObject(&b.named)
   251  	w.WriteObject(&b.attfill)
   252  	w.WriteI32(int32(b.compress))
   253  	w.WriteI32(int32(b.basketSize))
   254  	w.WriteI32(int32(b.entryOffsetLen))
   255  	w.WriteI32(int32(b.writeBasket))
   256  	w.WriteI64(b.entryNumber)
   257  	w.WriteObject(&b.iobits)
   258  	w.WriteI32(int32(b.offset))
   259  	w.WriteI32(int32(b.maxBaskets))
   260  	w.WriteI32(int32(b.splitLevel))
   261  	w.WriteI64(b.entries)
   262  	w.WriteI64(b.firstEntry)
   263  	w.WriteI64(b.totBytes)
   264  	w.WriteI64(b.zipBytes)
   265  
   266  	{
   267  		branches := rcont.NewObjArray()
   268  		if len(b.branches) > 0 {
   269  			elems := make([]root.Object, len(b.branches))
   270  			for i, v := range b.branches {
   271  				elems[i] = v
   272  			}
   273  			branches.SetElems(elems)
   274  		}
   275  		if n, err := branches.MarshalROOT(w); err != nil {
   276  			return n, err
   277  		}
   278  	}
   279  	{
   280  		leaves := rcont.NewObjArray()
   281  		if len(b.leaves) > 0 {
   282  			elems := make([]root.Object, len(b.leaves))
   283  			for i, v := range b.leaves {
   284  				elems[i] = v
   285  			}
   286  			leaves.SetElems(elems)
   287  		}
   288  		if n, err := leaves.MarshalROOT(w); err != nil {
   289  			return n, err
   290  		}
   291  	}
   292  	{
   293  		baskets := rcont.NewObjArray()
   294  		if len(b.baskets) > 0 {
   295  			elems := make([]root.Object, len(b.baskets))
   296  			for i := range b.baskets {
   297  				elems[i] = &b.baskets[i]
   298  			}
   299  			baskets.SetElems(elems)
   300  		}
   301  		if n, err := baskets.MarshalROOT(w); err != nil {
   302  			return n, err
   303  		}
   304  		baskets.SetElems(nil)
   305  	}
   306  
   307  	{
   308  		sli := b.basketBytes[:b.writeBasket]
   309  		w.WriteI8(1)
   310  		w.WriteArrayI32(sli)
   311  		if n := b.maxBaskets - len(sli); n > 0 {
   312  			// fill up with zeros.
   313  			w.WriteArrayI32(make([]int32, n))
   314  		}
   315  	}
   316  
   317  	{
   318  		sli := b.basketEntry[:b.writeBasket+1]
   319  		w.WriteI8(1)
   320  		w.WriteArrayI64(sli)
   321  		if n := b.maxBaskets - len(sli); n > 0 {
   322  			// fill up with zeros.
   323  			w.WriteArrayI64(make([]int64, n))
   324  		}
   325  	}
   326  
   327  	{
   328  		sli := b.basketSeek[:b.writeBasket]
   329  		w.WriteI8(1)
   330  		w.WriteArrayI64(sli)
   331  		if n := b.maxBaskets - len(sli); n > 0 {
   332  			// fill up with zeros.
   333  			w.WriteArrayI64(make([]int64, n))
   334  		}
   335  	}
   336  
   337  	w.WriteString(b.fname)
   338  
   339  	return w.SetHeader(hdr)
   340  }
   341  
   342  // ROOTUnmarshaler is the interface implemented by an object that can
   343  // unmarshal itself from a ROOT buffer
   344  func (b *tbranch) UnmarshalROOT(r *rbytes.RBuffer) error {
   345  	if r.Err() != nil {
   346  		return r.Err()
   347  	}
   348  
   349  	hdr := r.ReadHeader(b.Class(), b.RVersion())
   350  
   351  	b.tree = nil
   352  	b.ctx.bk = nil
   353  	b.ctx.entry = -1
   354  	b.ctx.first = -1
   355  	b.ctx.next = -1
   356  
   357  	const minVers = 6
   358  	switch {
   359  	case hdr.Vers >= 10:
   360  
   361  		r.ReadObject(&b.named)
   362  		r.ReadObject(&b.attfill)
   363  
   364  		b.compress = int(r.ReadI32())
   365  		b.basketSize = int(r.ReadI32())
   366  		b.entryOffsetLen = int(r.ReadI32())
   367  		b.writeBasket = int(r.ReadI32())
   368  		b.entryNumber = r.ReadI64()
   369  		if hdr.Vers >= 13 {
   370  			if err := b.iobits.UnmarshalROOT(r); err != nil {
   371  				return err
   372  			}
   373  		}
   374  		b.offset = int(r.ReadI32())
   375  		b.maxBaskets = int(r.ReadI32())
   376  		b.splitLevel = int(r.ReadI32())
   377  		b.entries = r.ReadI64()
   378  		if hdr.Vers >= 11 {
   379  			b.firstEntry = r.ReadI64()
   380  		}
   381  		b.totBytes = r.ReadI64()
   382  		b.zipBytes = r.ReadI64()
   383  
   384  		{
   385  			var branches rcont.ObjArray
   386  			if err := branches.UnmarshalROOT(r); err != nil {
   387  				return err
   388  			}
   389  			b.branches = make([]Branch, branches.Last()+1)
   390  			for i := range b.branches {
   391  				br := branches.At(i).(Branch)
   392  				b.branches[i] = br
   393  			}
   394  		}
   395  
   396  		{
   397  			var leaves rcont.ObjArray
   398  			if err := leaves.UnmarshalROOT(r); err != nil {
   399  				return err
   400  			}
   401  			b.leaves = make([]Leaf, leaves.Last()+1)
   402  			for i := range b.leaves {
   403  				leaf := leaves.At(i).(Leaf)
   404  				leaf.setBranch(b)
   405  				b.leaves[i] = leaf
   406  			}
   407  		}
   408  		{
   409  			var baskets rcont.ObjArray
   410  			if err := baskets.UnmarshalROOT(r); err != nil {
   411  				return err
   412  			}
   413  
   414  			b.baskets = make([]Basket, baskets.Last()+1)
   415  			for i := range b.baskets {
   416  				bkt := baskets.At(i)
   417  				// FIXME(sbinet) check why some are nil
   418  				if bkt == nil {
   419  					continue
   420  				}
   421  				bk := bkt.(*Basket)
   422  				b.baskets[i] = *bk
   423  			}
   424  		}
   425  
   426  		b.basketBytes = nil
   427  		b.basketEntry = nil
   428  		b.basketSeek = nil
   429  
   430  		/*isArray*/
   431  		_ = r.ReadI8()
   432  		b.basketBytes = make([]int32, b.maxBaskets)
   433  		r.ReadArrayI32(b.basketBytes)
   434  		b.basketBytes = b.basketBytes[:b.writeBasket:b.writeBasket]
   435  
   436  		/*isArray*/
   437  		_ = r.ReadI8()
   438  		b.basketEntry = make([]int64, b.maxBaskets)
   439  		r.ReadArrayI64(b.basketEntry)
   440  		b.basketEntry = b.basketEntry[: b.writeBasket+1 : b.writeBasket+1]
   441  
   442  		/*isArray*/
   443  		_ = r.ReadI8()
   444  		b.basketSeek = make([]int64, b.maxBaskets)
   445  		r.ReadArrayI64(b.basketSeek)
   446  		b.basketSeek = b.basketSeek[:b.writeBasket:b.writeBasket]
   447  
   448  		b.fname = r.ReadString()
   449  
   450  	case hdr.Vers >= 6:
   451  		r.ReadObject(&b.named)
   452  
   453  		if hdr.Vers > 7 {
   454  			r.ReadObject(&b.attfill)
   455  		}
   456  
   457  		b.compress = int(r.ReadI32())
   458  		b.basketSize = int(r.ReadI32())
   459  		b.entryOffsetLen = int(r.ReadI32())
   460  		b.writeBasket = int(r.ReadI32())
   461  		b.entryNumber = int64(r.ReadI32())
   462  		b.offset = int(r.ReadI32())
   463  		b.maxBaskets = int(r.ReadI32())
   464  		if hdr.Vers > 6 {
   465  			b.splitLevel = int(r.ReadI32())
   466  		}
   467  		b.entries = int64(r.ReadF64())
   468  		b.totBytes = int64(r.ReadF64())
   469  		b.zipBytes = int64(r.ReadF64())
   470  
   471  		{
   472  			var branches rcont.ObjArray
   473  			if err := branches.UnmarshalROOT(r); err != nil {
   474  				return err
   475  			}
   476  			b.branches = make([]Branch, branches.Last()+1)
   477  			for i := range b.branches {
   478  				br := branches.At(i).(Branch)
   479  				b.branches[i] = br
   480  			}
   481  		}
   482  
   483  		{
   484  			var leaves rcont.ObjArray
   485  			if err := leaves.UnmarshalROOT(r); err != nil {
   486  				return err
   487  			}
   488  			b.leaves = make([]Leaf, leaves.Last()+1)
   489  			for i := range b.leaves {
   490  				leaf := leaves.At(i).(Leaf)
   491  				leaf.setBranch(b)
   492  				b.leaves[i] = leaf
   493  			}
   494  		}
   495  		{
   496  			var baskets rcont.ObjArray
   497  			if err := baskets.UnmarshalROOT(r); err != nil {
   498  				return err
   499  			}
   500  			b.baskets = make([]Basket, baskets.Last()+1)
   501  			for i := range b.baskets {
   502  				bkt := baskets.At(i)
   503  				// FIXME(sbinet) check why some are nil
   504  				if bkt == nil {
   505  					continue
   506  				}
   507  				bk := bkt.(*Basket)
   508  				b.baskets[i] = *bk
   509  			}
   510  		}
   511  
   512  		b.basketBytes = nil
   513  		b.basketEntry = nil
   514  		b.basketSeek = nil
   515  
   516  		/*isArray*/
   517  		_ = r.ReadI8()
   518  		b.basketBytes = make([]int32, b.maxBaskets)
   519  		r.ReadArrayI32(b.basketBytes)
   520  
   521  		/*isArray*/
   522  		_ = r.ReadI8()
   523  		{
   524  			slice := make([]int32, b.maxBaskets)
   525  			r.ReadArrayI32(slice)
   526  			b.basketEntry = make([]int64, len(slice))
   527  			for i, v := range slice {
   528  				b.basketEntry[i] = int64(v)
   529  			}
   530  		}
   531  
   532  		switch r.ReadI8() {
   533  		case 2:
   534  			b.basketSeek = make([]int64, b.maxBaskets)
   535  			r.ReadArrayI64(b.basketSeek)
   536  		default:
   537  			slice := make([]int32, b.maxBaskets)
   538  			r.ReadArrayI32(slice)
   539  			b.basketSeek = make([]int64, len(slice))
   540  			for i, v := range slice {
   541  				b.basketSeek[i] = int64(v)
   542  			}
   543  		}
   544  
   545  		b.fname = r.ReadString()
   546  
   547  	default:
   548  		panic(fmt.Errorf("rtree: too old TBranch version (%d<%d)", hdr.Vers, minVers))
   549  	}
   550  
   551  	if b.splitLevel == 0 && len(b.branches) > 0 {
   552  		b.splitLevel = 1
   553  	}
   554  
   555  	r.CheckHeader(hdr)
   556  	return r.Err()
   557  }
   558  
   559  func (b *tbranch) loadEntry(ientry int64) error {
   560  	var err error
   561  
   562  	if len(b.basketBytes) == 0 {
   563  		return nil
   564  	}
   565  
   566  	err = b.loadBasket(ientry)
   567  	if err != nil {
   568  		return err
   569  	}
   570  	b.firstEntry = b.ctx.first
   571  
   572  	jentry := ientry - b.ctx.first
   573  	switch len(b.leaves) {
   574  	case 1:
   575  		err = b.ctx.bk.loadLeaf(jentry, b.leaves[0])
   576  		if err != nil {
   577  			return err
   578  		}
   579  	default:
   580  		for _, leaf := range b.leaves {
   581  			err = b.ctx.bk.loadLeaf(jentry, leaf)
   582  			if err != nil {
   583  				return err
   584  			}
   585  		}
   586  	}
   587  
   588  	return nil
   589  }
   590  
   591  func (b *tbranch) loadBasket(entry int64) error {
   592  	ib := b.findBasketIndex(entry)
   593  	if ib < 0 {
   594  		return fmt.Errorf("rtree: no basket for entry %d", entry)
   595  	}
   596  	var (
   597  		err   error
   598  		bufsz = int(b.basketBytes[ib])
   599  		seek  = b.basketSeek[ib]
   600  		f     = b.tree.getFile()
   601  	)
   602  	b.ctx.id = ib
   603  	b.ctx.entry = entry
   604  	b.ctx.next = b.basketEntry[ib+1]
   605  	b.ctx.first = b.basketEntry[ib]
   606  	if ib < len(b.baskets) {
   607  		b.ctx.bk = &b.baskets[ib]
   608  		if b.ctx.bk.rbuf == nil {
   609  			err = b.ctx.inflate(bufsz, seek, f)
   610  			if err != nil {
   611  				return fmt.Errorf("rtree: could not inflate basket: %w", err)
   612  			}
   613  
   614  			return b.setupBasket(&b.ctx, entry)
   615  		}
   616  		return nil
   617  	}
   618  
   619  	b.baskets = append(b.baskets, Basket{})
   620  	b.ctx.bk = &b.baskets[len(b.baskets)-1]
   621  	err = b.ctx.inflate(bufsz, seek, f)
   622  	if err != nil {
   623  		return fmt.Errorf("rtree: could not inflate basket: %w", err)
   624  	}
   625  	return b.setupBasket(&b.ctx, entry)
   626  }
   627  
   628  func (b *tbranch) findBasketIndex(entry int64) int {
   629  	switch {
   630  	case entry == 0:
   631  		return 0
   632  	case b.ctx.first <= entry && entry < b.ctx.next:
   633  		return b.ctx.id
   634  	}
   635  	/*
   636  		    // binary search is not efficient for small slices (like basketEntry)
   637  			// TODO(sbinet): test at which length of basketEntry it starts to be efficient.
   638  			entries := b.basketEntry[1:]
   639  			i := sort.Search(len(entries), func(i int) bool { return entries[i] >= entry })
   640  			if b.basketEntry[i+1] == entry {
   641  				return i + 1
   642  			}
   643  			return i
   644  	*/
   645  
   646  	for i := b.ctx.id; i < len(b.basketEntry); i++ {
   647  		v := b.basketEntry[i]
   648  		if v > entry && v > 0 {
   649  			return i - 1
   650  		}
   651  	}
   652  	if entry == b.basketEntry[len(b.basketEntry)-1] {
   653  		return -2 // len(b.basketEntry) - 1
   654  	}
   655  	return -1
   656  }
   657  
   658  func (b *tbranch) setupBasket(ctx *basketCtx, entry int64) error {
   659  	ib := ctx.id
   660  	switch ctx.keylen {
   661  	case 0: // FIXME(sbinet): from trial and error. check this is ok for all cases
   662  		b.basketEntry[ib] = 0
   663  		b.basketEntry[ib+1] = int64(ctx.bk.nevbuf)
   664  
   665  	default:
   666  		if b.entryOffsetLen <= 0 {
   667  			return nil
   668  		}
   669  
   670  		last := int64(ctx.bk.last)
   671  		ctx.bk.rbuf.SetPos(last)
   672  		n := int(ctx.bk.rbuf.ReadI32())
   673  		ctx.bk.offsets = rbytes.ResizeI32(ctx.bk.offsets, n)
   674  		ctx.bk.rbuf.ReadArrayI32(ctx.bk.offsets)
   675  		if err := ctx.bk.rbuf.Err(); err != nil {
   676  			return err
   677  		}
   678  	}
   679  
   680  	return nil
   681  }
   682  
   683  func (b *tbranch) setStreamer(s rbytes.StreamerInfo, ctx rbytes.StreamerInfoContext) {
   684  	// no op
   685  }
   686  
   687  func (b *tbranch) setStreamerElement(s rbytes.StreamerElement, ctx rbytes.StreamerInfoContext) {
   688  	// no op
   689  }
   690  
   691  func (b *tbranch) createNewBasket() {
   692  	cycle := int16(b.writeBasket) + 1
   693  	bk := newBasketFrom(b.tree, b, cycle, b.basketSize, b.entryOffsetLen)
   694  	b.ctx.bk = &bk
   695  	if n := b.writeBasket; n > b.maxBaskets {
   696  		b.maxBaskets = n
   697  	}
   698  }
   699  
   700  func (b *tbranch) write() (int, error) {
   701  	b.entries++
   702  	b.entryNumber++
   703  
   704  	szOld := b.ctx.bk.wbuf.Len()
   705  	b.ctx.bk.update(szOld)
   706  	_, err := b.writeToBuffer(b.ctx.bk.wbuf)
   707  	szNew := b.ctx.bk.wbuf.Len()
   708  	n := int(szNew - szOld)
   709  	if err != nil {
   710  		return n, fmt.Errorf("could not write to buffer (branch=%q): %w", b.Name(), err)
   711  	}
   712  	if n > b.ctx.bk.nevsize {
   713  		b.ctx.bk.nevsize = n
   714  	}
   715  
   716  	// FIXME(sbinet): harmonize or drive via "auto-flush" ?
   717  	if szNew+int64(n) >= int64(b.basketSize) {
   718  		err = b.flush()
   719  		if err != nil {
   720  			return n, fmt.Errorf("could not flush branch (auto-flush): %w", err)
   721  		}
   722  
   723  		b.createNewBasket()
   724  	}
   725  	return n, nil
   726  }
   727  
   728  func (b *tbranch) writeToBuffer(w *rbytes.WBuffer) (int, error) {
   729  	var tot int
   730  	for i, leaf := range b.leaves {
   731  		n, err := leaf.writeToBuffer(w)
   732  		if err != nil {
   733  			return tot, fmt.Errorf("could not write leaf[%d] name=%q of branch %q: %w", i, leaf.Name(), b.Name(), err)
   734  		}
   735  		tot += n
   736  	}
   737  	return tot, nil
   738  }
   739  
   740  func (b *tbranch) flush() error {
   741  	for i, sub := range b.branches {
   742  		err := sub.flush()
   743  		if err != nil {
   744  			return fmt.Errorf("could not flush subbranch[%d]=%q of branch %q: %w", i, sub.Name(), b.Name(), err)
   745  		}
   746  	}
   747  
   748  	f := b.tree.getFile()
   749  	totBytes, zipBytes, err := b.ctx.bk.writeFile(f, int32(b.compress))
   750  	if err != nil {
   751  		return fmt.Errorf("could not marshal basket[%d] (branch=%q): %w", b.writeBasket, b.Name(), err)
   752  	}
   753  	b.totBytes += totBytes
   754  	b.zipBytes += zipBytes
   755  
   756  	b.basketBytes = append(b.basketBytes, b.ctx.bk.key.Nbytes())
   757  	b.basketEntry = append(b.basketEntry, b.entryNumber)
   758  	b.basketSeek = append(b.basketSeek, b.ctx.bk.key.SeekKey())
   759  	b.writeBasket++
   760  	b.ctx.bk = nil
   761  
   762  	return nil
   763  }
   764  
   765  // tbranchObject is a Branch for objects.
   766  type tbranchObject struct {
   767  	tbranch
   768  	class string // class name of referenced object
   769  }
   770  
   771  func (b *tbranchObject) RVersion() int16 {
   772  	return rvers.BranchObject
   773  }
   774  
   775  func (b *tbranchObject) Class() string {
   776  	return "TBranchObject"
   777  }
   778  
   779  func (b *tbranchObject) MarshalROOT(w *rbytes.WBuffer) (int, error) {
   780  	if w.Err() != nil {
   781  		return 0, w.Err()
   782  	}
   783  
   784  	hdr := w.WriteHeader(b.Class(), b.RVersion())
   785  	w.WriteObject(&b.tbranch)
   786  	w.WriteString(b.class)
   787  
   788  	return w.SetHeader(hdr)
   789  }
   790  
   791  // ROOTUnmarshaler is the interface implemented by an object that can
   792  // unmarshal itself from a ROOT buffer
   793  func (b *tbranchObject) UnmarshalROOT(r *rbytes.RBuffer) error {
   794  	if r.Err() != nil {
   795  		return r.Err()
   796  	}
   797  
   798  	hdr := r.ReadHeader(b.Class(), b.RVersion())
   799  
   800  	if hdr.Vers < 1 {
   801  		r.SetErr(fmt.Errorf("rtree: TBranchObject version too old (%d < 8)", hdr.Vers))
   802  		return r.Err()
   803  	}
   804  
   805  	r.ReadObject(&b.tbranch)
   806  
   807  	for _, leaf := range b.leaves {
   808  		switch leaf := leaf.(type) {
   809  		case *tleaf:
   810  			leaf.branch = b
   811  		case *tleafObject:
   812  			leaf.branch = b
   813  		case *tleafElement:
   814  			leaf.branch = b
   815  		}
   816  	}
   817  
   818  	b.class = r.ReadString()
   819  
   820  	r.CheckHeader(hdr)
   821  	return r.Err()
   822  }
   823  
   824  // tbranchElement is a Branch for objects.
   825  type tbranchElement struct {
   826  	tbranch
   827  	class   string          // class name of referenced object
   828  	parent  string          // name of parent class
   829  	clones  string          // named of class in TClonesArray (if any)
   830  	chksum  uint32          // checksum of class
   831  	clsver  uint16          // version number of class
   832  	id      int32           // element serial number in fInfo
   833  	btype   int32           // branch type
   834  	stype   int32           // branch streamer type
   835  	max     int32           // maximum entries for a TClonesArray or variable array
   836  	stltyp  int32           // STL container type
   837  	bcount1 *tbranchElement // pointer to primary branchcount branch
   838  	bcount2 *tbranchElement // pointer to secondary branchcount branch
   839  
   840  	streamer  rbytes.StreamerInfo
   841  	estreamer rbytes.StreamerElement
   842  }
   843  
   844  func newBranchElementFromWVar(w *wtree, base *tbranch, wvar WriteVar, parent Branch, lvl int, cfg wopt) (Branch, error) {
   845  	var (
   846  		rv       = reflect.ValueOf(wvar.Value)
   847  		streamer = rdict.StreamerOf(w.ttree.f, reflect.Indirect(rv).Type())
   848  		pclass   = ""
   849  	)
   850  
   851  	if parent, ok := parent.(*tbranchElement); ok {
   852  		pclass = parent.class
   853  	}
   854  
   855  	b := &tbranchElement{
   856  		tbranch:  *base,
   857  		class:    streamer.Name(),
   858  		parent:   pclass,
   859  		chksum:   uint32(streamer.CheckSum()),
   860  		clsver:   uint16(streamer.ClassVersion()),
   861  		id:       -1,
   862  		btype:    0,
   863  		stype:    -1,
   864  		streamer: streamer,
   865  	}
   866  	switch reflect.TypeOf(wvar.Value).Elem().Kind() {
   867  	case reflect.Struct:
   868  		b.tbranch.entryOffsetLen = 20
   869  	case reflect.Slice:
   870  		b.tbranch.entryOffsetLen = 400
   871  	}
   872  
   873  	w.ttree.f.RegisterStreamer(b.streamer)
   874  
   875  	_, err := newLeafFromWVar(w, b, wvar, lvl, cfg)
   876  	if err != nil {
   877  		return nil, err
   878  	}
   879  	b.named.SetTitle(wvar.Name)
   880  	b.createNewBasket()
   881  	return b, nil
   882  }
   883  
   884  func (b *tbranchElement) RVersion() int16 {
   885  	return rvers.BranchElement
   886  }
   887  
   888  func (b *tbranchElement) Class() string {
   889  	return "TBranchElement"
   890  }
   891  
   892  func (b *tbranchElement) MarshalROOT(w *rbytes.WBuffer) (int, error) {
   893  	if w.Err() != nil {
   894  		return 0, w.Err()
   895  	}
   896  
   897  	hdr := w.WriteHeader(b.Class(), b.RVersion())
   898  	w.WriteObject(&b.tbranch)
   899  	w.WriteString(b.class)
   900  	w.WriteString(b.parent)
   901  	w.WriteString(b.clones)
   902  	w.WriteU32(b.chksum)
   903  	w.WriteU16(b.clsver)
   904  	w.WriteI32(b.id)
   905  	w.WriteI32(b.btype)
   906  	w.WriteI32(b.stype)
   907  	w.WriteI32(b.max)
   908  
   909  	{
   910  		var obj root.Object
   911  		if b.bcount1 != nil {
   912  			obj = b.bcount1
   913  		}
   914  		w.WriteObjectAny(obj)
   915  	}
   916  	{
   917  		var obj root.Object
   918  		if b.bcount2 != nil {
   919  			obj = b.bcount2
   920  		}
   921  		w.WriteObjectAny(obj)
   922  	}
   923  
   924  	return w.SetHeader(hdr)
   925  }
   926  
   927  // ROOTUnmarshaler is the interface implemented by an object that can
   928  // unmarshal itself from a ROOT buffer
   929  func (b *tbranchElement) UnmarshalROOT(r *rbytes.RBuffer) error {
   930  	if r.Err() != nil {
   931  		return r.Err()
   932  	}
   933  
   934  	hdr := r.ReadHeader(b.Class(), b.RVersion())
   935  
   936  	if hdr.Vers < 1 {
   937  		r.SetErr(fmt.Errorf("rtree: TBranchElement version too old (%d < 8)", hdr.Vers))
   938  		return r.Err()
   939  	}
   940  
   941  	r.ReadObject(&b.tbranch)
   942  
   943  	for _, leaf := range b.leaves {
   944  		switch leaf := leaf.(type) {
   945  		case *tleaf:
   946  			leaf.branch = b
   947  		case *tleafObject:
   948  			leaf.branch = b
   949  		case *tleafElement:
   950  			leaf.branch = b
   951  		}
   952  	}
   953  
   954  	b.class = r.ReadString()
   955  	if hdr.Vers > 1 {
   956  		b.parent = r.ReadString()
   957  		b.clones = r.ReadString()
   958  		b.chksum = r.ReadU32()
   959  	}
   960  	if hdr.Vers >= 10 {
   961  		b.clsver = r.ReadU16()
   962  	} else {
   963  		b.clsver = uint16(r.ReadU32())
   964  	}
   965  	b.id = r.ReadI32()
   966  	b.btype = r.ReadI32()
   967  	b.stype = r.ReadI32()
   968  	if hdr.Vers > 1 {
   969  		b.max = r.ReadI32()
   970  
   971  		bcount1 := r.ReadObjectAny()
   972  		if bcount1 != nil {
   973  			b.bcount1 = bcount1.(*tbranchElement)
   974  		}
   975  
   976  		bcount2 := r.ReadObjectAny()
   977  		if bcount2 != nil {
   978  			b.bcount2 = bcount2.(*tbranchElement)
   979  		}
   980  	}
   981  
   982  	r.CheckHeader(hdr)
   983  	return r.Err()
   984  }
   985  
   986  func (b *tbranchElement) loadEntry(ientry int64) error {
   987  	if len(b.branches) > 0 {
   988  		for _, sub := range b.branches {
   989  			err := sub.loadEntry(ientry)
   990  			if err != nil {
   991  				return err
   992  			}
   993  		}
   994  	}
   995  	return b.tbranch.loadEntry(ientry)
   996  }
   997  
   998  func (b *tbranchElement) setupReadStreamer(sictx rbytes.StreamerInfoContext) error {
   999  	streamer, err := sictx.StreamerInfo(b.class, int(b.clsver))
  1000  	if err != nil {
  1001  		streamer, err = sictx.StreamerInfo(b.class, -1)
  1002  		if err != nil {
  1003  			return fmt.Errorf("rtree: no StreamerInfo for class=%q version=%d checksum=%d", b.class, b.clsver, b.chksum)
  1004  		}
  1005  	}
  1006  	b.streamer = streamer
  1007  
  1008  	for _, leaf := range b.tbranch.leaves {
  1009  		leaf, ok := leaf.(*tleafElement)
  1010  		if !ok {
  1011  			continue
  1012  		}
  1013  		leaf.streamers = b.streamer.Elements()
  1014  	}
  1015  
  1016  	for _, sub := range b.branches {
  1017  		sub, ok := sub.(*tbranchElement)
  1018  		if !ok {
  1019  			continue
  1020  		}
  1021  		err := sub.setupReadStreamer(sictx)
  1022  		if err != nil {
  1023  			return err
  1024  		}
  1025  	}
  1026  
  1027  	return nil
  1028  }
  1029  
  1030  func (b *tbranchElement) GoType() reflect.Type {
  1031  	typ, err := rdict.TypeFromSI(b.tree.getFile(), b.streamer)
  1032  	if err != nil {
  1033  		panic(err)
  1034  	}
  1035  	return typ
  1036  }
  1037  
  1038  func (b *tbranchElement) setStreamer(s rbytes.StreamerInfo, ctx rbytes.StreamerInfoContext) {
  1039  	b.streamer = s
  1040  	if len(b.tbranch.leaves) == 1 {
  1041  		typ, err := rdict.TypeFromSI(ctx, s)
  1042  		if err != nil {
  1043  			panic(err)
  1044  		}
  1045  		tle := b.tbranch.leaves[0].(*tleafElement)
  1046  		tle.streamers = s.Elements()
  1047  		tle.src = reflect.New(typ).Elem()
  1048  	}
  1049  	err := b.setupReadStreamer(ctx)
  1050  	if err != nil {
  1051  		panic(err)
  1052  	}
  1053  }
  1054  
  1055  func (b *tbranchElement) setStreamerElement(se rbytes.StreamerElement, ctx rbytes.StreamerInfoContext) {
  1056  	b.estreamer = se
  1057  	if len(b.Leaves()) == 1 {
  1058  		tle := b.Leaves()[0].(*tleafElement)
  1059  		tle.streamers = []rbytes.StreamerElement{se}
  1060  		typ, err := rdict.TypeFromSE(ctx, se)
  1061  		if err != nil {
  1062  			panic(err)
  1063  		}
  1064  		tle.src = reflect.New(typ).Elem()
  1065  	}
  1066  	err := b.setupReadStreamer(ctx)
  1067  	if err != nil {
  1068  		panic(err)
  1069  	}
  1070  }
  1071  
  1072  func (b *tbranchElement) write() (int, error) {
  1073  	b.entries++
  1074  	b.entryNumber++
  1075  
  1076  	szOld := b.ctx.bk.wbuf.Len()
  1077  	b.ctx.bk.update(szOld)
  1078  	_, err := b.writeToBuffer(b.ctx.bk.wbuf)
  1079  	szNew := b.ctx.bk.wbuf.Len()
  1080  	n := int(szNew - szOld)
  1081  	if err != nil {
  1082  		return n, fmt.Errorf("could not write to buffer (branch=%q): %w", b.Name(), err)
  1083  	}
  1084  	if n > b.ctx.bk.nevsize {
  1085  		b.ctx.bk.grow(n)
  1086  	}
  1087  
  1088  	// FIXME(sbinet): harmonize or drive via "auto-flush" ?
  1089  	if szNew+int64(n) >= int64(b.basketSize) {
  1090  		err = b.flush()
  1091  		if err != nil {
  1092  			return n, fmt.Errorf("could not flush branch (auto-flush): %w", err)
  1093  		}
  1094  
  1095  		b.createNewBasket()
  1096  	}
  1097  	return n, nil
  1098  }
  1099  
  1100  func (b *tbranchElement) writeToBuffer(w *rbytes.WBuffer) (int, error) {
  1101  	var tot int
  1102  	for i, leaf := range b.leaves {
  1103  		n, err := leaf.writeToBuffer(w)
  1104  		if err != nil {
  1105  			return tot, fmt.Errorf("could not write leaf[%d] name=%q of branch %q: %w", i, leaf.Name(), b.Name(), err)
  1106  		}
  1107  		tot += n
  1108  	}
  1109  	return tot, nil
  1110  }
  1111  
  1112  func btopOf(b Branch) Branch {
  1113  	if b == nil {
  1114  		return nil
  1115  	}
  1116  	const max = 1<<31 - 1
  1117  	for range max {
  1118  		switch bb := b.(type) {
  1119  		case *tbranch:
  1120  			if bb.bup == nil {
  1121  				return bb
  1122  			}
  1123  			b = bb.bup
  1124  		case *tbranchElement:
  1125  			if bb.bup == nil {
  1126  				return bb
  1127  			}
  1128  			b = bb.bup
  1129  		default:
  1130  			panic(fmt.Errorf("rtree: unknown branch type %T", b))
  1131  		}
  1132  	}
  1133  	panic("impossible")
  1134  }
  1135  
  1136  func init() {
  1137  	{
  1138  		f := func() reflect.Value {
  1139  			o := &tbranch{}
  1140  			return reflect.ValueOf(o)
  1141  		}
  1142  		rtypes.Factory.Add("TBranch", f)
  1143  	}
  1144  	{
  1145  		f := func() reflect.Value {
  1146  			o := &tbranchObject{}
  1147  			return reflect.ValueOf(o)
  1148  		}
  1149  		rtypes.Factory.Add("TBranchObject", f)
  1150  	}
  1151  	{
  1152  		f := func() reflect.Value {
  1153  			o := &tbranchElement{}
  1154  			return reflect.ValueOf(o)
  1155  		}
  1156  		rtypes.Factory.Add("TBranchElement", f)
  1157  	}
  1158  }
  1159  
  1160  type basketCtx struct {
  1161  	id    int     // current basket number when reading
  1162  	entry int64   // current entry number when reading
  1163  	first int64   // first entry in the current basket
  1164  	next  int64   // next entry that will require us to go to TBranchElement next basket
  1165  	bk    *Basket // pointer to the current basket
  1166  	buf   []byte  // scratch space for the current basket
  1167  
  1168  	keylen uint32
  1169  }
  1170  
  1171  func (ctx *basketCtx) inflate(bufsz int, seek int64, f *riofs.File) error {
  1172  	ctx.buf = rbytes.ResizeU8(ctx.buf, bufsz)
  1173  	ctx.bk.key.SetFile(f)
  1174  	ctx.keylen = 0
  1175  
  1176  	var (
  1177  		bk    = ctx.bk
  1178  		buf   = ctx.buf[:bufsz]
  1179  		sictx = f
  1180  		err   error
  1181  	)
  1182  
  1183  	switch {
  1184  	case len(buf) == 0 && ctx.bk != nil: // FIXME(sbinet): from trial and error. check this is ok for all cases
  1185  
  1186  	default:
  1187  		_, err = f.ReadAt(buf, seek)
  1188  		if err != nil {
  1189  			return fmt.Errorf("rtree: could not read basket buffer from file: %w", err)
  1190  		}
  1191  
  1192  		err = bk.UnmarshalROOT(rbytes.NewRBuffer(buf, nil, 0, sictx))
  1193  		if err != nil {
  1194  			return fmt.Errorf("rtree: could not unmarshal basket buffer from file: %w", err)
  1195  		}
  1196  
  1197  		ctx.keylen = uint32(bk.key.KeyLen())
  1198  	}
  1199  
  1200  	buf = rbytes.ResizeU8(buf, int(bk.key.ObjLen()))
  1201  	_, err = bk.key.Load(buf)
  1202  	if err != nil {
  1203  		return err
  1204  	}
  1205  
  1206  	bk.rbuf = rbytes.NewRBuffer(buf, nil, ctx.keylen, sictx)
  1207  	return nil
  1208  }
  1209  
  1210  var (
  1211  	_ root.Object        = (*tbranch)(nil)
  1212  	_ root.Named         = (*tbranch)(nil)
  1213  	_ Branch             = (*tbranch)(nil)
  1214  	_ rbytes.Marshaler   = (*tbranch)(nil)
  1215  	_ rbytes.Unmarshaler = (*tbranch)(nil)
  1216  
  1217  	_ root.Object        = (*tbranchObject)(nil)
  1218  	_ root.Named         = (*tbranchObject)(nil)
  1219  	_ Branch             = (*tbranchObject)(nil)
  1220  	_ rbytes.Marshaler   = (*tbranchObject)(nil)
  1221  	_ rbytes.Unmarshaler = (*tbranchObject)(nil)
  1222  
  1223  	_ root.Object        = (*tbranchElement)(nil)
  1224  	_ root.Named         = (*tbranchElement)(nil)
  1225  	_ Branch             = (*tbranchElement)(nil)
  1226  	_ rbytes.Marshaler   = (*tbranchElement)(nil)
  1227  	_ rbytes.Unmarshaler = (*tbranchElement)(nil)
  1228  )