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

     1  // Copyright ©2019 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  	"compress/flate"
     9  	"fmt"
    10  	"io"
    11  	"math/rand"
    12  	"os"
    13  	"path"
    14  	"path/filepath"
    15  	"reflect"
    16  	"strings"
    17  	"testing"
    18  
    19  	"go-hep.org/x/hep/groot/internal/rtests"
    20  	"go-hep.org/x/hep/groot/rbase"
    21  	"go-hep.org/x/hep/groot/rbytes"
    22  	"go-hep.org/x/hep/groot/rdict"
    23  	"go-hep.org/x/hep/groot/riofs"
    24  	"go-hep.org/x/hep/groot/root"
    25  	"go-hep.org/x/hep/groot/rtypes"
    26  	"go-hep.org/x/hep/internal/diff"
    27  )
    28  
    29  func TestBasketRW(t *testing.T) {
    30  	tmp, err := os.MkdirTemp("", "groot-rtree-")
    31  	if err != nil {
    32  		t.Fatalf("could not create temporary directory: %v", err)
    33  	}
    34  	f, err := riofs.Create(filepath.Join(tmp, "basket.root"))
    35  	if err != nil {
    36  		t.Fatalf("could not create temporary file: %v", err)
    37  	}
    38  	defer f.Close()
    39  	defer os.RemoveAll(tmp)
    40  
    41  	dir, err := f.Mkdir("data")
    42  	if err != nil {
    43  		t.Fatalf("could not create TDirectory: %v", err)
    44  	}
    45  
    46  	var (
    47  		signed = false
    48  		branch = &tbranch{
    49  			named: *rbase.NewNamed("b1", "branch1"),
    50  		}
    51  		leaf = newLeafI(branch, "I32", nil, signed, nil)
    52  	)
    53  	branch.leaves = append(branch.leaves, leaf)
    54  
    55  	for _, tc := range []struct {
    56  		basket Basket
    57  	}{
    58  		{
    59  			basket: Basket{
    60  				key:    riofs.KeyFromDir(dir, "empty", "title", "TBasket"),
    61  				branch: branch,
    62  			},
    63  		},
    64  		{
    65  			basket: Basket{
    66  				key:     riofs.KeyFromDir(dir, "simple", "title", "TBasket"),
    67  				bufsize: 5,
    68  				nevsize: 4,
    69  				nevbuf:  3,
    70  				last:    0,
    71  				branch:  branch,
    72  			},
    73  		},
    74  		{
    75  			basket: Basket{
    76  				key:     riofs.KeyFromDir(dir, "with-iobits", "title", "TBasket"),
    77  				bufsize: 5,
    78  				nevsize: 4,
    79  				nevbuf:  3,
    80  				last:    0,
    81  				iobits:  1,
    82  				branch:  branch,
    83  			},
    84  		},
    85  		{
    86  			basket: Basket{
    87  				key:     riofs.KeyFromDir(dir, "with-offsets", "title", "TBasket"),
    88  				bufsize: 5,
    89  				nevsize: 4,
    90  				nevbuf:  4,
    91  				last:    0,
    92  				iobits:  1,
    93  				offsets: []int32{1, 2, 3, 4},
    94  				branch:  branch,
    95  			},
    96  		},
    97  		{
    98  			basket: Basket{
    99  				key:     riofs.KeyFromDir(dir, "with-offsets-displ", "title", "TBasket"),
   100  				bufsize: 5,
   101  				nevsize: 4,
   102  				nevbuf:  4,
   103  				last:    0,
   104  				iobits:  1,
   105  				displ:   []int32{0x11, 0x12, 0x13, 0x14},
   106  				offsets: []int32{1, 2, 3, 4},
   107  				branch:  branch,
   108  			},
   109  		},
   110  		{
   111  			basket: Basket{
   112  				key:     riofs.KeyFromDir(dir, "with-buffer-ref", "title", "TBasket"),
   113  				bufsize: 5,
   114  				nevsize: 4,
   115  				nevbuf:  4,
   116  				last:    1,
   117  				iobits:  1,
   118  				branch:  branch,
   119  				wbuf:    rbytes.NewWBuffer([]byte{42}, nil, 0, nil),
   120  			},
   121  		},
   122  	} {
   123  		t.Run(tc.basket.Name(), func(t *testing.T) {
   124  			wbuf := rbytes.NewWBuffer(nil, nil, 0, nil)
   125  
   126  			var wantBufRef []byte
   127  			if tc.basket.wbuf != nil {
   128  				tc.basket.wbuf.SetPos(int64(tc.basket.last))
   129  				want := tc.basket.wbuf.Bytes()
   130  				wantBufRef = make([]byte, len(want))
   131  				copy(wantBufRef, want)
   132  			}
   133  
   134  			n, err := tc.basket.MarshalROOT(wbuf)
   135  			if err != nil {
   136  				t.Fatalf("could not marshal basket: n=%d err=%v", n, err)
   137  			}
   138  
   139  			rbuf := rbytes.NewRBuffer(wbuf.Bytes(), nil, 0, nil)
   140  			var b Basket
   141  			err = b.UnmarshalROOT(rbuf)
   142  			if err != nil {
   143  				t.Fatalf("could not unmarshal basket: %v", err)
   144  			}
   145  			b.branch = branch
   146  
   147  			for _, tt := range []struct {
   148  				name      string
   149  				got, want any
   150  			}{
   151  				{"bufsize", b.bufsize, tc.basket.bufsize},
   152  				{"nevsize", b.nevsize, tc.basket.nevsize},
   153  				{"nevbuf", b.nevbuf, tc.basket.nevbuf},
   154  				{"last", b.last, tc.basket.last},
   155  				{"header", b.header, tc.basket.header},
   156  				{"iobits", b.iobits, tc.basket.iobits},
   157  				{"displ", b.displ, tc.basket.displ},
   158  				{"offsets", b.offsets, tc.basket.offsets},
   159  			} {
   160  				if !reflect.DeepEqual(tt.got, tt.want) {
   161  					t.Fatalf("invalid round-trip for %s:\ngot= %#v\nwant=%#v", tt.name, tt.got, tt.want)
   162  				}
   163  			}
   164  
   165  			if wantBufRef != nil {
   166  				raw, err := b.key.Bytes()
   167  				if err != nil {
   168  					t.Fatalf("could not unpack key payload: %v", err)
   169  				}
   170  				if got, want := raw, wantBufRef; !reflect.DeepEqual(got, want) {
   171  					t.Fatalf("invalid-roundtrip for wbuf:\ngot= %v\nwant=%v", got, want)
   172  				}
   173  			}
   174  		})
   175  	}
   176  
   177  }
   178  
   179  func TestIOFeaturesRW(t *testing.T) {
   180  	for _, tc := range []struct {
   181  		name string
   182  		want tioFeatures
   183  	}{
   184  		{"io-0x00", 0x00},
   185  		{"io-0x01", 0x01},
   186  		{"io-0x02", 0x02},
   187  		{"io-0x03", 0x03},
   188  		{"io-0xff", 0xff},
   189  	} {
   190  		t.Run(tc.name, func(t *testing.T) {
   191  			wbuf := rbytes.NewWBuffer(nil, nil, 0, nil)
   192  
   193  			n, err := tc.want.MarshalROOT(wbuf)
   194  			if err != nil {
   195  				t.Fatalf("could not marshal IOFeatures: n=%d err=%v", n, err)
   196  			}
   197  
   198  			rbuf := rbytes.NewRBuffer(wbuf.Bytes(), nil, 0, nil)
   199  			var got tioFeatures
   200  			err = got.UnmarshalROOT(rbuf)
   201  			if err != nil {
   202  				t.Fatalf("could not unmarshal IOFeatures: %v", err)
   203  			}
   204  
   205  			if !reflect.DeepEqual(tc.want, got) {
   206  				t.Fatalf("invalid round-trip: got=%x, want=%x", got, tc.want)
   207  			}
   208  		})
   209  	}
   210  }
   211  
   212  func TestBranchRW(t *testing.T) {
   213  	const (
   214  		unsigned = true
   215  		signed   = false
   216  	)
   217  
   218  	tmp, err := os.MkdirTemp("", "groot-rtree-")
   219  	if err != nil {
   220  		t.Fatalf("could not create temporary directory: %v", err)
   221  	}
   222  	f, err := riofs.Create(filepath.Join(tmp, "basket.root"))
   223  	if err != nil {
   224  		t.Fatalf("could not create temporary file: %v", err)
   225  	}
   226  	defer f.Close()
   227  	defer os.RemoveAll(tmp)
   228  
   229  	dir, err := f.Mkdir("data")
   230  	if err != nil {
   231  		t.Fatalf("could not create TDirectory: %v", err)
   232  	}
   233  
   234  	for _, tc := range []struct {
   235  		name string
   236  		want rtests.ROOTer
   237  	}{
   238  		{
   239  			name: "TBranch",
   240  			want: &tbranch{
   241  				named:          *rbase.NewNamed("branch", "leaf1/I"),
   242  				attfill:        *rbase.NewAttFill(),
   243  				compress:       1,
   244  				basketSize:     defaultBasketSize,
   245  				entryOffsetLen: 0,
   246  				writeBasket:    1,
   247  				entryNumber:    4,
   248  				iobits:         0,
   249  				offset:         0,
   250  				maxBaskets:     10,
   251  				splitLevel:     1,
   252  				entries:        4,
   253  				firstEntry:     0,
   254  				totBytes:       86,
   255  				zipBytes:       86,
   256  				branches:       []Branch{},
   257  				leaves:         []Leaf{},
   258  				baskets:        []Basket{},
   259  				basketBytes:    []int32{86},
   260  				basketEntry:    []int64{0, 4},
   261  				basketSeek:     []int64{304},
   262  				fname:          "foo.root",
   263  
   264  				//
   265  				ctx: basketCtx{
   266  					entry: -1,
   267  					first: -1,
   268  					next:  -1,
   269  				},
   270  			},
   271  		},
   272  		{
   273  			name: "TBranch-with-leaves",
   274  			want: &tbranch{
   275  				named:          *rbase.NewNamed("branch", "leaf1/I:leaf2/L:leaf3/G"),
   276  				attfill:        *rbase.NewAttFill(),
   277  				compress:       1,
   278  				basketSize:     defaultBasketSize,
   279  				entryOffsetLen: 0,
   280  				writeBasket:    1,
   281  				entryNumber:    4,
   282  				iobits:         0,
   283  				offset:         0,
   284  				maxBaskets:     10,
   285  				splitLevel:     1,
   286  				entries:        4,
   287  				firstEntry:     0,
   288  				totBytes:       86,
   289  				zipBytes:       86,
   290  				branches:       []Branch{},
   291  				leaves: []Leaf{
   292  					newLeafI(nil, "leaf1", nil, signed, nil),
   293  					newLeafL(nil, "leaf2", nil, signed, nil),
   294  					newLeafG(nil, "leaf3", nil, signed, nil),
   295  				},
   296  				baskets:     []Basket{},
   297  				basketBytes: []int32{86},
   298  				basketEntry: []int64{0, 4},
   299  				basketSeek:  []int64{304},
   300  				fname:       "foo.root",
   301  
   302  				//
   303  				ctx: basketCtx{
   304  					entry: -1,
   305  					first: -1,
   306  					next:  -1,
   307  				},
   308  			},
   309  		},
   310  		{
   311  			name: "TBranch-with-baskets",
   312  			want: &tbranch{
   313  				named:          *rbase.NewNamed("branch", "leaf1/I:leaf2/L:leaf3/G"),
   314  				attfill:        *rbase.NewAttFill(),
   315  				compress:       1,
   316  				basketSize:     defaultBasketSize,
   317  				entryOffsetLen: 0,
   318  				writeBasket:    1,
   319  				entryNumber:    4,
   320  				iobits:         0,
   321  				offset:         0,
   322  				maxBaskets:     10,
   323  				splitLevel:     1,
   324  				entries:        4,
   325  				firstEntry:     0,
   326  				totBytes:       86,
   327  				zipBytes:       86,
   328  				branches:       []Branch{},
   329  				leaves: []Leaf{
   330  					newLeafI(nil, "leaf1", nil, signed, nil),
   331  					newLeafL(nil, "leaf2", nil, signed, nil),
   332  					newLeafG(nil, "leaf3", nil, signed, nil),
   333  				},
   334  				baskets: []Basket{
   335  					{
   336  						key:     riofs.KeyFromDir(dir, "with-offsets", "title", "TBasket"),
   337  						bufsize: 5,
   338  						nevsize: 4,
   339  						nevbuf:  4,
   340  						last:    0,
   341  						iobits:  1,
   342  						offsets: []int32{1, 2, 3, 4},
   343  						branch:  nil,
   344  					},
   345  				},
   346  				basketBytes: []int32{86},
   347  				basketEntry: []int64{0, 4},
   348  				basketSeek:  []int64{304},
   349  				fname:       "foo.root",
   350  
   351  				//
   352  				ctx: basketCtx{
   353  					entry: -1,
   354  					first: -1,
   355  					next:  -1,
   356  				},
   357  			},
   358  		},
   359  		{
   360  			name: "TBranchElement",
   361  			want: &tbranchElement{
   362  				tbranch: tbranch{
   363  					named:          *rbase.NewNamed("branch", "leaf1/I:leaf2/L:leaf3/G"),
   364  					attfill:        *rbase.NewAttFill(),
   365  					compress:       1,
   366  					basketSize:     defaultBasketSize,
   367  					entryOffsetLen: 0,
   368  					writeBasket:    1,
   369  					entryNumber:    4,
   370  					iobits:         0,
   371  					offset:         0,
   372  					maxBaskets:     10,
   373  					splitLevel:     1,
   374  					entries:        4,
   375  					firstEntry:     0,
   376  					totBytes:       86,
   377  					zipBytes:       86,
   378  					branches:       []Branch{},
   379  					leaves: []Leaf{
   380  						newLeafI(nil, "leaf1", nil, signed, nil),
   381  						newLeafL(nil, "leaf2", nil, signed, nil),
   382  						newLeafG(nil, "leaf3", nil, signed, nil),
   383  					},
   384  					baskets: []Basket{
   385  						{
   386  							key:     riofs.KeyFromDir(dir, "with-offsets", "title", "TBasket"),
   387  							bufsize: 5,
   388  							nevsize: 4,
   389  							nevbuf:  4,
   390  							last:    0,
   391  							iobits:  1,
   392  							offsets: []int32{1, 2, 3, 4},
   393  							branch:  nil,
   394  						},
   395  					},
   396  					basketBytes: []int32{86},
   397  					basketEntry: []int64{0, 4},
   398  					basketSeek:  []int64{304},
   399  					fname:       "foo.root",
   400  
   401  					//
   402  					ctx: basketCtx{
   403  						entry: -1,
   404  						first: -1,
   405  						next:  -1,
   406  					},
   407  				},
   408  				class:  "myclass",
   409  				parent: "parentclass",
   410  				clones: "clones",
   411  				chksum: 123456789,
   412  				clsver: 42,
   413  				id:     3,
   414  				btype:  4,
   415  				stype:  5,
   416  				max:    42,
   417  				//stltyp: 45,
   418  			},
   419  		},
   420  		{
   421  			name: "TBranchElement-with-bcount1",
   422  			want: &tbranchElement{
   423  				tbranch: tbranch{
   424  					named:          *rbase.NewNamed("branch", "leaf1/I:leaf2/L:leaf3/G"),
   425  					attfill:        *rbase.NewAttFill(),
   426  					compress:       1,
   427  					basketSize:     defaultBasketSize,
   428  					entryOffsetLen: 0,
   429  					writeBasket:    1,
   430  					entryNumber:    4,
   431  					iobits:         0,
   432  					offset:         0,
   433  					maxBaskets:     10,
   434  					splitLevel:     1,
   435  					entries:        4,
   436  					firstEntry:     0,
   437  					totBytes:       86,
   438  					zipBytes:       86,
   439  					branches:       []Branch{},
   440  					leaves: []Leaf{
   441  						newLeafI(nil, "leaf1", nil, signed, nil),
   442  						newLeafL(nil, "leaf2", nil, signed, nil),
   443  						newLeafG(nil, "leaf3", nil, signed, nil),
   444  					},
   445  					baskets: []Basket{
   446  						{
   447  							key:     riofs.KeyFromDir(dir, "with-offsets", "title", "TBasket"),
   448  							bufsize: 5,
   449  							nevsize: 4,
   450  							nevbuf:  4,
   451  							last:    0,
   452  							iobits:  1,
   453  							offsets: []int32{1, 2, 3, 4},
   454  							branch:  nil,
   455  						},
   456  					},
   457  					basketBytes: []int32{86},
   458  					basketEntry: []int64{0, 4},
   459  					basketSeek:  []int64{304},
   460  					fname:       "foo.root",
   461  
   462  					//
   463  					ctx: basketCtx{
   464  						entry: -1,
   465  						first: -1,
   466  						next:  -1,
   467  					},
   468  				},
   469  				class:  "myclass",
   470  				parent: "parentclass",
   471  				clones: "clones",
   472  				chksum: 123456789,
   473  				clsver: 42,
   474  				id:     3,
   475  				btype:  4,
   476  				stype:  5,
   477  				max:    42,
   478  				//stltyp: 45,
   479  				bcount1: &tbranchElement{
   480  					tbranch: tbranch{
   481  						named:          *rbase.NewNamed("count", "leaf1/I"),
   482  						attfill:        *rbase.NewAttFill(),
   483  						compress:       1,
   484  						basketSize:     defaultBasketSize,
   485  						entryOffsetLen: 0,
   486  						writeBasket:    1,
   487  						entryNumber:    4,
   488  						iobits:         0,
   489  						offset:         0,
   490  						maxBaskets:     10,
   491  						splitLevel:     1,
   492  						entries:        4,
   493  						firstEntry:     0,
   494  						totBytes:       86,
   495  						zipBytes:       86,
   496  						branches:       []Branch{},
   497  						leaves: []Leaf{
   498  							newLeafI(nil, "leaf1", nil, signed, nil),
   499  						},
   500  						baskets: []Basket{
   501  							{
   502  								key:     riofs.KeyFromDir(dir, "with-offsets", "title", "TBasket"),
   503  								bufsize: 5,
   504  								nevsize: 4,
   505  								nevbuf:  4,
   506  								last:    0,
   507  								iobits:  1,
   508  								offsets: []int32{1, 2, 3, 4},
   509  								branch:  nil,
   510  							},
   511  						},
   512  						basketBytes: []int32{86},
   513  						basketEntry: []int64{0, 4},
   514  						basketSeek:  []int64{304},
   515  						fname:       "foo.root",
   516  
   517  						//
   518  						ctx: basketCtx{
   519  							entry: -1,
   520  							first: -1,
   521  							next:  -1,
   522  						},
   523  					},
   524  					class:  "myotherclass",
   525  					parent: "parentclass",
   526  					clones: "clones",
   527  					chksum: 123456789,
   528  					clsver: 42,
   529  					id:     3,
   530  					btype:  4,
   531  					stype:  5,
   532  					max:    42,
   533  					// stltyp: 45,
   534  				},
   535  			},
   536  		},
   537  	} {
   538  		t.Run(tc.name, func(t *testing.T) {
   539  			{
   540  				wbuf := rbytes.NewWBuffer(nil, nil, 0, nil)
   541  				wbuf.SetErr(io.EOF)
   542  				_, err := tc.want.MarshalROOT(wbuf)
   543  				if err == nil {
   544  					t.Fatalf("expected an error")
   545  				}
   546  				if err != io.EOF {
   547  					t.Fatalf("got=%v, want=%v", err, io.EOF)
   548  				}
   549  			}
   550  
   551  			asTBranch := func(b any) *tbranch {
   552  				switch b := b.(type) {
   553  				case *tbranch:
   554  					return b
   555  				case *tbranchElement:
   556  					return &b.tbranch
   557  				}
   558  				panic("impossible")
   559  			}
   560  
   561  			setupInput := func(b any) {
   562  				if b := asTBranch(b); len(b.leaves) != 0 {
   563  					for i := range b.leaves {
   564  						b.leaves[i].setBranch(b)
   565  					}
   566  				}
   567  				if b := asTBranch(tc.want); len(b.baskets) != 0 {
   568  					for i := range b.baskets {
   569  						b.baskets[i].branch = b
   570  					}
   571  				}
   572  
   573  			}
   574  
   575  			setupInput(tc.want)
   576  
   577  			if b, ok := tc.want.(*tbranchElement); ok {
   578  				if b.bcount1 != nil {
   579  					setupInput(b.bcount1)
   580  				}
   581  			}
   582  
   583  			wbuf := rbytes.NewWBuffer(nil, nil, 0, nil)
   584  			_, err := tc.want.MarshalROOT(wbuf)
   585  			if err != nil {
   586  				t.Fatalf("could not marshal ROOT: %v", err)
   587  			}
   588  
   589  			rbuf := rbytes.NewRBuffer(wbuf.Bytes(), nil, 0, nil)
   590  			class := tc.want.Class()
   591  			obj := rtypes.Factory.Get(class)().Interface().(rbytes.Unmarshaler)
   592  			{
   593  				rbuf.SetErr(io.EOF)
   594  				err = obj.UnmarshalROOT(rbuf)
   595  				if err == nil {
   596  					t.Fatalf("expected an error")
   597  				}
   598  				if err != io.EOF {
   599  					t.Fatalf("got=%v, want=%v", err, io.EOF)
   600  				}
   601  				rbuf.SetErr(nil)
   602  			}
   603  			err = obj.UnmarshalROOT(rbuf)
   604  			if err != nil {
   605  				t.Fatalf("could not unmarshal ROOT: %v", err)
   606  			}
   607  
   608  			if b := asTBranch(obj); len(b.baskets) != 0 {
   609  				for i := range b.baskets {
   610  					b.baskets[i].branch = b
   611  					b.baskets[i].key = asTBranch(tc.want).baskets[i].key
   612  				}
   613  			}
   614  
   615  			if b, ok := obj.(*tbranchElement); ok {
   616  
   617  				want := tc.want.(*tbranchElement)
   618  				if want.bcount1 != nil {
   619  					for i := range b.bcount1.baskets {
   620  						b.bcount1.baskets[i].branch = want.bcount1.baskets[i].branch
   621  						b.bcount1.baskets[i].key = want.bcount1.baskets[i].key
   622  					}
   623  				}
   624  
   625  				var cmpTBE func(n string, got, want *tbranchElement)
   626  				cmpTBE = func(n string, got, want *tbranchElement) {
   627  					if got == nil && want == nil {
   628  						return
   629  					}
   630  					if got == nil && want != nil {
   631  						t.Fatalf("got=%v, want=%v", got, want)
   632  					}
   633  					if got != nil && want == nil {
   634  						t.Fatalf("got=%v, want=%v", got, want)
   635  					}
   636  
   637  					for i, v := range []struct {
   638  						got, want any
   639  					}{
   640  						{got.tbranch, want.tbranch},
   641  						{got.class, want.class},
   642  						{got.parent, want.parent},
   643  						{got.clones, want.clones},
   644  						{got.chksum, want.chksum},
   645  						{got.clsver, want.clsver},
   646  						{got.id, want.id},
   647  						{got.btype, want.btype},
   648  						{got.stype, want.stype},
   649  						{got.max, want.max},
   650  						{got.stltyp, want.stltyp},
   651  						{got.streamer, want.streamer},
   652  						{got.estreamer, want.estreamer},
   653  					} {
   654  						if !reflect.DeepEqual(v.got, v.want) {
   655  							t.Fatalf("error[%s-%d]\ngot= %+v\nwant=%+v\n", n, i, v.got, v.want)
   656  						}
   657  					}
   658  					cmpTBE("bcount1", got.bcount1, want.bcount1)
   659  					cmpTBE("bcount2", got.bcount2, want.bcount2)
   660  				}
   661  				cmpTBE("master", b, want)
   662  				return
   663  			}
   664  
   665  			if !reflect.DeepEqual(obj, tc.want) {
   666  				t.Fatalf("error\ngot= %+v\nwant=%+v\n", obj, tc.want)
   667  			}
   668  		})
   669  	}
   670  }
   671  
   672  func TestTreeRW(t *testing.T) {
   673  	tmp, err := os.MkdirTemp("", "groot-rtree-")
   674  	if err != nil {
   675  		t.Fatalf("could not create dir: %v", err)
   676  	}
   677  	defer os.RemoveAll(tmp)
   678  
   679  	const (
   680  		treeName = "mytree"
   681  	)
   682  
   683  	for _, tc := range []struct {
   684  		name    string
   685  		skip    bool
   686  		wopts   []WriteOption
   687  		nevts   int64
   688  		wvars   []WriteVar
   689  		btitles []string
   690  		ltitles []string
   691  		total   int
   692  		want    func(i int) any
   693  		scan    []string // list of branches to use for ROOT TTree::Scan
   694  		cxx     string   // expected ROOT-TTree::Scan
   695  	}{
   696  		{
   697  			name:    "empty",
   698  			nevts:   5,
   699  			wvars:   []WriteVar{},
   700  			btitles: []string{},
   701  			ltitles: []string{},
   702  			total:   5 * (0),
   703  			want:    func(i int) any { return nil },
   704  			cxx: `************
   705  *    Row   *
   706  ************
   707  *        0 *
   708  *        1 *
   709  *        2 *
   710  *        3 *
   711  *        4 *
   712  ************
   713  `,
   714  		},
   715  		{
   716  			name:  "simple",
   717  			nevts: 5,
   718  			wvars: []WriteVar{
   719  				{Name: "i32", Value: new(int32)},
   720  				{Name: "f64", Value: new(float64)},
   721  			},
   722  			btitles: []string{"i32/I", "f64/D"},
   723  			ltitles: []string{"i32", "f64"},
   724  			total:   5 * (4 + 8),
   725  			want: func(i int) any {
   726  				return struct {
   727  					I32 int32
   728  					F64 float64
   729  				}{
   730  					I32: int32(i),
   731  					F64: float64(i),
   732  				}
   733  			},
   734  			cxx: `************************************
   735  *    Row   *   i32.i32 *   f64.f64 *
   736  ************************************
   737  *        0 *         0 *         0 *
   738  *        1 *         1 *         1 *
   739  *        2 *         2 *         2 *
   740  *        3 *         3 *         3 *
   741  *        4 *         4 *         4 *
   742  ************************************
   743  `,
   744  		},
   745  		{
   746  			name:  "builtins",
   747  			nevts: 5,
   748  			wvars: []WriteVar{
   749  				{Name: "B", Value: new(bool)},
   750  				{Name: "I8", Value: new(int8)},
   751  				{Name: "I16", Value: new(int16)},
   752  				{Name: "I32", Value: new(int32)},
   753  				{Name: "I64", Value: new(int64)},
   754  				{Name: "U8", Value: new(uint8)},
   755  				{Name: "U16", Value: new(uint16)},
   756  				{Name: "U32", Value: new(uint32)},
   757  				{Name: "U64", Value: new(uint64)},
   758  				{Name: "F32", Value: new(float32)},
   759  				{Name: "F64", Value: new(float64)},
   760  				{Name: "D16", Value: new(root.Float16)},
   761  				{Name: "D32", Value: new(root.Double32)},
   762  			},
   763  			btitles: []string{
   764  				"B/O",
   765  				"I8/B", "I16/S", "I32/I", "I64/L",
   766  				"U8/b", "U16/s", "U32/i", "U64/l",
   767  				"F32/F", "F64/D", "D16/f", "D32/d",
   768  			},
   769  			ltitles: []string{
   770  				"B",
   771  				"I8", "I16", "I32", "I64",
   772  				"U8", "U16", "U32", "U64",
   773  				"F32", "F64", "D16", "D32",
   774  			},
   775  			total: 5 * 50,
   776  			want: func(i int) any {
   777  				return struct {
   778  					B   bool
   779  					I8  int8
   780  					I16 int16
   781  					I32 int32
   782  					I64 int64
   783  					U8  uint8
   784  					U16 uint16
   785  					U32 uint32
   786  					U64 uint64
   787  					F32 float32
   788  					F64 float64
   789  					D16 root.Float16
   790  					D32 root.Double32
   791  				}{
   792  					B:   bool(i%2 == 0),
   793  					I8:  int8(i),
   794  					I16: int16(i),
   795  					I32: int32(i),
   796  					I64: int64(i),
   797  					U8:  uint8(i),
   798  					U16: uint16(i),
   799  					U32: uint32(i),
   800  					U64: uint64(i),
   801  					F32: float32(i),
   802  					F64: float64(i),
   803  					D16: root.Float16(i),
   804  					D32: root.Double32(i),
   805  				}
   806  			},
   807  			cxx: `************************************************************************************************************************************************************************
   808  *    Row   *       B.B *     I8.I8 *   I16.I16 *   I32.I32 *   I64.I64 *     U8.U8 *   U16.U16 *   U32.U32 *   U64.U64 *   F32.F32 *   F64.F64 *   D16.D16 *   D32.D32 *
   809  ************************************************************************************************************************************************************************
   810  *        0 *         1 *         0 *         0 *         0 *         0 *         0 *         0 *         0 *         0 *         0 *         0 *         0 *         0 *
   811  *        1 *         0 *         1 *         1 *         1 *         1 *         1 *         1 *         1 *         1 *         1 *         1 *         1 *         1 *
   812  *        2 *         1 *         2 *         2 *         2 *         2 *         2 *         2 *         2 *         2 *         2 *         2 *         2 *         2 *
   813  *        3 *         0 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *
   814  *        4 *         1 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *
   815  ************************************************************************************************************************************************************************
   816  `,
   817  		},
   818  		{
   819  			name:  "strings",
   820  			nevts: 5,
   821  			wvars: []WriteVar{
   822  				{Name: "i32", Value: new(int32)},
   823  				{Name: "f64", Value: new(float64)},
   824  				{Name: "str", Value: new(string)},
   825  			},
   826  			btitles: []string{"i32/I", "f64/D", "str/C"},
   827  			ltitles: []string{"i32", "f64", "str"},
   828  			total:   5 * (4 + 8 + (3 + 1)), // 3: strings are "xxx" + 1:string-size
   829  			want: func(i int) any {
   830  				return struct {
   831  					I32 int32
   832  					F64 float64
   833  					Str string
   834  				}{
   835  					I32: int32(i),
   836  					F64: float64(i),
   837  					Str: fmt.Sprintf("%03d", i),
   838  				}
   839  			},
   840  			cxx: `************************************************
   841  *    Row   *   i32.i32 *   f64.f64 *   str.str *
   842  ************************************************
   843  *        0 *         0 *         0 *       000 *
   844  *        1 *         1 *         1 *       001 *
   845  *        2 *         2 *         2 *       002 *
   846  *        3 *         3 *         3 *       003 *
   847  *        4 *         4 *         4 *       004 *
   848  ************************************************
   849  `,
   850  		},
   851  		{
   852  			name:  "strings-empty",
   853  			nevts: 5,
   854  			wvars: []WriteVar{
   855  				{Name: "s1", Value: new(string)},
   856  				{Name: "s2", Value: new(string)},
   857  			},
   858  			btitles: []string{"s1/C", "s2/C"},
   859  			ltitles: []string{"s1", "s2"},
   860  			total:   30,
   861  			want: func(i int) any {
   862  				return struct {
   863  					S1 string
   864  					S2 string
   865  				}{
   866  					S1: strings.Repeat("x", 4-i),
   867  					S2: strings.Repeat("x", i),
   868  				}
   869  			},
   870  			cxx: `************************************
   871  *    Row   *     s1.s1 *     s2.s2 *
   872  ************************************
   873  *        0 *      xxxx *           *
   874  *        1 *       xxx *         x *
   875  *        2 *        xx *        xx *
   876  *        3 *         x *       xxx *
   877  *        4 *           *      xxxx *
   878  ************************************
   879  `,
   880  		},
   881  		{
   882  			name:  "arrays",
   883  			nevts: 5,
   884  			wvars: []WriteVar{
   885  				{Name: "ArrB", Value: new([5]bool)},
   886  				{Name: "ArrI8", Value: new([5]int8)},
   887  				{Name: "ArrI16", Value: new([5]int16)},
   888  				{Name: "ArrI32", Value: new([5]int32)},
   889  				{Name: "ArrI64", Value: new([5]int64)},
   890  				{Name: "ArrU8", Value: new([5]uint8)},
   891  				{Name: "ArrU16", Value: new([5]uint16)},
   892  				{Name: "ArrU32", Value: new([5]uint32)},
   893  				{Name: "ArrU64", Value: new([5]uint64)},
   894  				{Name: "ArrF32", Value: new([5]float32)},
   895  				{Name: "ArrF64", Value: new([5]float64)},
   896  			},
   897  			btitles: []string{
   898  				"ArrB[5]/O",
   899  				"ArrI8[5]/B", "ArrI16[5]/S", "ArrI32[5]/I", "ArrI64[5]/L",
   900  				"ArrU8[5]/b", "ArrU16[5]/s", "ArrU32[5]/i", "ArrU64[5]/l",
   901  				"ArrF32[5]/F", "ArrF64[5]/D",
   902  			},
   903  			ltitles: []string{
   904  				"ArrB[5]",
   905  				"ArrI8[5]", "ArrI16[5]", "ArrI32[5]", "ArrI64[5]",
   906  				"ArrU8[5]", "ArrU16[5]", "ArrU32[5]", "ArrU64[5]",
   907  				"ArrF32[5]", "ArrF64[5]",
   908  			},
   909  			total: 5 * 215,
   910  			want: func(i int) any {
   911  				return struct {
   912  					ArrBool [5]bool
   913  					ArrI8   [5]int8
   914  					ArrI16  [5]int16
   915  					ArrI32  [5]int32
   916  					ArrI64  [5]int64
   917  					ArrU8   [5]uint8
   918  					ArrU16  [5]uint16
   919  					ArrU32  [5]uint32
   920  					ArrU64  [5]uint64
   921  					ArrF32  [5]float32
   922  					ArrF64  [5]float64
   923  				}{
   924  					ArrBool: [5]bool{bool(i%2 == 0), bool((i+1)%2 == 0), bool((i+2)%2 == 0), bool((i+3)%2 == 0), bool((i+4)%2 == 0)},
   925  					ArrI8:   [5]int8{'a' + int8(i), int8('a' + i + 1), int8('a' + i + 2), int8('a' + i + 3), int8(0)},
   926  					ArrI16:  [5]int16{int16(i), int16(i + 1), int16(i + 2), int16(i + 3), int16(i + 4)},
   927  					ArrI32:  [5]int32{int32(i), int32(i + 1), int32(i + 2), int32(i + 3), int32(i + 4)},
   928  					ArrI64:  [5]int64{int64(i), int64(i + 1), int64(i + 2), int64(i + 3), int64(i + 4)},
   929  					ArrU8:   [5]uint8{uint8(i), uint8(i + 1), uint8(i + 2), uint8(i + 3), uint8(i + 4)},
   930  					ArrU16:  [5]uint16{uint16(i), uint16(i + 1), uint16(i + 2), uint16(i + 3), uint16(i + 4)},
   931  					ArrU32:  [5]uint32{uint32(i), uint32(i + 1), uint32(i + 2), uint32(i + 3), uint32(i + 4)},
   932  					ArrU64:  [5]uint64{uint64(i), uint64(i + 1), uint64(i + 2), uint64(i + 3), uint64(i + 4)},
   933  					ArrF32:  [5]float32{float32(i), float32(i + 1), float32(i + 2), float32(i + 3), float32(i + 4)},
   934  					ArrF64:  [5]float64{float64(i), float64(i + 1), float64(i + 2), float64(i + 3), float64(i + 4)},
   935  				}
   936  			},
   937  			scan: []string{
   938  				"ArrB",
   939  				"ArrI8", "ArrI16", "ArrI32", "ArrI64",
   940  				"ArrU8", "ArrU16", "ArrU32", "ArrU64",
   941  				"ArrF32", "ArrF64",
   942  			},
   943  			cxx: `***********************************************************************************************************************************************************
   944  *    Row   * Instance *      ArrB *     ArrI8 *    ArrI16 *    ArrI32 *    ArrI64 *     ArrU8 *    ArrU16 *    ArrU32 *    ArrU64 *    ArrF32 *    ArrF64 *
   945  ***********************************************************************************************************************************************************
   946  *        0 *        0 *         1 *      abcd *         0 *         0 *         0 *         0 *         0 *         0 *         0 *         0 *         0 *
   947  *        0 *        1 *         0 *      abcd *         1 *         1 *         1 *         1 *         1 *         1 *         1 *         1 *         1 *
   948  *        0 *        2 *         1 *      abcd *         2 *         2 *         2 *         2 *         2 *         2 *         2 *         2 *         2 *
   949  *        0 *        3 *         0 *      abcd *         3 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *
   950  *        0 *        4 *         1 *      abcd *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *
   951  *        1 *        0 *         0 *      bcde *         1 *         1 *         1 *         1 *         1 *         1 *         1 *         1 *         1 *
   952  *        1 *        1 *         1 *      bcde *         2 *         2 *         2 *         2 *         2 *         2 *         2 *         2 *         2 *
   953  *        1 *        2 *         0 *      bcde *         3 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *
   954  *        1 *        3 *         1 *      bcde *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *
   955  *        1 *        4 *         0 *      bcde *         5 *         5 *         5 *         5 *         5 *         5 *         5 *         5 *         5 *
   956  *        2 *        0 *         1 *      cdef *         2 *         2 *         2 *         2 *         2 *         2 *         2 *         2 *         2 *
   957  *        2 *        1 *         0 *      cdef *         3 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *
   958  *        2 *        2 *         1 *      cdef *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *
   959  *        2 *        3 *         0 *      cdef *         5 *         5 *         5 *         5 *         5 *         5 *         5 *         5 *         5 *
   960  *        2 *        4 *         1 *      cdef *         6 *         6 *         6 *         6 *         6 *         6 *         6 *         6 *         6 *
   961  *        3 *        0 *         0 *      defg *         3 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *
   962  *        3 *        1 *         1 *      defg *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *
   963  *        3 *        2 *         0 *      defg *         5 *         5 *         5 *         5 *         5 *         5 *         5 *         5 *         5 *
   964  *        3 *        3 *         1 *      defg *         6 *         6 *         6 *         6 *         6 *         6 *         6 *         6 *         6 *
   965  *        3 *        4 *         0 *      defg *         7 *         7 *         7 *         7 *         7 *         7 *         7 *         7 *         7 *
   966  *        4 *        0 *         1 *      efgh *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *
   967  *        4 *        1 *         0 *      efgh *         5 *         5 *         5 *         5 *         5 *         5 *         5 *         5 *         5 *
   968  *        4 *        2 *         1 *      efgh *         6 *         6 *         6 *         6 *         6 *         6 *         6 *         6 *         6 *
   969  *        4 *        3 *         0 *      efgh *         7 *         7 *         7 *         7 *         7 *         7 *         7 *         7 *         7 *
   970  *        4 *        4 *         1 *      efgh *         8 *         8 *         8 *         8 *         8 *         8 *         8 *         8 *         8 *
   971  ***********************************************************************************************************************************************************
   972  `,
   973  		},
   974  		{
   975  			name:  "arrays-2d",
   976  			nevts: 5,
   977  			wvars: []WriteVar{
   978  				{Name: "ArrB", Value: new([2][3]bool)},
   979  				{Name: "ArrI8", Value: new([2][3]int8)},
   980  				{Name: "ArrI16", Value: new([2][3]int16)},
   981  				{Name: "ArrI32", Value: new([2][3]int32)},
   982  				{Name: "ArrI64", Value: new([2][3]int64)},
   983  				{Name: "ArrU8", Value: new([2][3]uint8)},
   984  				{Name: "ArrU16", Value: new([2][3]uint16)},
   985  				{Name: "ArrU32", Value: new([2][3]uint32)},
   986  				{Name: "ArrU64", Value: new([2][3]uint64)},
   987  				{Name: "ArrF32", Value: new([2][3]float32)},
   988  				{Name: "ArrF64", Value: new([2][3]float64)},
   989  			},
   990  			btitles: []string{
   991  				"ArrB[2][3]/O",
   992  				"ArrI8[2][3]/B", "ArrI16[2][3]/S", "ArrI32[2][3]/I", "ArrI64[2][3]/L",
   993  				"ArrU8[2][3]/b", "ArrU16[2][3]/s", "ArrU32[2][3]/i", "ArrU64[2][3]/l",
   994  				"ArrF32[2][3]/F", "ArrF64[2][3]/D",
   995  			},
   996  			ltitles: []string{
   997  				"ArrB[2][3]",
   998  				"ArrI8[2][3]", "ArrI16[2][3]", "ArrI32[2][3]", "ArrI64[2][3]",
   999  				"ArrU8[2][3]", "ArrU16[2][3]", "ArrU32[2][3]", "ArrU64[2][3]",
  1000  				"ArrF32[2][3]", "ArrF64[2][3]",
  1001  			},
  1002  			total: 5 * 258,
  1003  			want: func(i int) any {
  1004  				return struct {
  1005  					ArrBool [2][3]bool
  1006  					ArrI8   [2][3]int8
  1007  					ArrI16  [2][3]int16
  1008  					ArrI32  [2][3]int32
  1009  					ArrI64  [2][3]int64
  1010  					ArrU8   [2][3]uint8
  1011  					ArrU16  [2][3]uint16
  1012  					ArrU32  [2][3]uint32
  1013  					ArrU64  [2][3]uint64
  1014  					ArrF32  [2][3]float32
  1015  					ArrF64  [2][3]float64
  1016  				}{
  1017  					ArrBool: [2][3]bool{
  1018  						{bool(i%2 == 0), bool((i+1)%2 == 0), bool((i+2)%2 == 0)},
  1019  						{bool((i+3)%2 == 0), bool((i+4)%2 == 0), bool((i+4)%2 == 0)},
  1020  					},
  1021  					ArrI8: [2][3]int8{
  1022  						{int8(i + 0), int8(i + 1), int8(i + 2)},
  1023  						{int8(i + 3), int8(i + 4), int8(i + 5)},
  1024  					},
  1025  					ArrI16: [2][3]int16{
  1026  						{int16(i + 0), int16(i + 1), int16(i + 2)},
  1027  						{int16(i + 3), int16(i + 4), int16(i + 5)},
  1028  					},
  1029  					ArrI32: [2][3]int32{
  1030  						{int32(i + 0), int32(i + 1), int32(i + 2)},
  1031  						{int32(i + 3), int32(i + 4), int32(i + 5)},
  1032  					},
  1033  					ArrI64: [2][3]int64{
  1034  						{int64(i + 0), int64(i + 1), int64(i + 2)},
  1035  						{int64(i + 3), int64(i + 4), int64(i + 5)},
  1036  					},
  1037  					ArrU8: [2][3]uint8{
  1038  						{uint8(i + 0), uint8(i + 1), uint8(i + 2)},
  1039  						{uint8(i + 3), uint8(i + 4), uint8(i + 5)},
  1040  					},
  1041  					ArrU16: [2][3]uint16{
  1042  						{uint16(i), uint16(i + 1), uint16(i + 2)},
  1043  						{uint16(i + 3), uint16(i + 4), uint16(i + 5)},
  1044  					},
  1045  					ArrU32: [2][3]uint32{
  1046  						{uint32(i + 0), uint32(i + 1), uint32(i + 2)},
  1047  						{uint32(i + 3), uint32(i + 4), uint32(i + 5)},
  1048  					},
  1049  					ArrU64: [2][3]uint64{
  1050  						{uint64(i + 0), uint64(i + 1), uint64(i + 2)},
  1051  						{uint64(i + 3), uint64(i + 4), uint64(i + 5)},
  1052  					},
  1053  					ArrF32: [2][3]float32{
  1054  						{float32(i + 0), float32(i + 1), float32(i + 2)},
  1055  						{float32(i + 3), float32(i + 4), float32(i + 5)},
  1056  					},
  1057  					ArrF64: [2][3]float64{
  1058  						{float64(i + 0), float64(i + 1), float64(i + 2)},
  1059  						{float64(i + 3), float64(i + 4), float64(i + 5)},
  1060  					},
  1061  				}
  1062  			},
  1063  			scan: []string{
  1064  				"ArrB",
  1065  				"ArrI8+0", "ArrI16", "ArrI32", "ArrI64",
  1066  				"ArrU8", "ArrU16", "ArrU32", "ArrU64",
  1067  				"ArrF32", "ArrF64",
  1068  			},
  1069  			cxx: `***********************************************************************************************************************************************************
  1070  *    Row   * Instance *      ArrB *   ArrI8+0 *    ArrI16 *    ArrI32 *    ArrI64 *     ArrU8 *    ArrU16 *    ArrU32 *    ArrU64 *    ArrF32 *    ArrF64 *
  1071  ***********************************************************************************************************************************************************
  1072  *        0 *        0 *         1 *         0 *         0 *         0 *         0 *         0 *         0 *         0 *         0 *         0 *         0 *
  1073  *        0 *        1 *         0 *         1 *         1 *         1 *         1 *         1 *         1 *         1 *         1 *         1 *         1 *
  1074  *        0 *        2 *         1 *         2 *         2 *         2 *         2 *         2 *         2 *         2 *         2 *         2 *         2 *
  1075  *        0 *        3 *         0 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *
  1076  *        0 *        4 *         1 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *
  1077  *        0 *        5 *         1 *         5 *         5 *         5 *         5 *         5 *         5 *         5 *         5 *         5 *         5 *
  1078  *        1 *        0 *         0 *         1 *         1 *         1 *         1 *         1 *         1 *         1 *         1 *         1 *         1 *
  1079  *        1 *        1 *         1 *         2 *         2 *         2 *         2 *         2 *         2 *         2 *         2 *         2 *         2 *
  1080  *        1 *        2 *         0 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *
  1081  *        1 *        3 *         1 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *
  1082  *        1 *        4 *         0 *         5 *         5 *         5 *         5 *         5 *         5 *         5 *         5 *         5 *         5 *
  1083  *        1 *        5 *         0 *         6 *         6 *         6 *         6 *         6 *         6 *         6 *         6 *         6 *         6 *
  1084  *        2 *        0 *         1 *         2 *         2 *         2 *         2 *         2 *         2 *         2 *         2 *         2 *         2 *
  1085  *        2 *        1 *         0 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *
  1086  *        2 *        2 *         1 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *
  1087  *        2 *        3 *         0 *         5 *         5 *         5 *         5 *         5 *         5 *         5 *         5 *         5 *         5 *
  1088  *        2 *        4 *         1 *         6 *         6 *         6 *         6 *         6 *         6 *         6 *         6 *         6 *         6 *
  1089  *        2 *        5 *         1 *         7 *         7 *         7 *         7 *         7 *         7 *         7 *         7 *         7 *         7 *
  1090  *        3 *        0 *         0 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *         3 *
  1091  *        3 *        1 *         1 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *
  1092  *        3 *        2 *         0 *         5 *         5 *         5 *         5 *         5 *         5 *         5 *         5 *         5 *         5 *
  1093  *        3 *        3 *         1 *         6 *         6 *         6 *         6 *         6 *         6 *         6 *         6 *         6 *         6 *
  1094  *        3 *        4 *         0 *         7 *         7 *         7 *         7 *         7 *         7 *         7 *         7 *         7 *         7 *
  1095  *        3 *        5 *         0 *         8 *         8 *         8 *         8 *         8 *         8 *         8 *         8 *         8 *         8 *
  1096  *        4 *        0 *         1 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *         4 *
  1097  *        4 *        1 *         0 *         5 *         5 *         5 *         5 *         5 *         5 *         5 *         5 *         5 *         5 *
  1098  *        4 *        2 *         1 *         6 *         6 *         6 *         6 *         6 *         6 *         6 *         6 *         6 *         6 *
  1099  *        4 *        3 *         0 *         7 *         7 *         7 *         7 *         7 *         7 *         7 *         7 *         7 *         7 *
  1100  *        4 *        4 *         1 *         8 *         8 *         8 *         8 *         8 *         8 *         8 *         8 *         8 *         8 *
  1101  *        4 *        5 *         1 *         9 *         9 *         9 *         9 *         9 *         9 *         9 *         9 *         9 *         9 *
  1102  ***********************************************************************************************************************************************************
  1103  `,
  1104  		},
  1105  		{
  1106  			name:  "slices-uint",
  1107  			nevts: 5,
  1108  			wvars: []WriteVar{
  1109  				{Name: "N", Value: new(int32)},
  1110  				{Name: "SliU8", Value: new([]uint8), Count: "N"},
  1111  				{Name: "SliU16", Value: new([]uint16), Count: "N"},
  1112  				{Name: "SliU32", Value: new([]uint32), Count: "N"},
  1113  				{Name: "SliU64", Value: new([]uint64), Count: "N"},
  1114  			},
  1115  			btitles: []string{
  1116  				"N/I",
  1117  				"SliU8[N]/b", "SliU16[N]/s", "SliU32[N]/i", "SliU64[N]/l",
  1118  			},
  1119  			ltitles: []string{
  1120  				"N",
  1121  				"SliU8[N]", "SliU16[N]", "SliU32[N]", "SliU64[N]",
  1122  			},
  1123  			total: 170,
  1124  			want: func(i int) any {
  1125  				type Data struct {
  1126  					N      int32
  1127  					SliU8  []uint8
  1128  					SliU16 []uint16
  1129  					SliU32 []uint32
  1130  					SliU64 []uint64
  1131  				}
  1132  				return Data{
  1133  					N:      int32(i),
  1134  					SliU8:  []uint8{uint8(i), uint8(i + 1), uint8(i + 2), uint8(i + 3), uint8(i + 4)}[:i],
  1135  					SliU16: []uint16{uint16(i), uint16(i + 1), uint16(i + 2), uint16(i + 3), uint16(i + 4)}[:i],
  1136  					SliU32: []uint32{uint32(i), uint32(i + 1), uint32(i + 2), uint32(i + 3), uint32(i + 4)}[:i],
  1137  					SliU64: []uint64{uint64(i), uint64(i + 1), uint64(i + 2), uint64(i + 3), uint64(i + 4)}[:i],
  1138  				}
  1139  			},
  1140  			scan: []string{
  1141  				"N",
  1142  				"SliU8", "SliU16", "SliU32", "SliU64",
  1143  			},
  1144  			cxx: `***********************************************************************************
  1145  *    Row   * Instance *         N *     SliU8 *    SliU16 *    SliU32 *    SliU64 *
  1146  ***********************************************************************************
  1147  *        0 *        0 *         0 *           *           *           *           *
  1148  *        1 *        0 *         1 *         1 *         1 *         1 *         1 *
  1149  *        2 *        0 *         2 *         2 *         2 *         2 *         2 *
  1150  *        2 *        1 *         2 *         3 *         3 *         3 *         3 *
  1151  *        3 *        0 *         3 *         3 *         3 *         3 *         3 *
  1152  *        3 *        1 *         3 *         4 *         4 *         4 *         4 *
  1153  *        3 *        2 *         3 *         5 *         5 *         5 *         5 *
  1154  *        4 *        0 *         4 *         4 *         4 *         4 *         4 *
  1155  *        4 *        1 *         4 *         5 *         5 *         5 *         5 *
  1156  *        4 *        2 *         4 *         6 *         6 *         6 *         6 *
  1157  *        4 *        3 *         4 *         7 *         7 *         7 *         7 *
  1158  ***********************************************************************************
  1159  `,
  1160  		},
  1161  		{
  1162  			name:  "slices-int",
  1163  			nevts: 5,
  1164  			wvars: []WriteVar{
  1165  				{Name: "N", Value: new(int32)},
  1166  				{Name: "SliI16", Value: new([]int16), Count: "N"},
  1167  				{Name: "SliI32", Value: new([]int32), Count: "N"},
  1168  				{Name: "SliI64", Value: new([]int64), Count: "N"},
  1169  			},
  1170  			btitles: []string{
  1171  				"N/I",
  1172  				"SliI16[N]/S", "SliI32[N]/I", "SliI64[N]/L",
  1173  			},
  1174  			ltitles: []string{
  1175  				"N",
  1176  				"SliI16[N]", "SliI32[N]", "SliI64[N]",
  1177  			},
  1178  			total: 160,
  1179  			want: func(i int) any {
  1180  				type Data struct {
  1181  					N      int32
  1182  					SliI16 []int16
  1183  					SliI32 []int32
  1184  					SliI64 []int64
  1185  				}
  1186  				return Data{
  1187  					N:      int32(i),
  1188  					SliI16: []int16{int16(i), int16(i + 1), int16(i + 2), int16(i + 3), int16(i + 4)}[:i],
  1189  					SliI32: []int32{int32(i), int32(i + 1), int32(i + 2), int32(i + 3), int32(i + 4)}[:i],
  1190  					SliI64: []int64{int64(i), int64(i + 1), int64(i + 2), int64(i + 3), int64(i + 4)}[:i],
  1191  				}
  1192  			},
  1193  			scan: []string{
  1194  				"N",
  1195  				"SliI16", "SliI32", "SliI64",
  1196  			},
  1197  			cxx: `***********************************************************************
  1198  *    Row   * Instance *         N *    SliI16 *    SliI32 *    SliI64 *
  1199  ***********************************************************************
  1200  *        0 *        0 *         0 *           *           *           *
  1201  *        1 *        0 *         1 *         1 *         1 *         1 *
  1202  *        2 *        0 *         2 *         2 *         2 *         2 *
  1203  *        2 *        1 *         2 *         3 *         3 *         3 *
  1204  *        3 *        0 *         3 *         3 *         3 *         3 *
  1205  *        3 *        1 *         3 *         4 *         4 *         4 *
  1206  *        3 *        2 *         3 *         5 *         5 *         5 *
  1207  *        4 *        0 *         4 *         4 *         4 *         4 *
  1208  *        4 *        1 *         4 *         5 *         5 *         5 *
  1209  *        4 *        2 *         4 *         6 *         6 *         6 *
  1210  *        4 *        3 *         4 *         7 *         7 *         7 *
  1211  ***********************************************************************
  1212  `,
  1213  		},
  1214  		{
  1215  			name:  "slices-int8",
  1216  			skip:  true,
  1217  			nevts: 5,
  1218  			wvars: []WriteVar{
  1219  				{Name: "N", Value: new(int32)},
  1220  				{Name: "SliI8", Value: new([]int8), Count: "N"},
  1221  			},
  1222  			btitles: []string{
  1223  				"N/I", "SliI8[N]/B",
  1224  			},
  1225  			ltitles: []string{
  1226  				"N", "SliI8[N]",
  1227  			},
  1228  			total: 30,
  1229  			want: func(i int) any {
  1230  				type Data struct {
  1231  					N     int32
  1232  					SliI8 []int8
  1233  				}
  1234  				return Data{
  1235  					N:     int32(i),
  1236  					SliI8: []int8{int8('a' + i), int8('a' + i + 1), int8('a' + i + 2), int8('a' + i + 3), int8(0)}[:i],
  1237  				}
  1238  			},
  1239  			scan: []string{
  1240  				"N", "SliI8",
  1241  			},
  1242  			cxx: `***********************************************
  1243  *    Row   * Instance *         N *     SliI8 *
  1244  ***********************************************
  1245  *        0 *        0 *         0 *           *
  1246  *        1 *        0 *         1 *         b *
  1247  *        2 *        0 *         2 *        cd *
  1248  *        2 *        1 *         2 *        cd *
  1249  *        3 *        0 *         3 *       def *
  1250  *        3 *        1 *         3 *       def *
  1251  *        3 *        2 *         3 *       def *
  1252  *        4 *        0 *         4 *      efgh *
  1253  *        4 *        1 *         4 *      efgh *
  1254  *        4 *        2 *         4 *      efgh *
  1255  *        4 *        3 *         4 *      efgh *
  1256  ***********************************************
  1257  `,
  1258  		},
  1259  		{
  1260  			name:  "slices-bool-floats",
  1261  			nevts: 5,
  1262  			wvars: []WriteVar{
  1263  				{Name: "N", Value: new(int32)},
  1264  				{Name: "SliB", Value: new([]bool), Count: "N"},
  1265  				{Name: "SliF32", Value: new([]float32), Count: "N"},
  1266  				{Name: "SliF64", Value: new([]float64), Count: "N"},
  1267  			},
  1268  			btitles: []string{
  1269  				"N/I",
  1270  				"SliB[N]/O",
  1271  				"SliF32[N]/F", "SliF64[N]/D",
  1272  			},
  1273  			ltitles: []string{
  1274  				"N",
  1275  				"SliB[N]",
  1276  				"SliF32[N]", "SliF64[N]",
  1277  			},
  1278  			total: 150,
  1279  			want: func(i int) any {
  1280  				type Data struct {
  1281  					N       int32
  1282  					SliBool []bool
  1283  					SliF32  []float32
  1284  					SliF64  []float64
  1285  				}
  1286  				return Data{
  1287  					N:       int32(i),
  1288  					SliBool: []bool{bool(i%2 == 0), bool((i+1)%2 == 0), bool((i+2)%2 == 0), bool((i+3)%2 == 0), bool((i+4)%2 == 0)}[:i],
  1289  					SliF32:  []float32{float32(i), float32(i + 1), float32(i + 2), float32(i + 3), float32(i + 4)}[:i],
  1290  					SliF64:  []float64{float64(i), float64(i + 1), float64(i + 2), float64(i + 3), float64(i + 4)}[:i],
  1291  				}
  1292  			},
  1293  			scan: []string{
  1294  				"N",
  1295  				"SliB",
  1296  				"SliF32", "SliF64",
  1297  			},
  1298  			cxx: `***********************************************************************
  1299  *    Row   * Instance *         N *      SliB *    SliF32 *    SliF64 *
  1300  ***********************************************************************
  1301  *        0 *        0 *         0 *           *           *           *
  1302  *        1 *        0 *         1 *         0 *         1 *         1 *
  1303  *        2 *        0 *         2 *         1 *         2 *         2 *
  1304  *        2 *        1 *         2 *         0 *         3 *         3 *
  1305  *        3 *        0 *         3 *         0 *         3 *         3 *
  1306  *        3 *        1 *         3 *         1 *         4 *         4 *
  1307  *        3 *        2 *         3 *         0 *         5 *         5 *
  1308  *        4 *        0 *         4 *         1 *         4 *         4 *
  1309  *        4 *        1 *         4 *         0 *         5 *         5 *
  1310  *        4 *        2 *         4 *         1 *         6 *         6 *
  1311  *        4 *        3 *         4 *         0 *         7 *         7 *
  1312  ***********************************************************************
  1313  `,
  1314  		},
  1315  		{
  1316  			name:  "slices-multi-baskets",
  1317  			nevts: 10000,
  1318  			wvars: []WriteVar{
  1319  				{Name: "N", Value: new(int32)},
  1320  				{Name: "SliI64", Value: new([]int64), Count: "N"},
  1321  			},
  1322  			btitles: []string{
  1323  				"N/I",
  1324  				"SliI64[N]/L",
  1325  			},
  1326  			ltitles: []string{
  1327  				"N",
  1328  				"SliI64[N]",
  1329  			},
  1330  			total: 400000,
  1331  			want: func(i int) any {
  1332  				type Data struct {
  1333  					N      int32
  1334  					SliI64 []int64
  1335  				}
  1336  				n := i % 10
  1337  				d := Data{
  1338  					N:      int32(n),
  1339  					SliI64: make([]int64, n),
  1340  				}
  1341  				for j := range d.SliI64 {
  1342  					d.SliI64[j] = int64(j + 1)
  1343  				}
  1344  				return d
  1345  			},
  1346  		},
  1347  		{
  1348  			name:  "compr-no-compression",
  1349  			wopts: []WriteOption{WithoutCompression()},
  1350  			nevts: 500,
  1351  			wvars: []WriteVar{
  1352  				{Name: "i32", Value: new(int32)},
  1353  				{Name: "f64", Value: new(float64)},
  1354  			},
  1355  			btitles: []string{"i32/I", "f64/D"},
  1356  			ltitles: []string{"i32", "f64"},
  1357  			total:   500 * (4 + 8),
  1358  			want: func(i int) any {
  1359  				return struct {
  1360  					I32 int32
  1361  					F64 float64
  1362  				}{
  1363  					I32: int32(i),
  1364  					F64: float64(i),
  1365  				}
  1366  			},
  1367  		},
  1368  		{
  1369  			name:  "compr-lz4-default",
  1370  			wopts: []WriteOption{WithLZ4(flate.DefaultCompression)},
  1371  			nevts: 500,
  1372  			wvars: []WriteVar{
  1373  				{Name: "i32", Value: new(int32)},
  1374  				{Name: "f64", Value: new(float64)},
  1375  			},
  1376  			btitles: []string{"i32/I", "f64/D"},
  1377  			ltitles: []string{"i32", "f64"},
  1378  			total:   500 * (4 + 8),
  1379  			want: func(i int) any {
  1380  				return struct {
  1381  					I32 int32
  1382  					F64 float64
  1383  				}{
  1384  					I32: int32(i),
  1385  					F64: float64(i),
  1386  				}
  1387  			},
  1388  		},
  1389  		{
  1390  			name:  "compr-lzma-default",
  1391  			wopts: []WriteOption{WithLZMA(flate.DefaultCompression)},
  1392  			nevts: 500,
  1393  			wvars: []WriteVar{
  1394  				{Name: "i32", Value: new(int32)},
  1395  				{Name: "f64", Value: new(float64)},
  1396  			},
  1397  			btitles: []string{"i32/I", "f64/D"},
  1398  			ltitles: []string{"i32", "f64"},
  1399  			total:   500 * (4 + 8),
  1400  			want: func(i int) any {
  1401  				return struct {
  1402  					I32 int32
  1403  					F64 float64
  1404  				}{
  1405  					I32: int32(i),
  1406  					F64: float64(i),
  1407  				}
  1408  			},
  1409  		},
  1410  		{
  1411  			name:  "compr-zlib-2",
  1412  			wopts: []WriteOption{WithZlib(2)},
  1413  			nevts: 500,
  1414  			wvars: []WriteVar{
  1415  				{Name: "i32", Value: new(int32)},
  1416  				{Name: "f64", Value: new(float64)},
  1417  			},
  1418  			btitles: []string{"i32/I", "f64/D"},
  1419  			ltitles: []string{"i32", "f64"},
  1420  			total:   500 * (4 + 8),
  1421  			want: func(i int) any {
  1422  				return struct {
  1423  					I32 int32
  1424  					F64 float64
  1425  				}{
  1426  					I32: int32(i),
  1427  					F64: float64(i),
  1428  				}
  1429  			},
  1430  		},
  1431  		{
  1432  			name:  "compr-zlib-default",
  1433  			wopts: []WriteOption{WithZlib(flate.DefaultCompression)},
  1434  			nevts: 500,
  1435  			wvars: []WriteVar{
  1436  				{Name: "i32", Value: new(int32)},
  1437  				{Name: "f64", Value: new(float64)},
  1438  			},
  1439  			btitles: []string{"i32/I", "f64/D"},
  1440  			ltitles: []string{"i32", "f64"},
  1441  			total:   500 * (4 + 8),
  1442  			want: func(i int) any {
  1443  				return struct {
  1444  					I32 int32
  1445  					F64 float64
  1446  				}{
  1447  					I32: int32(i),
  1448  					F64: float64(i),
  1449  				}
  1450  			},
  1451  		},
  1452  	} {
  1453  		t.Run(tc.name, func(t *testing.T) {
  1454  			fname := filepath.Join(tmp, tc.name+".root")
  1455  
  1456  			if tc.skip {
  1457  				t.Skipf("skipping %s...", tc.name)
  1458  			}
  1459  
  1460  			func() {
  1461  				f, err := riofs.Create(fname)
  1462  				if err != nil {
  1463  					t.Fatalf("could not create write ROOT file %q: %v", fname, err)
  1464  				}
  1465  				defer f.Close()
  1466  
  1467  				tw, err := NewWriter(f, treeName, tc.wvars, tc.wopts...)
  1468  				if err != nil {
  1469  					t.Fatalf("could not create tree writer: %v", err)
  1470  				}
  1471  				defer tw.Close()
  1472  
  1473  				for i, b := range tw.Branches() {
  1474  					if got, want := b.Name(), tc.wvars[i].Name; got != want {
  1475  						t.Fatalf("branch[%d]: got=%q, want=%q", i, got, want)
  1476  					}
  1477  					if got, want := b.Title(), tc.btitles[i]; got != want {
  1478  						t.Fatalf("branch[%d]: got=%q, want=%q", i, got, want)
  1479  					}
  1480  				}
  1481  
  1482  				for i, leaf := range tw.Leaves() {
  1483  					if got, want := leaf.Name(), tc.wvars[i].Name; got != want {
  1484  						t.Fatalf("leaf[%d]: got=%q, want=%q", i, got, want)
  1485  					}
  1486  					if got, want := leaf.Title(), tc.ltitles[i]; got != want {
  1487  						t.Fatalf("leaf[%d]: got=%q, want=%q", i, got, want)
  1488  					}
  1489  				}
  1490  
  1491  				total := 0
  1492  				for i := range int(tc.nevts) {
  1493  					want := tc.want(i)
  1494  					for j, wvar := range tc.wvars {
  1495  						v := reflect.ValueOf(wvar.Value).Elem()
  1496  						want := reflect.ValueOf(want).Field(j)
  1497  						v.Set(want)
  1498  					}
  1499  					n, err := tw.Write()
  1500  					if err != nil {
  1501  						t.Fatalf("could not write event %d: %v", i, err)
  1502  					}
  1503  					total += n
  1504  				}
  1505  
  1506  				if got, want := tw.Entries(), tc.nevts; got != want {
  1507  					t.Fatalf("invalid number of entries: got=%d, want=%d", got, want)
  1508  				}
  1509  				if got, want := total, tc.total; got != want {
  1510  					t.Errorf("invalid number of bytes written: got=%d, want=%d", got, want)
  1511  				}
  1512  
  1513  				err = tw.Close()
  1514  				if err != nil {
  1515  					t.Fatalf("could not close tree writer: %v", err)
  1516  				}
  1517  
  1518  				err = f.Close()
  1519  				if err != nil {
  1520  					t.Fatalf("could not close write ROOT file %q: %v", fname, err)
  1521  				}
  1522  			}()
  1523  
  1524  			func() {
  1525  				f, err := riofs.Open(fname)
  1526  				if err != nil {
  1527  					t.Fatalf("could not opend read ROOT file %q: %+v", fname, err)
  1528  				}
  1529  				defer f.Close()
  1530  
  1531  				obj, err := f.Get(treeName)
  1532  				if err != nil {
  1533  					t.Fatalf("could not get ROOT tree %q: %+v", treeName, err)
  1534  				}
  1535  				tree := obj.(Tree)
  1536  
  1537  				if got, want := tree.Entries(), tc.nevts; got != want {
  1538  					t.Fatalf("invalid number of events: got=%v, want=%v", got, want)
  1539  				}
  1540  
  1541  				for i, b := range tree.Branches() {
  1542  					if got, want := b.Name(), tc.wvars[i].Name; got != want {
  1543  						t.Fatalf("branch[%d]: got=%q, want=%q", i, got, want)
  1544  					}
  1545  					if got, want := b.Title(), tc.btitles[i]; got != want {
  1546  						t.Fatalf("branch[%d]: got=%q, want=%q", i, got, want)
  1547  					}
  1548  				}
  1549  
  1550  				for i, leaf := range tree.Leaves() {
  1551  					if got, want := leaf.Name(), tc.wvars[i].Name; got != want {
  1552  						t.Fatalf("leaf[%d]: got=%q, want=%q", i, got, want)
  1553  					}
  1554  					if got, want := leaf.Title(), tc.ltitles[i]; got != want {
  1555  						t.Fatalf("leaf[%d]: got=%q, want=%q", i, got, want)
  1556  					}
  1557  				}
  1558  
  1559  				if len(tc.wvars) == 0 {
  1560  					return
  1561  				}
  1562  
  1563  				rvars := NewReadVars(tree)
  1564  				if len(rvars) != len(tc.wvars) {
  1565  					t.Fatalf("invalid number of read-vars: got=%d, want=%d", len(rvars), len(tc.wvars))
  1566  				}
  1567  
  1568  				for i, rvar := range rvars {
  1569  					wvar := tc.wvars[i]
  1570  					if got, want := rvar.Name, wvar.Name; got != want {
  1571  						t.Fatalf("invalid name for rvar[%d]: got=%q, want=%q", i, got, want)
  1572  					}
  1573  					wtyp := reflect.TypeOf(wvar.Value)
  1574  					rtyp := reflect.TypeOf(rvar.Value)
  1575  					if got, want := rtyp, wtyp; got != want {
  1576  						t.Fatalf("invalid type for rvar[%d]: got=%v, want=%v", i, got, want)
  1577  					}
  1578  				}
  1579  
  1580  				r, err := NewReader(tree, rvars)
  1581  				if err != nil {
  1582  					t.Fatalf("could not create reader: %+v", err)
  1583  				}
  1584  				defer r.Close()
  1585  
  1586  				nn := 0
  1587  				err = r.Read(func(ctx RCtx) error {
  1588  					i := int(ctx.Entry)
  1589  					want := tc.want(i)
  1590  					for i, rvar := range rvars {
  1591  						var (
  1592  							want = reflect.ValueOf(want).Field(i).Interface()
  1593  							got  = reflect.ValueOf(rvar.Value).Elem().Interface()
  1594  						)
  1595  						if !reflect.DeepEqual(got, want) {
  1596  							return fmt.Errorf(
  1597  								"entry[%d]: invalid scan-value[%s]: got=%v, want=%v",
  1598  								ctx.Entry, tc.wvars[i].Name, got, want,
  1599  							)
  1600  						}
  1601  					}
  1602  					nn++
  1603  					return nil
  1604  				})
  1605  				if err != nil {
  1606  					t.Fatalf("could not read tree: %+v", err)
  1607  				}
  1608  
  1609  				if got, want := nn, int(tc.nevts); got != want {
  1610  					t.Fatalf("invalid number of events: got=%d, want=%d", got, want)
  1611  				}
  1612  			}()
  1613  			if rtests.HasROOT && tc.cxx != "" {
  1614  				code := `#include <iostream>
  1615  #include "TFile.h"
  1616  #include "TTree.h"
  1617  #include "TTreePlayer.h"
  1618  
  1619  void scan(const char* fname, const char* tree, const char *list, const char *oname) {
  1620  	auto f = TFile::Open(fname);
  1621  	auto t = (TTree*)f->Get(tree);
  1622  	if (!t) {
  1623  		std::cerr << "could not fetch TTree [" << tree << "] from file [" << fname << "]\n";
  1624  		exit(1);
  1625  	}
  1626  	auto player = dynamic_cast<TTreePlayer*>(t->GetPlayer());
  1627  	player->SetScanRedirect(kTRUE);
  1628  	player->SetScanFileName(oname);
  1629  	t->SetScanField(0);
  1630  	t->Scan(list);
  1631  }
  1632  `
  1633  
  1634  				scan := []string{"*"}
  1635  				if len(tc.scan) != 0 {
  1636  					scan = tc.scan
  1637  				}
  1638  
  1639  				ofile := filepath.Join(tmp, tc.name+".txt")
  1640  				out, err := rtests.RunCxxROOT("scan", []byte(code), fname, treeName, strings.Join(scan, ":"), ofile)
  1641  				if err != nil {
  1642  					t.Fatalf("could not run C++ ROOT: %+v\noutput:\n%s", err, out)
  1643  				}
  1644  
  1645  				got, err := os.ReadFile(ofile)
  1646  				if err != nil {
  1647  					t.Fatalf("could not read C++ ROOT scan file %q: %+v\noutput:\n%s", ofile, err, out)
  1648  				}
  1649  
  1650  				if got, want := string(got), tc.cxx; got != want {
  1651  					t.Fatalf("invalid ROOT scan:\ngot:\n%v\nwant:\n%v\noutput:\n%s\n%s", got, want, out, diff.Format(got, want))
  1652  				}
  1653  			}
  1654  		})
  1655  	}
  1656  }
  1657  
  1658  func TestNestedTreeRW(t *testing.T) {
  1659  	tmp, err := os.MkdirTemp("", "groot-rtree-")
  1660  	if err != nil {
  1661  		t.Fatalf("could not create dir: %v", err)
  1662  	}
  1663  	defer os.RemoveAll(tmp)
  1664  
  1665  	const (
  1666  		treeName = "mytree"
  1667  	)
  1668  
  1669  	sictx := rdict.StreamerInfos
  1670  
  1671  	for _, tc := range []struct {
  1672  		name    string
  1673  		skip    bool
  1674  		wopts   []WriteOption
  1675  		nevts   int64
  1676  		wvars   []WriteVar
  1677  		rvars   []ReadVar
  1678  		btitles []string
  1679  		ltitles []string
  1680  		total   int
  1681  		want    func(i int) any
  1682  		macro   string // ROOT macro to execute to read back ROOT file
  1683  		cxx     string // expected ROOT-TTree::Scan
  1684  		sinfos  []rbytes.StreamerInfo
  1685  	}{
  1686  		{
  1687  			name: "struct-with-struct",
  1688  			wopts: []WriteOption{
  1689  				WithZlib(flate.DefaultCompression),
  1690  				WithSplitLevel(0),
  1691  			},
  1692  			nevts: 10,
  1693  			wvars: []WriteVar{
  1694  				{Name: "evt", Value: new(TNestedStruct1)},
  1695  			},
  1696  			rvars: []ReadVar{
  1697  				{Name: "evt", Value: new(TNestedStruct1)},
  1698  			},
  1699  			btitles: []string{"evt"},
  1700  			ltitles: []string{"evt"},
  1701  			total:   460,
  1702  			want: func(i int) any {
  1703  				var evt struct {
  1704  					Data TNestedStruct1
  1705  				}
  1706  				evt.Data.RunNbr = 10 + int64(i)
  1707  				evt.Data.EvtNbr = int64(i)
  1708  				evt.Data.P3.Px = float64(i + 10)
  1709  				evt.Data.P3.Py = float64(i + 20)
  1710  				evt.Data.P3.Pz = float64(i + 30)
  1711  				return evt
  1712  			},
  1713  			macro: `
  1714  #include "TFile.h"
  1715  #include "TTree.h"
  1716  
  1717  #include <vector>
  1718  #include <fstream>
  1719  
  1720  struct TNestedStruct1P3 {
  1721  	double px,py,pz;
  1722  };
  1723  
  1724  struct TNestedStruct1 {
  1725  	Long64_t runnbr;
  1726  	Long64_t evtnbr;
  1727  	TNestedStruct1P3 p3;
  1728  };
  1729  
  1730  
  1731  void scan(const char *fname, const char *tname, const char *oname) {
  1732   auto o = std::fstream(oname, std::ofstream::out);
  1733   auto f = TFile::Open(fname, "READ");
  1734   auto t = (TTree*)f->Get(tname);
  1735   t->Print();
  1736  
  1737   TNestedStruct1 *evt = nullptr;
  1738   t->SetBranchAddress("evt", &evt);
  1739  
  1740   auto n = t->GetEntries();
  1741   o << "entries: " << n << "\n";
  1742   for (int i = 0; i < n; i++) {
  1743  	t->GetEntry(i);
  1744  	o << "evt[" << i << "]:"
  1745  	  << " run=" << evt->runnbr << ","
  1746  	  << " evt=" << evt->evtnbr << ","
  1747  	  << " p3(" << evt->p3.px << ", " << evt->p3.py << ", " << evt->p3.pz << ")"
  1748  	  << "\n";
  1749   }
  1750   o.flush();
  1751  }
  1752  			`,
  1753  			cxx: `entries: 10
  1754  evt[0]: run=10, evt=0, p3(10, 20, 30)
  1755  evt[1]: run=11, evt=1, p3(11, 21, 31)
  1756  evt[2]: run=12, evt=2, p3(12, 22, 32)
  1757  evt[3]: run=13, evt=3, p3(13, 23, 33)
  1758  evt[4]: run=14, evt=4, p3(14, 24, 34)
  1759  evt[5]: run=15, evt=5, p3(15, 25, 35)
  1760  evt[6]: run=16, evt=6, p3(16, 26, 36)
  1761  evt[7]: run=17, evt=7, p3(17, 27, 37)
  1762  evt[8]: run=18, evt=8, p3(18, 28, 38)
  1763  evt[9]: run=19, evt=9, p3(19, 29, 39)
  1764  `,
  1765  			sinfos: []rbytes.StreamerInfo{
  1766  				rdict.StreamerOf(sictx, reflect.TypeOf(TNestedStruct1P3{})),
  1767  				rdict.StreamerOf(sictx, reflect.TypeOf(TNestedStruct1{})),
  1768  			},
  1769  		},
  1770  		{
  1771  			name: "large-struct-with-struct",
  1772  			wopts: []WriteOption{
  1773  				WithZlib(flate.DefaultCompression),
  1774  				WithSplitLevel(0),
  1775  			},
  1776  			nevts: 1000,
  1777  			wvars: []WriteVar{
  1778  				{Name: "evt", Value: new(TNestedStruct1)},
  1779  			},
  1780  			rvars: []ReadVar{
  1781  				{Name: "evt", Value: new(TNestedStruct1)},
  1782  			},
  1783  			btitles: []string{"evt"},
  1784  			ltitles: []string{"evt"},
  1785  			total:   46 * 1000,
  1786  			want: func(i int) any {
  1787  				var evt struct {
  1788  					Data TNestedStruct1
  1789  				}
  1790  				evt.Data.RunNbr = 10 + int64(i)
  1791  				evt.Data.EvtNbr = int64(i)
  1792  				evt.Data.P3.Px = float64(i + 10)
  1793  				evt.Data.P3.Py = float64(i + 20)
  1794  				evt.Data.P3.Pz = float64(i + 30)
  1795  				return evt
  1796  			},
  1797  			sinfos: []rbytes.StreamerInfo{
  1798  				rdict.StreamerOf(sictx, reflect.TypeOf(TNestedStruct1P3{})),
  1799  				rdict.StreamerOf(sictx, reflect.TypeOf(TNestedStruct1{})),
  1800  			},
  1801  		},
  1802  		{
  1803  			name: "struct-with-struct+slice",
  1804  			wopts: []WriteOption{
  1805  				WithZlib(flate.DefaultCompression),
  1806  				WithSplitLevel(0),
  1807  			},
  1808  			nevts: 10,
  1809  			wvars: []WriteVar{
  1810  				{Name: "evt", Value: new(TNestedStruct2)},
  1811  			},
  1812  			rvars: []ReadVar{
  1813  				{Name: "evt", Value: new(TNestedStruct2)},
  1814  			},
  1815  			btitles: []string{"evt"},
  1816  			ltitles: []string{"evt"},
  1817  			total:   740,
  1818  			want: func(i int) any {
  1819  				var evt struct {
  1820  					Data TNestedStruct2
  1821  				}
  1822  				evt.Data.RunNbr = 10 + int64(i)
  1823  				evt.Data.EvtNbr = int64(i)
  1824  				evt.Data.P3.Px = float64(i + 10)
  1825  				evt.Data.P3.Py = float64(i + 20)
  1826  				evt.Data.P3.Pz = float64(i + 30)
  1827  				switch i {
  1828  				case 0:
  1829  					evt.Data.F32s = nil
  1830  				default:
  1831  					evt.Data.F32s = make([]float32, 0, i)
  1832  				}
  1833  				for j := range i {
  1834  					evt.Data.F32s = append(evt.Data.F32s, float32((i+1)*10+j))
  1835  				}
  1836  
  1837  				return evt
  1838  			},
  1839  			macro: `
  1840  #include "TFile.h"
  1841  #include "TTree.h"
  1842  
  1843  #include <vector>
  1844  #include <fstream>
  1845  
  1846  struct TNestedStruct1P3 {
  1847  	double px,py,pz;
  1848  };
  1849  
  1850  struct TNestedStruct2 {
  1851  	Long64_t runnbr;
  1852  	Long64_t evtnbr;
  1853  	TNestedStruct1P3 p3;
  1854  	std::vector<float> f32s;
  1855  };
  1856  
  1857  template<class T>
  1858  std::string printVec(const std::vector<T>& v) {
  1859  	std::stringstream o;
  1860  	int i = 0;
  1861  	o << "[";
  1862  	for (auto e : v) {
  1863  		if (i > 0) {
  1864  			o << ", ";
  1865  		}
  1866  		o << e;
  1867  		i++;
  1868  	}
  1869  	o << "]";
  1870  	return o.str();
  1871  }
  1872  
  1873  void scan(const char *fname, const char *tname, const char *oname) {
  1874   auto o = std::fstream(oname, std::ofstream::out);
  1875   auto f = TFile::Open(fname, "READ");
  1876   auto t = (TTree*)f->Get(tname);
  1877   t->Print();
  1878  
  1879   TNestedStruct2 *evt = nullptr;
  1880   t->SetBranchAddress("evt", &evt);
  1881  
  1882   auto n = t->GetEntries();
  1883   o << "entries: " << n << "\n";
  1884   for (int i = 0; i < n; i++) {
  1885  	t->GetEntry(i);
  1886  	o << "evt[" << i << "]:"
  1887  	  << " run=" << evt->runnbr << ","
  1888  	  << " evt=" << evt->evtnbr << ","
  1889  	  << " p3(" << evt->p3.px << ", " << evt->p3.py << ", " << evt->p3.pz << ")"
  1890  	  << " f32s(" << printVec(evt->f32s) << ")"
  1891  	  << "\n";
  1892   }
  1893   o.flush();
  1894  }
  1895  			`,
  1896  			cxx: `entries: 10
  1897  evt[0]: run=10, evt=0, p3(10, 20, 30) f32s([])
  1898  evt[1]: run=11, evt=1, p3(11, 21, 31) f32s([20])
  1899  evt[2]: run=12, evt=2, p3(12, 22, 32) f32s([30, 31])
  1900  evt[3]: run=13, evt=3, p3(13, 23, 33) f32s([40, 41, 42])
  1901  evt[4]: run=14, evt=4, p3(14, 24, 34) f32s([50, 51, 52, 53])
  1902  evt[5]: run=15, evt=5, p3(15, 25, 35) f32s([60, 61, 62, 63, 64])
  1903  evt[6]: run=16, evt=6, p3(16, 26, 36) f32s([70, 71, 72, 73, 74, 75])
  1904  evt[7]: run=17, evt=7, p3(17, 27, 37) f32s([80, 81, 82, 83, 84, 85, 86])
  1905  evt[8]: run=18, evt=8, p3(18, 28, 38) f32s([90, 91, 92, 93, 94, 95, 96, 97])
  1906  evt[9]: run=19, evt=9, p3(19, 29, 39) f32s([100, 101, 102, 103, 104, 105, 106, 107, 108])
  1907  `,
  1908  			sinfos: []rbytes.StreamerInfo{
  1909  				rdict.StreamerOf(sictx, reflect.TypeOf(TNestedStruct1P3{})),
  1910  				rdict.StreamerOf(sictx, reflect.TypeOf(TNestedStruct2{})),
  1911  			},
  1912  		},
  1913  		{
  1914  			name: "struct+slice",
  1915  			wopts: []WriteOption{
  1916  				WithZlib(flate.DefaultCompression),
  1917  				WithSplitLevel(0),
  1918  			},
  1919  			nevts: 10,
  1920  			wvars: []WriteVar{
  1921  				{Name: "runnbr", Value: new(int64)},
  1922  				{Name: "evtnbr", Value: new(int64)},
  1923  				{Name: "p3", Value: new(TNestedStruct1P3)},
  1924  				{Name: "f32s", Value: new([]float32)},
  1925  			},
  1926  			rvars: []ReadVar{
  1927  				{Name: "runnbr", Value: new(int64)},
  1928  				{Name: "evtnbr", Value: new(int64)},
  1929  				{Name: "p3", Value: new(TNestedStruct1P3)},
  1930  				{Name: "f32s", Value: new([]float32)},
  1931  			},
  1932  			btitles: []string{"runnbr/L", "evtnbr/L", "p3", "f32s"},
  1933  			ltitles: []string{"runnbr", "evtnbr", "p3", "f32s"},
  1934  			total:   680,
  1935  			want: func(i int) any {
  1936  				var evt struct {
  1937  					Data TNestedStruct3
  1938  				}
  1939  				evt.Data.RunNbr = 10 + int64(i)
  1940  				evt.Data.EvtNbr = int64(i)
  1941  				evt.Data.P3.Px = float64(i + 10)
  1942  				evt.Data.P3.Py = float64(i + 20)
  1943  				evt.Data.P3.Pz = float64(i + 30)
  1944  				switch i {
  1945  				case 0:
  1946  					evt.Data.F32s = nil
  1947  				default:
  1948  					evt.Data.F32s = make([]float32, 0, i)
  1949  				}
  1950  				for j := range i {
  1951  					evt.Data.F32s = append(evt.Data.F32s, float32((i+1)*10+j))
  1952  				}
  1953  
  1954  				return evt.Data
  1955  			},
  1956  			macro: `
  1957  #include "TFile.h"
  1958  #include "TTree.h"
  1959  
  1960  #include <vector>
  1961  #include <fstream>
  1962  
  1963  struct TNestedStruct1P3 {
  1964  	double px,py,pz;
  1965  };
  1966  
  1967  struct TNestedStruct3 {
  1968  	Long64_t runnbr;
  1969  	Long64_t evtnbr;
  1970  	TNestedStruct1P3 p3;
  1971  	std::vector<float> f32s;
  1972  };
  1973  
  1974  template<class T>
  1975  std::string printVec(const std::vector<T>& v) {
  1976  	std::stringstream o;
  1977  	int i = 0;
  1978  	o << "[";
  1979  	for (auto e : v) {
  1980  		if (i > 0) {
  1981  			o << ", ";
  1982  		}
  1983  		o << e;
  1984  		i++;
  1985  	}
  1986  	o << "]";
  1987  	return o.str();
  1988  }
  1989  
  1990  void scan(const char *fname, const char *tname, const char *oname) {
  1991   auto o = std::fstream(oname, std::ofstream::out);
  1992   auto f = TFile::Open(fname, "READ");
  1993   auto t = (TTree*)f->Get(tname);
  1994   t->Print();
  1995  
  1996   Long64_t runnbr;
  1997   t->SetBranchAddress("runnbr", &runnbr);
  1998  
  1999   Long64_t evtnbr;
  2000   t->SetBranchAddress("evtnbr", &evtnbr);
  2001  
  2002   TNestedStruct1P3 *p3 = nullptr;
  2003   t->SetBranchAddress("p3", &p3);
  2004  
  2005   std::vector<float> *f32s = nullptr;
  2006   t->SetBranchAddress("f32s", &f32s);
  2007  
  2008   auto n = t->GetEntries();
  2009   o << "entries: " << n << "\n";
  2010   for (int i = 0; i < n; i++) {
  2011  	t->GetEntry(i);
  2012  	o << "evt[" << i << "]:"
  2013  	  << " run=" << runnbr << ","
  2014  	  << " evt=" << evtnbr << ","
  2015  	  << " p3(" << p3->px << ", " << p3->py << ", " << p3->pz << ")"
  2016  	  << " f32s(" << printVec(*f32s) << ")"
  2017  	  << "\n";
  2018   }
  2019   o.flush();
  2020  }
  2021  			`,
  2022  			cxx: `entries: 10
  2023  evt[0]: run=10, evt=0, p3(10, 20, 30) f32s([])
  2024  evt[1]: run=11, evt=1, p3(11, 21, 31) f32s([20])
  2025  evt[2]: run=12, evt=2, p3(12, 22, 32) f32s([30, 31])
  2026  evt[3]: run=13, evt=3, p3(13, 23, 33) f32s([40, 41, 42])
  2027  evt[4]: run=14, evt=4, p3(14, 24, 34) f32s([50, 51, 52, 53])
  2028  evt[5]: run=15, evt=5, p3(15, 25, 35) f32s([60, 61, 62, 63, 64])
  2029  evt[6]: run=16, evt=6, p3(16, 26, 36) f32s([70, 71, 72, 73, 74, 75])
  2030  evt[7]: run=17, evt=7, p3(17, 27, 37) f32s([80, 81, 82, 83, 84, 85, 86])
  2031  evt[8]: run=18, evt=8, p3(18, 28, 38) f32s([90, 91, 92, 93, 94, 95, 96, 97])
  2032  evt[9]: run=19, evt=9, p3(19, 29, 39) f32s([100, 101, 102, 103, 104, 105, 106, 107, 108])
  2033  `,
  2034  			sinfos: []rbytes.StreamerInfo{
  2035  				rdict.StreamerOf(sictx, reflect.TypeOf(TNestedStruct1P3{})),
  2036  				rdict.StreamerOf(sictx, reflect.TypeOf(TNestedStruct3{})),
  2037  			},
  2038  		},
  2039  		{
  2040  			name: "vector+slice",
  2041  			wopts: []WriteOption{
  2042  				WithZlib(flate.DefaultCompression),
  2043  				WithSplitLevel(0),
  2044  			},
  2045  			nevts: 10,
  2046  			wvars: []WriteVar{
  2047  				{Name: "N", Value: new(int32)},
  2048  				{Name: "vec", Value: new([]float32)},
  2049  				//				{Name: "sli", Value: new([]float32), Count: "N"},
  2050  			},
  2051  			rvars: []ReadVar{
  2052  				{Name: "N", Value: new(int32)},
  2053  				{Name: "vec", Value: new([]float32)},
  2054  				//				{Name: "sli", Value: new([]float32)},
  2055  			},
  2056  			btitles: []string{"N/I", "vec"}, // "sli[N]/F"},
  2057  			ltitles: []string{"N", "vec"},   // "sli[N]"},
  2058  			total:   360,
  2059  			want: func(i int) any {
  2060  				var evt struct {
  2061  					N   int32
  2062  					Vec []float32
  2063  					//					Sli []float32 `groot:"sli[N]"`
  2064  				}
  2065  
  2066  				evt.N = int32(i) + 1
  2067  				evt.Vec = make([]float32, evt.N)
  2068  				//				evt.Sli = make([]float32, evt.N)
  2069  				for j := range int(evt.N) {
  2070  					evt.Vec[j] = -float32((i+1)*10 + j)
  2071  					//					evt.Sli[j] = +float32((i+1)*10 + j)
  2072  				}
  2073  
  2074  				return evt
  2075  			},
  2076  			macro: `
  2077  #include "TFile.h"
  2078  #include "TTree.h"
  2079  
  2080  #include <vector>
  2081  #include <fstream>
  2082  
  2083  template<class T>
  2084  std::string printVec(const std::vector<T>& v) {
  2085  	std::stringstream o;
  2086  	int i = 0;
  2087  	o << "[";
  2088  	for (auto e : v) {
  2089  		if (i > 0) {
  2090  			o << " ";
  2091  		}
  2092  		o << e;
  2093  		i++;
  2094  	}
  2095  	o << "]";
  2096  	return o.str();
  2097  }
  2098  
  2099  template<class T>
  2100  std::string printSli(int32_t n, const T *v) {
  2101  	std::stringstream o;
  2102  	o << "[";
  2103  	for (int i = 0; i < n; i++) {
  2104  		auto e = v[i];
  2105  		if (i > 0) {
  2106  			o << " ";
  2107  		}
  2108  		o << e;
  2109  	}
  2110  	o << "]";
  2111  	return o.str();
  2112  }
  2113  
  2114  void scan(const char *fname, const char *tname, const char *oname) {
  2115   auto o = std::fstream(oname, std::ofstream::out);
  2116   auto f = TFile::Open(fname, "READ");
  2117   auto t = (TTree*)f->Get(tname);
  2118   t->Print();
  2119  
  2120   int32_t n;
  2121   t->SetBranchAddress("N", &n);
  2122  
  2123   std::vector<float> *vec = nullptr;
  2124   t->SetBranchAddress("vec", &vec);
  2125  
  2126  // float *sli = nullptr;
  2127  // t->SetBranchAddress("sli", &sli);
  2128  
  2129   auto nevts = t->GetEntries();
  2130   o << "entries: " << nevts << "\n";
  2131   for (int i = 0; i < nevts; i++) {
  2132  	t->GetEntry(i);
  2133  	o << "evt[" << i << "]:"
  2134  	  << " " << n
  2135  	  << " " << printVec(*vec)
  2136  //	  << " " << printSli(n, sli)
  2137  	  << "\n";
  2138   }
  2139   o.flush();
  2140  }
  2141  			`,
  2142  			cxx: `entries: 10
  2143  evt[0]: 1 [-10]
  2144  evt[1]: 2 [-20 -21]
  2145  evt[2]: 3 [-30 -31 -32]
  2146  evt[3]: 4 [-40 -41 -42 -43]
  2147  evt[4]: 5 [-50 -51 -52 -53 -54]
  2148  evt[5]: 6 [-60 -61 -62 -63 -64 -65]
  2149  evt[6]: 7 [-70 -71 -72 -73 -74 -75 -76]
  2150  evt[7]: 8 [-80 -81 -82 -83 -84 -85 -86 -87]
  2151  evt[8]: 9 [-90 -91 -92 -93 -94 -95 -96 -97 -98]
  2152  evt[9]: 10 [-100 -101 -102 -103 -104 -105 -106 -107 -108 -109]
  2153  `,
  2154  			sinfos: []rbytes.StreamerInfo{
  2155  				rdict.StreamerOf(sictx, reflect.TypeOf([]float32{})),
  2156  			},
  2157  		},
  2158  		{
  2159  			name: "event-nosplit",
  2160  			wopts: []WriteOption{
  2161  				WithZlib(flate.DefaultCompression),
  2162  				WithSplitLevel(0),
  2163  			},
  2164  			nevts: 10,
  2165  			wvars: []WriteVar{
  2166  				{Name: "evt", Value: new(TNestedEvent1)},
  2167  			},
  2168  			rvars: []ReadVar{
  2169  				{Name: "evt", Value: new(TNestedEvent1)},
  2170  			},
  2171  			btitles: []string{"evt"},
  2172  			ltitles: []string{"evt"},
  2173  			total:   25520,
  2174  			want: func(i int) any {
  2175  				var evt struct {
  2176  					Event TNestedEvent1
  2177  				}
  2178  
  2179  				evt.Event = TNestedEvent1{}.want(int64(i))
  2180  
  2181  				return evt
  2182  			},
  2183  			macro: `
  2184  #include "TFile.h"
  2185  #include "TTree.h"
  2186  #include "TString.h"
  2187  #include "TObjString.h"
  2188  
  2189  #include <vector>
  2190  #include <fstream>
  2191  
  2192  const int ARRAYSZ  = 10;
  2193  const int MAXSLICE = 20;
  2194  const int MAXSTR   = 32;
  2195  
  2196  #define OFFSET 0
  2197  
  2198  struct TNestedP2 {
  2199  	double px;
  2200  	float  py;
  2201  };
  2202  
  2203  
  2204  template<class T>
  2205  std::string printV(T v) {
  2206  	std::stringstream o;
  2207  	o << v;
  2208  	return o.str();
  2209  }
  2210  
  2211  template<>
  2212  std::string printV(TNestedP2 v) {
  2213  	std::stringstream o;
  2214  	o << "{" << v.px << " " << v.py << "}";
  2215  	return o.str();
  2216  }
  2217  
  2218  template<>
  2219  std::string printV(bool v) {
  2220  	if (v) {
  2221  		return "true";
  2222  	}
  2223  	return "false";
  2224  }
  2225  
  2226  template<>
  2227  std::string printV(int8_t v) {
  2228  	std::stringstream o;
  2229  	o << int(v);
  2230  	return o.str();
  2231  }
  2232  
  2233  template<>
  2234  std::string printV(uint8_t v) {
  2235  	std::stringstream o;
  2236  	o << int(v);
  2237  	return o.str();
  2238  }
  2239  
  2240  template<>
  2241  std::string printV(TString v) {
  2242  	std::stringstream o;
  2243  	o << v.Data();
  2244  	return o.str();
  2245  }
  2246  
  2247  template<>
  2248  std::string printV(TObjString v) {
  2249  	std::stringstream o;
  2250  	o << v.GetString().Data();
  2251  	return o.str();
  2252  }
  2253  
  2254  template<>
  2255  std::string printV(std::string v) {
  2256  	return v;
  2257  }
  2258  
  2259  template<class T>
  2260  std::string printArr(const T *v) {
  2261  	std::stringstream o;
  2262  	o << "[";
  2263  	for (int i = 0; i < ARRAYSZ; i++) {
  2264  		auto e = v[i];
  2265  		if (i > 0) {
  2266  			o << " ";
  2267  		}
  2268  		o << printV(e);
  2269  	}
  2270  	o << "]";
  2271  	return o.str();
  2272  }
  2273  
  2274  //template<>
  2275  std::string printArrCStr(char *v[ARRAYSZ]) {
  2276  	std::stringstream o;
  2277  	o << "[";
  2278  	for (int i = 0; i < ARRAYSZ; i++) {
  2279  		auto e = v[i];
  2280  		if (i > 0) {
  2281  			o << " ";
  2282  		}
  2283  		o << e;
  2284  	}
  2285  	o << "]";
  2286  	return o.str();
  2287  }
  2288  
  2289  template<class T>
  2290  std::string printSli(int32_t n, const T *v) {
  2291  	std::stringstream o;
  2292  	o << "[";
  2293  	for (int i = 0; i < n; i++) {
  2294  		auto e = v[i];
  2295  		if (i > 0) {
  2296  			o << " ";
  2297  		}
  2298  		o << printV(e);
  2299  	}
  2300  	o << "]";
  2301  	return o.str();
  2302  }
  2303  
  2304  std::string printSliStr(int32_t n, char *v[ARRAYSZ]) {
  2305  	std::stringstream o;
  2306  	o << "[";
  2307  	for (int i = 0; i < n; i++) {
  2308  		auto e = v[i];
  2309  		if (i > 0) {
  2310  			o << " ";
  2311  		}
  2312  		o << e;
  2313  	}
  2314  	o << "]";
  2315  	return o.str();
  2316  }
  2317  
  2318  template<class T>
  2319  std::string printVec(const std::vector<T>& v) {
  2320  	std::stringstream o;
  2321  	int i = 0;
  2322  	o << "[";
  2323  	for (auto e : v) {
  2324  		if (i > 0) {
  2325  			o << " ";
  2326  		}
  2327  		o << printV(e);
  2328  		i++;
  2329  	}
  2330  	o << "]";
  2331  	return o.str();
  2332  }
  2333  
  2334  template<class T>
  2335  std::string printVecVec(const std::vector<std::vector<T> >& v) {
  2336  	std::stringstream o;
  2337  	int i = 0;
  2338  	o << "[";
  2339  	for (auto e : v) {
  2340  		if (i > 0) {
  2341  			o << " ";
  2342  		}
  2343  		o << printVec(e);
  2344  		i++;
  2345  	}
  2346  	o << "]";
  2347  	return o.str();
  2348  }
  2349  
  2350  struct TNestedEvent1 {
  2351  	bool     Bool;
  2352  	//char     Str[MAXSTR];
  2353  	//char    *Str;
  2354  	std::string Str;
  2355  	int8_t   I8;
  2356  	int16_t  I16;
  2357  	int32_t  I32;
  2358  	int64_t  I64;
  2359  	uint8_t  U8;
  2360  	uint16_t U16;
  2361  	uint32_t U32;
  2362  	uint64_t U64;
  2363  	float    F32;
  2364  	double   F64;
  2365  
  2366  	Float16_t  D16;
  2367  	Double32_t D32;
  2368  
  2369  	TNestedP2  P2;
  2370  	TObjString Obj;
  2371  
  2372  	bool     ArrBs[ARRAYSZ];
  2373  //	TString  ArrStr[ARRAYSZ];
  2374  	int8_t   ArrI8[ARRAYSZ];
  2375  	int16_t  ArrI16[ARRAYSZ];
  2376  	int32_t  ArrI32[ARRAYSZ];
  2377  	int64_t  ArrI64[ARRAYSZ];
  2378  	uint8_t  ArrU8[ARRAYSZ];
  2379  	uint16_t ArrU16[ARRAYSZ];
  2380  	uint32_t ArrU32[ARRAYSZ];
  2381  	uint64_t ArrU64[ARRAYSZ];
  2382  	float    ArrF32[ARRAYSZ];
  2383  	double   ArrF64[ARRAYSZ];
  2384  
  2385  	Float16_t    ArrD16[ARRAYSZ];
  2386  	Double32_t   ArrD32[ARRAYSZ];
  2387  
  2388  	TNestedP2  ArrP2[ARRAYSZ];
  2389  	TObjString ArrObj[ARRAYSZ];
  2390  
  2391  	int32_t  N;
  2392  	bool     *SliBs;   //[N]
  2393  //	char*    *SliStr;  //[N]
  2394  	int8_t   *SliI8;   //[N]
  2395  	int16_t  *SliI16;  //[N]
  2396  	int32_t  *SliI32;  //[N]
  2397  	int64_t  *SliI64;  //[N]
  2398  	uint8_t  *SliU8;   //[N]
  2399  	uint16_t *SliU16;  //[N]
  2400  	uint32_t *SliU32;  //[N]
  2401  	uint64_t *SliU64;  //[N]
  2402  	float    *SliF32;  //[N]
  2403  	double   *SliF64;  //[N]
  2404  
  2405  	Float16_t  *SliD16; //[N]
  2406  	Double32_t *SliD32; //[N]
  2407  //	TNestedP2  *SliP2;  //[N]
  2408  //	TObjString *SliObj; //[N]
  2409  
  2410  	std::vector<bool> StdVecBs;
  2411  	std::vector<std::string> StdVecStr;
  2412  	std::vector<int8_t>  StdVecI8;
  2413  	std::vector<int16_t> StdVecI16;
  2414  	std::vector<int32_t> StdVecI32;
  2415  	std::vector<int64_t> StdVecI64;
  2416  	std::vector<uint8_t>  StdVecU8;
  2417  	std::vector<uint16_t> StdVecU16;
  2418  	std::vector<uint32_t> StdVecU32;
  2419  	std::vector<uint64_t> StdVecU64;
  2420  	std::vector<float>    StdVecF32;
  2421  	std::vector<double>   StdVecF64;
  2422  
  2423  	std::vector<Float16_t>  StdVecD16;
  2424  	std::vector<Double32_t> StdVecD32;
  2425  	std::vector<TNestedP2>  StdVecP2;
  2426  	std::vector<TObjString> StdVecObj;
  2427  
  2428  	std::vector<std::vector<double> >      StdVecVecF64;
  2429  	std::vector<std::vector<std::string> > StdVecVecStr;
  2430  	std::vector<std::vector<TNestedP2> >   StdVecVecP2;
  2431  };
  2432  
  2433  TNestedEvent1 *newEvent() {
  2434  	auto *evt = new TNestedEvent1;
  2435  	evt->SliBs = (bool*)malloc(sizeof(bool)*0);
  2436  //	evt->SliStr = (char**)malloc(sizeof(char*)*0);
  2437  	evt->SliI8  = (int8_t*)malloc(sizeof(int8_t)*0);
  2438  	evt->SliI16 = (int16_t*)malloc(sizeof(int16_t)*0);
  2439  	evt->SliI32 = (int32_t*)malloc(sizeof(int32_t)*0);
  2440  	evt->SliI64 = (int64_t*)malloc(sizeof(int64_t)*0);
  2441  	evt->SliU8  = (uint8_t*)malloc(sizeof(uint8_t)*0);
  2442  	evt->SliU16 = (uint16_t*)malloc(sizeof(uint16_t)*0);
  2443  	evt->SliU32 = (uint32_t*)malloc(sizeof(uint32_t)*0);
  2444  	evt->SliU64 = (uint64_t*)malloc(sizeof(uint64_t)*0);
  2445  	evt->SliF32 = (float*)malloc(sizeof(float)*0);
  2446  	evt->SliF64 = (double*)malloc(sizeof(double)*0);
  2447  
  2448  	evt->SliD16 = (Float16_t*)malloc(sizeof(Float16_t)*0);
  2449  	evt->SliD32 = (Double32_t*)malloc(sizeof(Double32_t)*0);
  2450  //	evt->SliP2 =  (TNestedP2*)malloc(sizeof(TNestedP2)*0);
  2451  //	evt->SliObj = (TObjString*)malloc(sizeof(TObjString)*0);
  2452  
  2453  	return evt;
  2454  }
  2455  
  2456  
  2457  void scan(const char *fname, const char *tname, const char *oname) {
  2458   auto o = std::fstream(oname, std::ofstream::out);
  2459   auto f = TFile::Open(fname, "READ");
  2460   auto t = (TTree*)f->Get(tname);
  2461   t->Print();
  2462  
  2463   TNestedEvent1 *evt = newEvent();
  2464   t->SetBranchAddress("evt", &evt);
  2465  
  2466   o << "key[000]: " << tname << ";1 \"\" (TTree)\n";
  2467  
  2468   auto n = t->GetEntries();
  2469   for (int i = 0; i < n; i++) {
  2470  	t->GetEntry(i);
  2471  	o << "[00" << i << "][evt]: "
  2472  	  << "{" << printV(evt->Bool)
  2473  	  << " " << printV(evt->Str)
  2474  	  << " " << printV(int(evt->I8))
  2475  	  << " " << printV(evt->I16)
  2476  	  << " " << printV(evt->I32)
  2477  	  << " " << printV(evt->I64)
  2478  	  << " " << printV(int(evt->U8))
  2479  	  << " " << printV(evt->U16)
  2480  	  << " " << printV(evt->U32)
  2481  	  << " " << printV(evt->U64)
  2482  	  << " " << printV(evt->F32)
  2483  	  << " " << printV(evt->F64)
  2484  	  << " " << printV(evt->D16)
  2485  	  << " " << printV(evt->D32)
  2486  	  << " " << printV(evt->P2)
  2487  	  << " " << printV(evt->Obj)
  2488  
  2489  	  << " " << printArr(evt->ArrBs)
  2490  //	  << " " << printArr(evt->ArrStr)
  2491  	  << " " << printArr(evt->ArrI8)
  2492  	  << " " << printArr(evt->ArrI16)
  2493  	  << " " << printArr(evt->ArrI32)
  2494  	  << " " << printArr(evt->ArrI64)
  2495  	  << " " << printArr(evt->ArrU8)
  2496  	  << " " << printArr(evt->ArrU16)
  2497  	  << " " << printArr(evt->ArrU32)
  2498  	  << " " << printArr(evt->ArrU64)
  2499  	  << " " << printArr(evt->ArrF32)
  2500  	  << " " << printArr(evt->ArrF64)
  2501  	  << " " << printArr(evt->ArrD16)
  2502  	  << " " << printArr(evt->ArrD32)
  2503  	  << " " << printArr(evt->ArrP2)
  2504  	  << " " << printArr(evt->ArrObj)
  2505  
  2506  	  << " " << evt->N
  2507  	  << " " << printSli(evt->N, evt->SliBs)
  2508  //	  << " " << printSli(evt->N, evt->SliStr)
  2509  	  << " " << printSli(evt->N, evt->SliI8)
  2510  	  << " " << printSli(evt->N, evt->SliI16)
  2511  	  << " " << printSli(evt->N, evt->SliI32)
  2512  	  << " " << printSli(evt->N, evt->SliI64)
  2513  	  << " " << printSli(evt->N, evt->SliU8)
  2514  	  << " " << printSli(evt->N, evt->SliU16)
  2515  	  << " " << printSli(evt->N, evt->SliU32)
  2516  	  << " " << printSli(evt->N, evt->SliU64)
  2517  	  << " " << printSli(evt->N, evt->SliF32)
  2518  	  << " " << printSli(evt->N, evt->SliF64)
  2519  	  << " " << printSli(evt->N, evt->SliD16)
  2520  	  << " " << printSli(evt->N, evt->SliD32)
  2521  //	  << " " << printSli(evt->N, evt->SliP2)
  2522  //	  << " " << printSli(evt->N, evt->SliObj)
  2523  
  2524  	  << " " << printVec(evt->StdVecBs)
  2525  	  << " " << printVec(evt->StdVecStr)
  2526  	  << " " << printVec(evt->StdVecI8)
  2527  	  << " " << printVec(evt->StdVecI16)
  2528  	  << " " << printVec(evt->StdVecI32)
  2529  	  << " " << printVec(evt->StdVecI64)
  2530  	  << " " << printVec(evt->StdVecU8)
  2531  	  << " " << printVec(evt->StdVecU16)
  2532  	  << " " << printVec(evt->StdVecU32)
  2533  	  << " " << printVec(evt->StdVecU64)
  2534  	  << " " << printVec(evt->StdVecF32)
  2535  	  << " " << printVec(evt->StdVecF64)
  2536  	  << " " << printVec(evt->StdVecD16)
  2537  	  << " " << printVec(evt->StdVecD32)
  2538  	  << " " << printVec(evt->StdVecP2)
  2539  	  << " " << printVec(evt->StdVecObj)
  2540  
  2541  	  << " " << printVecVec(evt->StdVecVecF64)
  2542  	  << " " << printVecVec(evt->StdVecVecStr)
  2543  	  << " " << printVecVec(evt->StdVecVecP2)
  2544  	  << "}\n";
  2545   }
  2546   o.flush();
  2547  }
  2548  			`,
  2549  			cxx: `key[000]: mytree;1 "" (TTree)
  2550  [000][evt]: {true str-000 0 0 0 0 0 0 0 0 0 0 0 0 {0 0} obj-0 [true false false false false false false false false false] [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [{0 0} {0 0} {0 0} {0 0} {0 0} {0 0} {0 0} {0 0} {0 0} {0 0}] [obj-0 obj-0 obj-0 obj-0 obj-0 obj-0 obj-0 obj-0 obj-0 obj-0] 0 [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] []}
  2551  [001][evt]: {false str-001 -1 -1 -1 -1 1 1 1 1 1 1 1 1 {1 1} obj-1 [false true false false false false false false false false] [-1 -1 -1 -1 -1 -1 -1 -1 -1 -1] [-1 -1 -1 -1 -1 -1 -1 -1 -1 -1] [-1 -1 -1 -1 -1 -1 -1 -1 -1 -1] [-1 -1 -1 -1 -1 -1 -1 -1 -1 -1] [1 1 1 1 1 1 1 1 1 1] [1 1 1 1 1 1 1 1 1 1] [1 1 1 1 1 1 1 1 1 1] [1 1 1 1 1 1 1 1 1 1] [1 1 1 1 1 1 1 1 1 1] [1 1 1 1 1 1 1 1 1 1] [1 1 1 1 1 1 1 1 1 1] [1 1 1 1 1 1 1 1 1 1] [{1 1} {1 1} {1 1} {1 1} {1 1} {1 1} {1 1} {1 1} {1 1} {1 1}] [obj-1 obj-1 obj-1 obj-1 obj-1 obj-1 obj-1 obj-1 obj-1 obj-1] 1 [true] [-1] [-1] [-1] [-1] [1] [1] [1] [1] [1] [1] [1] [1] [true] [std-001] [-1] [-1] [-1] [-1] [1] [1] [1] [1] [1] [1] [1] [1] [{1 1}] [obj-001] [[0 1 2 3]] [[vec-001 vec-002 vec-003 vec-004]] [[{1 1} {2 2} {3 3} {4 4}]]}
  2552  [002][evt]: {true str-002 -2 -2 -2 -2 2 2 2 2 2 2 2 2 {2 2} obj-2 [false false true false false false false false false false] [-2 -2 -2 -2 -2 -2 -2 -2 -2 -2] [-2 -2 -2 -2 -2 -2 -2 -2 -2 -2] [-2 -2 -2 -2 -2 -2 -2 -2 -2 -2] [-2 -2 -2 -2 -2 -2 -2 -2 -2 -2] [2 2 2 2 2 2 2 2 2 2] [2 2 2 2 2 2 2 2 2 2] [2 2 2 2 2 2 2 2 2 2] [2 2 2 2 2 2 2 2 2 2] [2 2 2 2 2 2 2 2 2 2] [2 2 2 2 2 2 2 2 2 2] [2 2 2 2 2 2 2 2 2 2] [2 2 2 2 2 2 2 2 2 2] [{2 2} {2 2} {2 2} {2 2} {2 2} {2 2} {2 2} {2 2} {2 2} {2 2}] [obj-2 obj-2 obj-2 obj-2 obj-2 obj-2 obj-2 obj-2 obj-2 obj-2] 2 [false true] [-2 -2] [-2 -2] [-2 -2] [-2 -2] [2 2] [2 2] [2 2] [2 2] [2 2] [2 2] [2 2] [2 2] [false true] [std-002 std-002] [-2 -2] [-2 -2] [-2 -2] [-2 -2] [2 2] [2 2] [2 2] [2 2] [2 2] [2 2] [2 2] [2 2] [{2 2} {2 2}] [obj-002 obj-002] [[0 1 2 3] [1 2 3 4]] [[vec-002 vec-003 vec-004 vec-005] [vec-002 vec-003 vec-004 vec-005]] [[{2 2} {3 3} {4 4} {5 5}] [{2 2} {3 3} {4 4} {5 5}]]}
  2553  [003][evt]: {false str-003 -3 -3 -3 -3 3 3 3 3 3 3 3 3 {3 3} obj-3 [false false false true false false false false false false] [-3 -3 -3 -3 -3 -3 -3 -3 -3 -3] [-3 -3 -3 -3 -3 -3 -3 -3 -3 -3] [-3 -3 -3 -3 -3 -3 -3 -3 -3 -3] [-3 -3 -3 -3 -3 -3 -3 -3 -3 -3] [3 3 3 3 3 3 3 3 3 3] [3 3 3 3 3 3 3 3 3 3] [3 3 3 3 3 3 3 3 3 3] [3 3 3 3 3 3 3 3 3 3] [3 3 3 3 3 3 3 3 3 3] [3 3 3 3 3 3 3 3 3 3] [3 3 3 3 3 3 3 3 3 3] [3 3 3 3 3 3 3 3 3 3] [{3 3} {3 3} {3 3} {3 3} {3 3} {3 3} {3 3} {3 3} {3 3} {3 3}] [obj-3 obj-3 obj-3 obj-3 obj-3 obj-3 obj-3 obj-3 obj-3 obj-3] 3 [false false true] [-3 -3 -3] [-3 -3 -3] [-3 -3 -3] [-3 -3 -3] [3 3 3] [3 3 3] [3 3 3] [3 3 3] [3 3 3] [3 3 3] [3 3 3] [3 3 3] [false false true] [std-003 std-003 std-003] [-3 -3 -3] [-3 -3 -3] [-3 -3 -3] [-3 -3 -3] [3 3 3] [3 3 3] [3 3 3] [3 3 3] [3 3 3] [3 3 3] [3 3 3] [3 3 3] [{3 3} {3 3} {3 3}] [obj-003 obj-003 obj-003] [[0 1 2 3] [1 2 3 4] [2 3 4 5]] [[vec-003 vec-004 vec-005 vec-006] [vec-003 vec-004 vec-005 vec-006] [vec-003 vec-004 vec-005 vec-006]] [[{3 3} {4 4} {5 5} {6 6}] [{3 3} {4 4} {5 5} {6 6}] [{3 3} {4 4} {5 5} {6 6}]]}
  2554  [004][evt]: {true str-004 -4 -4 -4 -4 4 4 4 4 4 4 4 4 {4 4} obj-4 [false false false false true false false false false false] [-4 -4 -4 -4 -4 -4 -4 -4 -4 -4] [-4 -4 -4 -4 -4 -4 -4 -4 -4 -4] [-4 -4 -4 -4 -4 -4 -4 -4 -4 -4] [-4 -4 -4 -4 -4 -4 -4 -4 -4 -4] [4 4 4 4 4 4 4 4 4 4] [4 4 4 4 4 4 4 4 4 4] [4 4 4 4 4 4 4 4 4 4] [4 4 4 4 4 4 4 4 4 4] [4 4 4 4 4 4 4 4 4 4] [4 4 4 4 4 4 4 4 4 4] [4 4 4 4 4 4 4 4 4 4] [4 4 4 4 4 4 4 4 4 4] [{4 4} {4 4} {4 4} {4 4} {4 4} {4 4} {4 4} {4 4} {4 4} {4 4}] [obj-4 obj-4 obj-4 obj-4 obj-4 obj-4 obj-4 obj-4 obj-4 obj-4] 4 [false false false true] [-4 -4 -4 -4] [-4 -4 -4 -4] [-4 -4 -4 -4] [-4 -4 -4 -4] [4 4 4 4] [4 4 4 4] [4 4 4 4] [4 4 4 4] [4 4 4 4] [4 4 4 4] [4 4 4 4] [4 4 4 4] [false false false true] [std-004 std-004 std-004 std-004] [-4 -4 -4 -4] [-4 -4 -4 -4] [-4 -4 -4 -4] [-4 -4 -4 -4] [4 4 4 4] [4 4 4 4] [4 4 4 4] [4 4 4 4] [4 4 4 4] [4 4 4 4] [4 4 4 4] [4 4 4 4] [{4 4} {4 4} {4 4} {4 4}] [obj-004 obj-004 obj-004 obj-004] [[0 1 2 3] [1 2 3 4] [2 3 4 5] [3 4 5 6]] [[vec-004 vec-005 vec-006 vec-007] [vec-004 vec-005 vec-006 vec-007] [vec-004 vec-005 vec-006 vec-007] [vec-004 vec-005 vec-006 vec-007]] [[{4 4} {5 5} {6 6} {7 7}] [{4 4} {5 5} {6 6} {7 7}] [{4 4} {5 5} {6 6} {7 7}] [{4 4} {5 5} {6 6} {7 7}]]}
  2555  [005][evt]: {false str-005 -5 -5 -5 -5 5 5 5 5 5 5 5 5 {5 5} obj-5 [false false false false false true false false false false] [-5 -5 -5 -5 -5 -5 -5 -5 -5 -5] [-5 -5 -5 -5 -5 -5 -5 -5 -5 -5] [-5 -5 -5 -5 -5 -5 -5 -5 -5 -5] [-5 -5 -5 -5 -5 -5 -5 -5 -5 -5] [5 5 5 5 5 5 5 5 5 5] [5 5 5 5 5 5 5 5 5 5] [5 5 5 5 5 5 5 5 5 5] [5 5 5 5 5 5 5 5 5 5] [5 5 5 5 5 5 5 5 5 5] [5 5 5 5 5 5 5 5 5 5] [5 5 5 5 5 5 5 5 5 5] [5 5 5 5 5 5 5 5 5 5] [{5 5} {5 5} {5 5} {5 5} {5 5} {5 5} {5 5} {5 5} {5 5} {5 5}] [obj-5 obj-5 obj-5 obj-5 obj-5 obj-5 obj-5 obj-5 obj-5 obj-5] 5 [false false false false true] [-5 -5 -5 -5 -5] [-5 -5 -5 -5 -5] [-5 -5 -5 -5 -5] [-5 -5 -5 -5 -5] [5 5 5 5 5] [5 5 5 5 5] [5 5 5 5 5] [5 5 5 5 5] [5 5 5 5 5] [5 5 5 5 5] [5 5 5 5 5] [5 5 5 5 5] [false false false false true] [std-005 std-005 std-005 std-005 std-005] [-5 -5 -5 -5 -5] [-5 -5 -5 -5 -5] [-5 -5 -5 -5 -5] [-5 -5 -5 -5 -5] [5 5 5 5 5] [5 5 5 5 5] [5 5 5 5 5] [5 5 5 5 5] [5 5 5 5 5] [5 5 5 5 5] [5 5 5 5 5] [5 5 5 5 5] [{5 5} {5 5} {5 5} {5 5} {5 5}] [obj-005 obj-005 obj-005 obj-005 obj-005] [[0 1 2 3] [1 2 3 4] [2 3 4 5] [3 4 5 6] [4 5 6 7]] [[vec-005 vec-006 vec-007 vec-008] [vec-005 vec-006 vec-007 vec-008] [vec-005 vec-006 vec-007 vec-008] [vec-005 vec-006 vec-007 vec-008] [vec-005 vec-006 vec-007 vec-008]] [[{5 5} {6 6} {7 7} {8 8}] [{5 5} {6 6} {7 7} {8 8}] [{5 5} {6 6} {7 7} {8 8}] [{5 5} {6 6} {7 7} {8 8}] [{5 5} {6 6} {7 7} {8 8}]]}
  2556  [006][evt]: {true str-006 -6 -6 -6 -6 6 6 6 6 6 6 6 6 {6 6} obj-6 [false false false false false false true false false false] [-6 -6 -6 -6 -6 -6 -6 -6 -6 -6] [-6 -6 -6 -6 -6 -6 -6 -6 -6 -6] [-6 -6 -6 -6 -6 -6 -6 -6 -6 -6] [-6 -6 -6 -6 -6 -6 -6 -6 -6 -6] [6 6 6 6 6 6 6 6 6 6] [6 6 6 6 6 6 6 6 6 6] [6 6 6 6 6 6 6 6 6 6] [6 6 6 6 6 6 6 6 6 6] [6 6 6 6 6 6 6 6 6 6] [6 6 6 6 6 6 6 6 6 6] [6 6 6 6 6 6 6 6 6 6] [6 6 6 6 6 6 6 6 6 6] [{6 6} {6 6} {6 6} {6 6} {6 6} {6 6} {6 6} {6 6} {6 6} {6 6}] [obj-6 obj-6 obj-6 obj-6 obj-6 obj-6 obj-6 obj-6 obj-6 obj-6] 6 [false false false false false true] [-6 -6 -6 -6 -6 -6] [-6 -6 -6 -6 -6 -6] [-6 -6 -6 -6 -6 -6] [-6 -6 -6 -6 -6 -6] [6 6 6 6 6 6] [6 6 6 6 6 6] [6 6 6 6 6 6] [6 6 6 6 6 6] [6 6 6 6 6 6] [6 6 6 6 6 6] [6 6 6 6 6 6] [6 6 6 6 6 6] [false false false false false true] [std-006 std-006 std-006 std-006 std-006 std-006] [-6 -6 -6 -6 -6 -6] [-6 -6 -6 -6 -6 -6] [-6 -6 -6 -6 -6 -6] [-6 -6 -6 -6 -6 -6] [6 6 6 6 6 6] [6 6 6 6 6 6] [6 6 6 6 6 6] [6 6 6 6 6 6] [6 6 6 6 6 6] [6 6 6 6 6 6] [6 6 6 6 6 6] [6 6 6 6 6 6] [{6 6} {6 6} {6 6} {6 6} {6 6} {6 6}] [obj-006 obj-006 obj-006 obj-006 obj-006 obj-006] [[0 1 2 3] [1 2 3 4] [2 3 4 5] [3 4 5 6] [4 5 6 7] [5 6 7 8]] [[vec-006 vec-007 vec-008 vec-009] [vec-006 vec-007 vec-008 vec-009] [vec-006 vec-007 vec-008 vec-009] [vec-006 vec-007 vec-008 vec-009] [vec-006 vec-007 vec-008 vec-009] [vec-006 vec-007 vec-008 vec-009]] [[{6 6} {7 7} {8 8} {9 9}] [{6 6} {7 7} {8 8} {9 9}] [{6 6} {7 7} {8 8} {9 9}] [{6 6} {7 7} {8 8} {9 9}] [{6 6} {7 7} {8 8} {9 9}] [{6 6} {7 7} {8 8} {9 9}]]}
  2557  [007][evt]: {false str-007 -7 -7 -7 -7 7 7 7 7 7 7 7 7 {7 7} obj-7 [false false false false false false false true false false] [-7 -7 -7 -7 -7 -7 -7 -7 -7 -7] [-7 -7 -7 -7 -7 -7 -7 -7 -7 -7] [-7 -7 -7 -7 -7 -7 -7 -7 -7 -7] [-7 -7 -7 -7 -7 -7 -7 -7 -7 -7] [7 7 7 7 7 7 7 7 7 7] [7 7 7 7 7 7 7 7 7 7] [7 7 7 7 7 7 7 7 7 7] [7 7 7 7 7 7 7 7 7 7] [7 7 7 7 7 7 7 7 7 7] [7 7 7 7 7 7 7 7 7 7] [7 7 7 7 7 7 7 7 7 7] [7 7 7 7 7 7 7 7 7 7] [{7 7} {7 7} {7 7} {7 7} {7 7} {7 7} {7 7} {7 7} {7 7} {7 7}] [obj-7 obj-7 obj-7 obj-7 obj-7 obj-7 obj-7 obj-7 obj-7 obj-7] 7 [false false false false false false true] [-7 -7 -7 -7 -7 -7 -7] [-7 -7 -7 -7 -7 -7 -7] [-7 -7 -7 -7 -7 -7 -7] [-7 -7 -7 -7 -7 -7 -7] [7 7 7 7 7 7 7] [7 7 7 7 7 7 7] [7 7 7 7 7 7 7] [7 7 7 7 7 7 7] [7 7 7 7 7 7 7] [7 7 7 7 7 7 7] [7 7 7 7 7 7 7] [7 7 7 7 7 7 7] [false false false false false false true] [std-007 std-007 std-007 std-007 std-007 std-007 std-007] [-7 -7 -7 -7 -7 -7 -7] [-7 -7 -7 -7 -7 -7 -7] [-7 -7 -7 -7 -7 -7 -7] [-7 -7 -7 -7 -7 -7 -7] [7 7 7 7 7 7 7] [7 7 7 7 7 7 7] [7 7 7 7 7 7 7] [7 7 7 7 7 7 7] [7 7 7 7 7 7 7] [7 7 7 7 7 7 7] [7 7 7 7 7 7 7] [7 7 7 7 7 7 7] [{7 7} {7 7} {7 7} {7 7} {7 7} {7 7} {7 7}] [obj-007 obj-007 obj-007 obj-007 obj-007 obj-007 obj-007] [[0 1 2 3] [1 2 3 4] [2 3 4 5] [3 4 5 6] [4 5 6 7] [5 6 7 8] [6 7 8 9]] [[vec-007 vec-008 vec-009 vec-010] [vec-007 vec-008 vec-009 vec-010] [vec-007 vec-008 vec-009 vec-010] [vec-007 vec-008 vec-009 vec-010] [vec-007 vec-008 vec-009 vec-010] [vec-007 vec-008 vec-009 vec-010] [vec-007 vec-008 vec-009 vec-010]] [[{7 7} {8 8} {9 9} {10 10}] [{7 7} {8 8} {9 9} {10 10}] [{7 7} {8 8} {9 9} {10 10}] [{7 7} {8 8} {9 9} {10 10}] [{7 7} {8 8} {9 9} {10 10}] [{7 7} {8 8} {9 9} {10 10}] [{7 7} {8 8} {9 9} {10 10}]]}
  2558  [008][evt]: {true str-008 -8 -8 -8 -8 8 8 8 8 8 8 8 8 {8 8} obj-8 [false false false false false false false false true false] [-8 -8 -8 -8 -8 -8 -8 -8 -8 -8] [-8 -8 -8 -8 -8 -8 -8 -8 -8 -8] [-8 -8 -8 -8 -8 -8 -8 -8 -8 -8] [-8 -8 -8 -8 -8 -8 -8 -8 -8 -8] [8 8 8 8 8 8 8 8 8 8] [8 8 8 8 8 8 8 8 8 8] [8 8 8 8 8 8 8 8 8 8] [8 8 8 8 8 8 8 8 8 8] [8 8 8 8 8 8 8 8 8 8] [8 8 8 8 8 8 8 8 8 8] [8 8 8 8 8 8 8 8 8 8] [8 8 8 8 8 8 8 8 8 8] [{8 8} {8 8} {8 8} {8 8} {8 8} {8 8} {8 8} {8 8} {8 8} {8 8}] [obj-8 obj-8 obj-8 obj-8 obj-8 obj-8 obj-8 obj-8 obj-8 obj-8] 8 [false false false false false false false true] [-8 -8 -8 -8 -8 -8 -8 -8] [-8 -8 -8 -8 -8 -8 -8 -8] [-8 -8 -8 -8 -8 -8 -8 -8] [-8 -8 -8 -8 -8 -8 -8 -8] [8 8 8 8 8 8 8 8] [8 8 8 8 8 8 8 8] [8 8 8 8 8 8 8 8] [8 8 8 8 8 8 8 8] [8 8 8 8 8 8 8 8] [8 8 8 8 8 8 8 8] [8 8 8 8 8 8 8 8] [8 8 8 8 8 8 8 8] [false false false false false false false true] [std-008 std-008 std-008 std-008 std-008 std-008 std-008 std-008] [-8 -8 -8 -8 -8 -8 -8 -8] [-8 -8 -8 -8 -8 -8 -8 -8] [-8 -8 -8 -8 -8 -8 -8 -8] [-8 -8 -8 -8 -8 -8 -8 -8] [8 8 8 8 8 8 8 8] [8 8 8 8 8 8 8 8] [8 8 8 8 8 8 8 8] [8 8 8 8 8 8 8 8] [8 8 8 8 8 8 8 8] [8 8 8 8 8 8 8 8] [8 8 8 8 8 8 8 8] [8 8 8 8 8 8 8 8] [{8 8} {8 8} {8 8} {8 8} {8 8} {8 8} {8 8} {8 8}] [obj-008 obj-008 obj-008 obj-008 obj-008 obj-008 obj-008 obj-008] [[0 1 2 3] [1 2 3 4] [2 3 4 5] [3 4 5 6] [4 5 6 7] [5 6 7 8] [6 7 8 9] [7 8 9 10]] [[vec-008 vec-009 vec-010 vec-011] [vec-008 vec-009 vec-010 vec-011] [vec-008 vec-009 vec-010 vec-011] [vec-008 vec-009 vec-010 vec-011] [vec-008 vec-009 vec-010 vec-011] [vec-008 vec-009 vec-010 vec-011] [vec-008 vec-009 vec-010 vec-011] [vec-008 vec-009 vec-010 vec-011]] [[{8 8} {9 9} {10 10} {11 11}] [{8 8} {9 9} {10 10} {11 11}] [{8 8} {9 9} {10 10} {11 11}] [{8 8} {9 9} {10 10} {11 11}] [{8 8} {9 9} {10 10} {11 11}] [{8 8} {9 9} {10 10} {11 11}] [{8 8} {9 9} {10 10} {11 11}] [{8 8} {9 9} {10 10} {11 11}]]}
  2559  [009][evt]: {false str-009 -9 -9 -9 -9 9 9 9 9 9 9 9 9 {9 9} obj-9 [false false false false false false false false false true] [-9 -9 -9 -9 -9 -9 -9 -9 -9 -9] [-9 -9 -9 -9 -9 -9 -9 -9 -9 -9] [-9 -9 -9 -9 -9 -9 -9 -9 -9 -9] [-9 -9 -9 -9 -9 -9 -9 -9 -9 -9] [9 9 9 9 9 9 9 9 9 9] [9 9 9 9 9 9 9 9 9 9] [9 9 9 9 9 9 9 9 9 9] [9 9 9 9 9 9 9 9 9 9] [9 9 9 9 9 9 9 9 9 9] [9 9 9 9 9 9 9 9 9 9] [9 9 9 9 9 9 9 9 9 9] [9 9 9 9 9 9 9 9 9 9] [{9 9} {9 9} {9 9} {9 9} {9 9} {9 9} {9 9} {9 9} {9 9} {9 9}] [obj-9 obj-9 obj-9 obj-9 obj-9 obj-9 obj-9 obj-9 obj-9 obj-9] 9 [false false false false false false false false true] [-9 -9 -9 -9 -9 -9 -9 -9 -9] [-9 -9 -9 -9 -9 -9 -9 -9 -9] [-9 -9 -9 -9 -9 -9 -9 -9 -9] [-9 -9 -9 -9 -9 -9 -9 -9 -9] [9 9 9 9 9 9 9 9 9] [9 9 9 9 9 9 9 9 9] [9 9 9 9 9 9 9 9 9] [9 9 9 9 9 9 9 9 9] [9 9 9 9 9 9 9 9 9] [9 9 9 9 9 9 9 9 9] [9 9 9 9 9 9 9 9 9] [9 9 9 9 9 9 9 9 9] [false false false false false false false false true] [std-009 std-009 std-009 std-009 std-009 std-009 std-009 std-009 std-009] [-9 -9 -9 -9 -9 -9 -9 -9 -9] [-9 -9 -9 -9 -9 -9 -9 -9 -9] [-9 -9 -9 -9 -9 -9 -9 -9 -9] [-9 -9 -9 -9 -9 -9 -9 -9 -9] [9 9 9 9 9 9 9 9 9] [9 9 9 9 9 9 9 9 9] [9 9 9 9 9 9 9 9 9] [9 9 9 9 9 9 9 9 9] [9 9 9 9 9 9 9 9 9] [9 9 9 9 9 9 9 9 9] [9 9 9 9 9 9 9 9 9] [9 9 9 9 9 9 9 9 9] [{9 9} {9 9} {9 9} {9 9} {9 9} {9 9} {9 9} {9 9} {9 9}] [obj-009 obj-009 obj-009 obj-009 obj-009 obj-009 obj-009 obj-009 obj-009] [[0 1 2 3] [1 2 3 4] [2 3 4 5] [3 4 5 6] [4 5 6 7] [5 6 7 8] [6 7 8 9] [7 8 9 10] [8 9 10 11]] [[vec-009 vec-010 vec-011 vec-012] [vec-009 vec-010 vec-011 vec-012] [vec-009 vec-010 vec-011 vec-012] [vec-009 vec-010 vec-011 vec-012] [vec-009 vec-010 vec-011 vec-012] [vec-009 vec-010 vec-011 vec-012] [vec-009 vec-010 vec-011 vec-012] [vec-009 vec-010 vec-011 vec-012] [vec-009 vec-010 vec-011 vec-012]] [[{9 9} {10 10} {11 11} {12 12}] [{9 9} {10 10} {11 11} {12 12}] [{9 9} {10 10} {11 11} {12 12}] [{9 9} {10 10} {11 11} {12 12}] [{9 9} {10 10} {11 11} {12 12}] [{9 9} {10 10} {11 11} {12 12}] [{9 9} {10 10} {11 11} {12 12}] [{9 9} {10 10} {11 11} {12 12}] [{9 9} {10 10} {11 11} {12 12}]]}
  2560  `,
  2561  			sinfos: []rbytes.StreamerInfo{
  2562  				rdict.StreamerOf(sictx, reflect.TypeOf([]float64{})),
  2563  				rdict.StreamerOf(sictx, reflect.TypeOf([]string{})),
  2564  				rdict.StreamerOf(sictx, reflect.TypeOf([][]float64{})),
  2565  				rdict.StreamerOf(sictx, reflect.TypeOf([][]string{})),
  2566  				rdict.StreamerOf(sictx, reflect.TypeOf(TNestedP2{})),
  2567  				rdict.StreamerOf(sictx, reflect.TypeOf([]TNestedP2{})),
  2568  				rdict.StreamerOf(sictx, reflect.TypeOf([][]TNestedP2{})),
  2569  				rdict.StreamerOf(sictx, reflect.TypeOf(TNestedEvent1{})),
  2570  			},
  2571  		},
  2572  	} {
  2573  		t.Run(tc.name, func(t *testing.T) {
  2574  			fname := filepath.Join(tmp, tc.name+".root")
  2575  
  2576  			if tc.skip {
  2577  				t.Skipf("skipping %s...", tc.name)
  2578  			}
  2579  
  2580  			for i := range tc.sinfos {
  2581  				rdict.StreamerInfos.Add(tc.sinfos[i])
  2582  			}
  2583  
  2584  			func() {
  2585  				f, err := riofs.Create(fname)
  2586  				if err != nil {
  2587  					t.Fatalf("could not create write ROOT file %q: %v", fname, err)
  2588  				}
  2589  				defer f.Close()
  2590  
  2591  				tw, err := NewWriter(f, treeName, tc.wvars, tc.wopts...)
  2592  				if err != nil {
  2593  					t.Fatalf("could not create tree writer: %v", err)
  2594  				}
  2595  				defer tw.Close()
  2596  
  2597  				if got, want := len(tw.Branches()), len(tc.wvars); got != want {
  2598  					t.Fatalf("invalid number of branches: got=%d, want=%d", got, want)
  2599  				}
  2600  
  2601  				for i, b := range tw.Branches() {
  2602  					if got, want := b.Name(), tc.wvars[i].Name; got != want {
  2603  						t.Fatalf("branch[%d]: got=%q, want=%q", i, got, want)
  2604  					}
  2605  					if got, want := b.Title(), tc.btitles[i]; got != want {
  2606  						t.Fatalf("branch[%d]: got=%q, want=%q", i, got, want)
  2607  					}
  2608  				}
  2609  
  2610  				if got, want := len(tw.Leaves()), len(tc.wvars); got != want {
  2611  					leaves := make([]string, got)
  2612  					for i, l := range tw.Leaves() {
  2613  						leaves[i] = l.Name()
  2614  					}
  2615  					t.Fatalf("invalid number of leaves: got=%d, want=%d (leaves: %q)", got, want, leaves)
  2616  				}
  2617  
  2618  				for i, leaf := range tw.Leaves() {
  2619  					if got, want := leaf.Name(), tc.wvars[i].Name; got != want {
  2620  						t.Fatalf("leaf[%d]: got=%q, want=%q", i, got, want)
  2621  					}
  2622  					if got, want := leaf.Title(), tc.ltitles[i]; got != want {
  2623  						t.Fatalf("leaf[%d]: got=%q, want=%q", i, got, want)
  2624  					}
  2625  				}
  2626  
  2627  				total := 0
  2628  				for i := range int(tc.nevts) {
  2629  					want := tc.want(i)
  2630  					for j, wvar := range tc.wvars {
  2631  						v := reflect.ValueOf(wvar.Value).Elem()
  2632  						o := reflect.ValueOf(want).Field(j)
  2633  						v.Set(o)
  2634  					}
  2635  					n, err := tw.Write()
  2636  					if err != nil {
  2637  						t.Fatalf("could not write event %d: %v", i, err)
  2638  					}
  2639  					total += n
  2640  				}
  2641  
  2642  				if got, want := tw.Entries(), tc.nevts; got != want {
  2643  					t.Fatalf("invalid number of entries: got=%d, want=%d", got, want)
  2644  				}
  2645  				if got, want := total, tc.total; got != want {
  2646  					t.Errorf("invalid number of bytes written: got=%d, want=%d", got, want)
  2647  				}
  2648  
  2649  				err = tw.Close()
  2650  				if err != nil {
  2651  					t.Fatalf("could not close tree writer: %v", err)
  2652  				}
  2653  
  2654  				err = f.Close()
  2655  				if err != nil {
  2656  					t.Fatalf("could not close write ROOT file %q: %v", fname, err)
  2657  				}
  2658  			}()
  2659  
  2660  			func() {
  2661  				f, err := riofs.Open(fname)
  2662  				if err != nil {
  2663  					t.Fatalf("could not opend read ROOT file %q: %+v", fname, err)
  2664  				}
  2665  				defer f.Close()
  2666  
  2667  				obj, err := f.Get(treeName)
  2668  				if err != nil {
  2669  					t.Fatalf("could not get ROOT tree %q: %+v", treeName, err)
  2670  				}
  2671  				tree := obj.(Tree)
  2672  
  2673  				if got, want := tree.Entries(), tc.nevts; got != want {
  2674  					t.Fatalf("invalid number of events: got=%v, want=%v", got, want)
  2675  				}
  2676  
  2677  				for i, b := range tree.Branches() {
  2678  					if got, want := b.Name(), tc.wvars[i].Name; got != want {
  2679  						t.Fatalf("branch[%d]: got=%q, want=%q", i, got, want)
  2680  					}
  2681  					if got, want := b.Title(), tc.btitles[i]; got != want {
  2682  						t.Fatalf("branch[%d]: got=%q, want=%q", i, got, want)
  2683  					}
  2684  				}
  2685  
  2686  				for i, leaf := range tree.Leaves() {
  2687  					if got, want := leaf.Name(), tc.wvars[i].Name; got != want {
  2688  						t.Fatalf("leaf[%d]: got=%q, want=%q", i, got, want)
  2689  					}
  2690  					if got, want := leaf.Title(), tc.ltitles[i]; got != want {
  2691  						t.Fatalf("leaf[%d]: got=%q, want=%q", i, got, want)
  2692  					}
  2693  				}
  2694  
  2695  				rvars := tc.rvars
  2696  				if len(rvars) != len(tc.wvars) {
  2697  					t.Fatalf("invalid number of read-vars: got=%d, want=%d", len(rvars), len(tc.wvars))
  2698  				}
  2699  
  2700  				for i, rvar := range rvars {
  2701  					wvar := tc.wvars[i]
  2702  					if got, want := rvar.Name, wvar.Name; got != want {
  2703  						t.Fatalf("invalid name for rvar[%d]: got=%q, want=%q", i, got, want)
  2704  					}
  2705  					wtyp := reflect.TypeOf(wvar.Value)
  2706  					rtyp := reflect.TypeOf(rvar.Value)
  2707  					if got, want := rtyp, wtyp; got != want {
  2708  						t.Fatalf("invalid type for rvar[%d]: got=%v, want=%v", i, got, want)
  2709  					}
  2710  				}
  2711  
  2712  				r, err := NewReader(tree, rvars)
  2713  				if err != nil {
  2714  					t.Fatalf("could not create reader: %+v", err)
  2715  				}
  2716  				defer r.Close()
  2717  
  2718  				nn := 0
  2719  				err = r.Read(func(ctx RCtx) error {
  2720  					i := int(ctx.Entry)
  2721  					want := tc.want(i)
  2722  					for i, rvar := range rvars {
  2723  						var (
  2724  							want = reflect.ValueOf(want).Field(i).Interface()
  2725  							got  = reflect.ValueOf(rvar.Value).Elem().Interface()
  2726  						)
  2727  						if !reflect.DeepEqual(got, want) {
  2728  							return fmt.Errorf(
  2729  								"entry[%d]: invalid scan-value[%s]:\ngot= %v\nwant=%v",
  2730  								ctx.Entry, tc.wvars[i].Name, got, want,
  2731  							)
  2732  						}
  2733  					}
  2734  					nn++
  2735  					return nil
  2736  				})
  2737  				if err != nil {
  2738  					t.Fatalf("could not read tree: %+v", err)
  2739  				}
  2740  
  2741  				if got, want := nn, int(tc.nevts); got != want {
  2742  					t.Fatalf("invalid number of events: got=%d, want=%d", got, want)
  2743  				}
  2744  			}()
  2745  
  2746  			if rtests.HasROOT && len(tc.macro) != 0 {
  2747  				ofile := filepath.Join(tmp, tc.name+".txt")
  2748  				out, err := rtests.RunCxxROOT("scan", []byte(tc.macro), fname, treeName, ofile)
  2749  				if err != nil {
  2750  					t.Fatalf("could not run C++ ROOT: %+v\noutput:\n%s", err, out)
  2751  				}
  2752  
  2753  				got, err := os.ReadFile(ofile)
  2754  				if err != nil {
  2755  					t.Fatalf("could not read C++ ROOT scan file %q: %+v\noutput:\n%s", ofile, err, out)
  2756  				}
  2757  
  2758  				if got, want := string(got), tc.cxx; got != want {
  2759  					t.Fatalf("invalid ROOT scan:\ngot:\n%v\nwant:\n%v\noutput:\n%s", got, want, out)
  2760  				}
  2761  			}
  2762  		})
  2763  	}
  2764  }
  2765  
  2766  func TestTreeWriteSubdir(t *testing.T) {
  2767  	tmp, err := os.MkdirTemp("", "groot-rtree-")
  2768  	if err != nil {
  2769  		t.Fatalf("could not create dir: %v", err)
  2770  	}
  2771  	defer os.RemoveAll(tmp)
  2772  
  2773  	fname := filepath.Join(tmp, "tree-subdir.root")
  2774  
  2775  	f, err := riofs.Create(fname)
  2776  	if err != nil {
  2777  		t.Fatalf("%+v", err)
  2778  	}
  2779  	defer f.Close()
  2780  
  2781  	dir, err := riofs.Dir(f).Mkdir("dir-1/dir-11/dir-111")
  2782  	if err != nil {
  2783  		t.Fatalf("could not create sub-dir hierarchy: %+v", err)
  2784  	}
  2785  
  2786  	var data struct {
  2787  		I32 int32   `groot:"i32"`
  2788  		F64 float64 `groot:"f64"`
  2789  	}
  2790  
  2791  	ntup, err := NewWriter(dir, "ntup", WriteVarsFromStruct(&data))
  2792  	if err != nil {
  2793  		t.Fatalf("could not create tree: %+v", err)
  2794  	}
  2795  	defer ntup.Close()
  2796  
  2797  	for i := range 5 {
  2798  		data.I32 = int32(i)
  2799  		data.F64 = float64(i)
  2800  		_, err = ntup.Write()
  2801  		if err != nil {
  2802  			t.Fatalf("could not write event %d: %+v", i, err)
  2803  		}
  2804  	}
  2805  
  2806  	err = ntup.Close()
  2807  	if err != nil {
  2808  		t.Fatalf("could not close tree: %+v", err)
  2809  	}
  2810  
  2811  	err = f.Close()
  2812  	if err != nil {
  2813  		t.Fatalf("could not close file: %+v", err)
  2814  	}
  2815  
  2816  	if !rtests.HasROOT {
  2817  		return
  2818  	}
  2819  
  2820  	code := `#include <iostream>
  2821  #include "TDirectory.h"
  2822  #include "TFile.h"
  2823  #include "TTree.h"
  2824  #include "TTreePlayer.h"
  2825  
  2826  void scan(const char *fname, const char *tree, const char *oname) {
  2827  	auto f = TFile::Open(fname);
  2828  	gDirectory->cd("dir-1");
  2829  	gDirectory->cd("dir-11");
  2830  	gDirectory->cd("dir-111");
  2831  
  2832  	auto t = (TTree*)gDirectory->Get(tree);
  2833  	if (!t) {
  2834  		std::cerr << "could not fetch TTree [" << tree << "] from file [" << fname << "]\n";
  2835  		exit(1);
  2836  	}
  2837  	auto player = dynamic_cast<TTreePlayer*>(t->GetPlayer());
  2838  	player->SetScanRedirect(kTRUE);
  2839  	player->SetScanFileName(oname);
  2840  	t->SetScanField(0);
  2841  	t->Scan("i32:f64");
  2842  }
  2843  `
  2844  	ofile := filepath.Join(tmp, "tree-subdir.txt")
  2845  	out, err := rtests.RunCxxROOT("scan", []byte(code), fname, "ntup", ofile)
  2846  	if err != nil {
  2847  		t.Fatalf("could not run C++ ROOT: %+v\noutput:\n%s", err, out)
  2848  	}
  2849  
  2850  	got, err := os.ReadFile(ofile)
  2851  	if err != nil {
  2852  		t.Fatalf("could not read C++ ROOT scan file %q: %+v\noutput:\n%s", ofile, err, out)
  2853  	}
  2854  
  2855  	want := `************************************
  2856  *    Row   *       i32 *       f64 *
  2857  ************************************
  2858  *        0 *         0 *         0 *
  2859  *        1 *         1 *         1 *
  2860  *        2 *         2 *         2 *
  2861  *        3 *         3 *         3 *
  2862  *        4 *         4 *         4 *
  2863  ************************************
  2864  `
  2865  	if got, want := string(got), want; got != want {
  2866  		t.Fatalf("invalid ROOT scan:\ngot:\n%v\nwant:\n%v\noutput:\n%s", got, want, out)
  2867  	}
  2868  
  2869  }
  2870  
  2871  var sumBenchReadTreeF64 = 0.0
  2872  
  2873  func BenchmarkReadTreeF64(b *testing.B) {
  2874  	tmp, err := os.MkdirTemp("", "groot-rtree-read-tree-f64-")
  2875  	if err != nil {
  2876  		b.Fatal(err)
  2877  	}
  2878  	defer os.RemoveAll(tmp)
  2879  
  2880  	const nevts = 10000
  2881  
  2882  	fname := path.Join(tmp, "f64.root")
  2883  	func() {
  2884  		b.StopTimer()
  2885  		defer b.StartTimer()
  2886  
  2887  		f, err := riofs.Create(fname, riofs.WithoutCompression())
  2888  		if err != nil {
  2889  			b.Fatal(err)
  2890  		}
  2891  		defer f.Close()
  2892  
  2893  		var data struct {
  2894  			F64 float64
  2895  		}
  2896  		wvars := []WriteVar{
  2897  			{Name: "F64", Value: &data.F64},
  2898  		}
  2899  		tree, err := NewWriter(f, "tree", wvars, WithoutCompression())
  2900  		if err != nil {
  2901  			b.Fatal(err)
  2902  		}
  2903  		defer tree.Close()
  2904  
  2905  		rnd := rand.New(rand.NewSource(1234))
  2906  		for range nevts {
  2907  			data.F64 = rnd.Float64() * 10
  2908  
  2909  			_, err = tree.Write()
  2910  			if err != nil {
  2911  				b.Fatal(err)
  2912  			}
  2913  		}
  2914  
  2915  		err = tree.Close()
  2916  		if err != nil {
  2917  			b.Fatal(err)
  2918  		}
  2919  
  2920  		err = f.Close()
  2921  		if err != nil {
  2922  			b.Fatal(err)
  2923  		}
  2924  	}()
  2925  
  2926  	b.StopTimer()
  2927  	f, err := riofs.Open(fname)
  2928  	if err != nil {
  2929  		b.Fatal(err)
  2930  	}
  2931  	defer f.Close()
  2932  
  2933  	o, err := f.Get("tree")
  2934  	if err != nil {
  2935  		b.Fatal(err)
  2936  	}
  2937  
  2938  	tree := o.(Tree)
  2939  
  2940  	var data struct {
  2941  		F64 float64
  2942  	}
  2943  
  2944  	rvars := ReadVarsFromStruct(&data)
  2945  	r, err := NewReader(tree, rvars)
  2946  	if err != nil {
  2947  		b.Fatal(err)
  2948  	}
  2949  	defer r.Close()
  2950  
  2951  	b.StartTimer()
  2952  	b.ReportAllocs()
  2953  	b.ResetTimer()
  2954  
  2955  	for i := 0; i < b.N; i++ {
  2956  		b.StopTimer()
  2957  		r.r.reset()
  2958  		b.StartTimer()
  2959  
  2960  		err = r.Read(func(RCtx) error {
  2961  			sumBenchReadTreeF64 += data.F64
  2962  			return nil
  2963  		})
  2964  		if err != nil {
  2965  			b.Fatal(err)
  2966  		}
  2967  	}
  2968  }
  2969  
  2970  var sumBenchReadTreeSliF64 = 0
  2971  
  2972  func BenchmarkReadTreeSliF64(b *testing.B) {
  2973  	tmp, err := os.MkdirTemp("", "groot-rtree-read-tree-sli-f64s-")
  2974  	if err != nil {
  2975  		b.Fatal(err)
  2976  	}
  2977  	defer os.RemoveAll(tmp)
  2978  
  2979  	const nevts = 1000
  2980  
  2981  	for _, sz := range []int{0, 1, 2, 4, 8, 16, 64, 128, 512, 1024, 1024 * 1024} {
  2982  		fname := path.Join(tmp, fmt.Sprintf("f64s-%d.root", sz))
  2983  		func() {
  2984  			b.StopTimer()
  2985  			defer b.StartTimer()
  2986  
  2987  			f, err := riofs.Create(fname, riofs.WithoutCompression())
  2988  			if err != nil {
  2989  				b.Fatal(err)
  2990  			}
  2991  			defer f.Close()
  2992  
  2993  			var data struct {
  2994  				N   int32
  2995  				Sli []float64
  2996  			}
  2997  			wvars := []WriteVar{
  2998  				{Name: "N", Value: &data.N},
  2999  				{Name: "Sli", Value: &data.Sli, Count: "N"},
  3000  			}
  3001  			tree, err := NewWriter(f, "tree", wvars, WithoutCompression())
  3002  			if err != nil {
  3003  				b.Fatal(err)
  3004  			}
  3005  			defer tree.Close()
  3006  
  3007  			rnd := rand.New(rand.NewSource(1234))
  3008  			for range nevts {
  3009  				data.N = int32(rnd.Float64() * 100)
  3010  				data.Sli = make([]float64, int(data.N))
  3011  				for j := range data.Sli {
  3012  					data.Sli[j] = rnd.Float64() * 10
  3013  				}
  3014  
  3015  				_, err = tree.Write()
  3016  				if err != nil {
  3017  					b.Fatal(err)
  3018  				}
  3019  			}
  3020  
  3021  			err = tree.Close()
  3022  			if err != nil {
  3023  				b.Fatal(err)
  3024  			}
  3025  
  3026  			err = f.Close()
  3027  			if err != nil {
  3028  				b.Fatal(err)
  3029  			}
  3030  		}()
  3031  
  3032  		b.Run(fmt.Sprintf("%d", sz), func(b *testing.B) {
  3033  			b.StopTimer()
  3034  			f, err := riofs.Open(fname)
  3035  			if err != nil {
  3036  				b.Fatal(err)
  3037  			}
  3038  			defer f.Close()
  3039  
  3040  			o, err := f.Get("tree")
  3041  			if err != nil {
  3042  				b.Fatal(err)
  3043  			}
  3044  
  3045  			tree := o.(Tree)
  3046  
  3047  			var data struct {
  3048  				N   int32
  3049  				Sli []float64
  3050  			}
  3051  
  3052  			rvars := ReadVarsFromStruct(&data)
  3053  			r, err := NewReader(tree, rvars)
  3054  			if err != nil {
  3055  				b.Fatal(err)
  3056  			}
  3057  			defer r.Close()
  3058  
  3059  			b.StartTimer()
  3060  			b.ReportAllocs()
  3061  			b.ResetTimer()
  3062  
  3063  			for i := 0; i < b.N; i++ {
  3064  				b.StopTimer()
  3065  				r.r.reset()
  3066  				data.N = 0
  3067  				data.Sli = data.Sli[:0]
  3068  				b.StartTimer()
  3069  
  3070  				err = r.Read(func(RCtx) error {
  3071  					sumBenchReadTreeSliF64 += len(data.Sli)
  3072  					return nil
  3073  				})
  3074  				if err != nil {
  3075  					b.Fatal(err)
  3076  				}
  3077  			}
  3078  		})
  3079  	}
  3080  }
  3081  
  3082  type TNestedStruct1 struct {
  3083  	RunNbr int64            `groot:"runnbr"`
  3084  	EvtNbr int64            `groot:"evtnbr"`
  3085  	P3     TNestedStruct1P3 `groot:"p3"`
  3086  }
  3087  
  3088  type TNestedStruct1P3 struct {
  3089  	Px float64 `groot:"px"`
  3090  	Py float64 `groot:"py"`
  3091  	Pz float64 `groot:"pz"`
  3092  }
  3093  
  3094  type TNestedStruct2 struct {
  3095  	RunNbr int64            `groot:"runnbr"`
  3096  	EvtNbr int64            `groot:"evtnbr"`
  3097  	P3     TNestedStruct1P3 `groot:"p3"`
  3098  	F32s   []float32        `groot:"f32s"`
  3099  }
  3100  
  3101  type TNestedStruct3 struct {
  3102  	RunNbr int64            `groot:"runnbr"`
  3103  	EvtNbr int64            `groot:"evtnbr"`
  3104  	P3     TNestedStruct1P3 `groot:"p3"`
  3105  	F32s   []float32        `groot:"f32s"`
  3106  }
  3107  
  3108  type TNestedP2 struct {
  3109  	Px float64 `groot:"px"`
  3110  	Py float32 `groot:"py"`
  3111  }
  3112  
  3113  type TNestedEvent1 struct {
  3114  	B   bool            `groot:"Bool"`
  3115  	Str string          `groot:"Str"`
  3116  	I8  int8            `groot:"I8"`
  3117  	I16 int16           `groot:"I16"`
  3118  	I32 int32           `groot:"I32"`
  3119  	I64 int64           `groot:"I64"`
  3120  	U8  uint8           `groot:"U8"`
  3121  	U16 uint16          `groot:"U16"`
  3122  	U32 uint32          `groot:"U32"`
  3123  	U64 uint64          `groot:"U64"`
  3124  	F32 float32         `groot:"F32"`
  3125  	F64 float64         `groot:"F64"`
  3126  	D16 root.Float16    `groot:"D16"`
  3127  	D32 root.Double32   `groot:"D32"`
  3128  	P2  TNestedP2       `groot:"P2"`
  3129  	Obj rbase.ObjString `groot:"Obj"`
  3130  
  3131  	ArrBs [10]bool `groot:"ArrBs[10]"`
  3132  	//ArrStr [10]string `groot:"ArrStr[10]"`
  3133  	ArrI8  [10]int8            `groot:"ArrI8[10]"`
  3134  	ArrI16 [10]int16           `groot:"ArrI16[10]"`
  3135  	ArrI32 [10]int32           `groot:"ArrI32[10]"`
  3136  	ArrI64 [10]int64           `groot:"ArrI64[10]"`
  3137  	ArrU8  [10]uint8           `groot:"ArrU8[10]"`
  3138  	ArrU16 [10]uint16          `groot:"ArrU16[10]"`
  3139  	ArrU32 [10]uint32          `groot:"ArrU32[10]"`
  3140  	ArrU64 [10]uint64          `groot:"ArrU64[10]"`
  3141  	ArrF32 [10]float32         `groot:"ArrF32[10]"`
  3142  	ArrF64 [10]float64         `groot:"ArrF64[10]"`
  3143  	ArrD16 [10]root.Float16    `groot:"ArrD16[10]"`
  3144  	ArrD32 [10]root.Double32   `groot:"ArrD32[10]"`
  3145  	ArrP2  [10]TNestedP2       `groot:"ArrP2[10]"`
  3146  	ArrObj [10]rbase.ObjString `groot:"ArrObj[10]"`
  3147  
  3148  	N     int32  `groot:"N"`
  3149  	SliBs []bool `groot:"SliBs[N]"`
  3150  	//	SliStr []string        `groot:"SliStr[N]"`
  3151  	SliI8  []int8          `groot:"SliI8[N]"`
  3152  	SliI16 []int16         `groot:"SliI16[N]"`
  3153  	SliI32 []int32         `groot:"SliI32[N]"`
  3154  	SliI64 []int64         `groot:"SliI64[N]"`
  3155  	SliU8  []uint8         `groot:"SliU8[N]"`
  3156  	SliU16 []uint16        `groot:"SliU16[N]"`
  3157  	SliU32 []uint32        `groot:"SliU32[N]"`
  3158  	SliU64 []uint64        `groot:"SliU64[N]"`
  3159  	SliF32 []float32       `groot:"SliF32[N]"`
  3160  	SliF64 []float64       `groot:"SliF64[N]"`
  3161  	SliD16 []root.Float16  `groot:"SliD16[N]"`
  3162  	SliD32 []root.Double32 `groot:"SliD32[N]"`
  3163  	//	SliP2  []TNestedP2     `groot:"SliP2[N]"` // FIXME(sbinet): var-len-array of non-builtins has extra bytes in front
  3164  	//	SliObj  []rbase.ObjString     `groot:"SliObj[N]"` // FIXME(sbinet): var-len-array of non-builtins has extra bytes in front
  3165  
  3166  	StdVecBs  []bool            `groot:"StdVecBs"`
  3167  	StdVecStr []string          `groot:"StdVecStr"`
  3168  	StdVecI8  []int8            `groot:"StdVecI8"`
  3169  	StdVecI16 []int16           `groot:"StdVecI16"`
  3170  	StdVecI32 []int32           `groot:"StdVecI32"`
  3171  	StdVecI64 []int64           `groot:"StdVecI64"`
  3172  	StdVecU8  []uint8           `groot:"StdVecU8"`
  3173  	StdVecU16 []uint16          `groot:"StdVecU16"`
  3174  	StdVecU32 []uint32          `groot:"StdVecU32"`
  3175  	StdVecU64 []uint64          `groot:"StdVecU64"`
  3176  	StdVecF32 []float32         `groot:"StdVecF32"`
  3177  	StdVecF64 []float64         `groot:"StdVecF64"`
  3178  	StdVecD16 []root.Float16    `groot:"StdVecD16"`
  3179  	StdVecD32 []root.Double32   `groot:"StdVecD32"`
  3180  	StdVecP2  []TNestedP2       `groot:"StdVecP2"`
  3181  	StdVecObj []rbase.ObjString `groot:"StdVecObj"`
  3182  
  3183  	StdVecVecF64 [][]float64   `groot:"StdVecVecF64"`
  3184  	StdVecVecStr [][]string    `groot:"StdVecVecStr"`
  3185  	StdVecVecP2  [][]TNestedP2 `groot:"StdVecVecP2"`
  3186  }
  3187  
  3188  func (TNestedEvent1) want(i int64) (data TNestedEvent1) {
  3189  	data.B = i%2 == 0
  3190  	data.Str = fmt.Sprintf("str-%03d", i)
  3191  	data.I8 = int8(-i)
  3192  	data.I16 = int16(-i)
  3193  	data.I32 = int32(-i)
  3194  	data.I64 = int64(-i)
  3195  	data.U8 = uint8(i)
  3196  	data.U16 = uint16(i)
  3197  	data.U32 = uint32(i)
  3198  	data.U64 = uint64(i)
  3199  	data.F32 = float32(i)
  3200  	data.F64 = float64(i)
  3201  	data.D16 = root.Float16(i)
  3202  	data.D32 = root.Double32(i)
  3203  	data.P2 = TNestedP2{Px: float64(i), Py: float32(i)}
  3204  	data.Obj = *rbase.NewObjString(fmt.Sprintf("obj-%d", i))
  3205  
  3206  	for ii := range data.ArrI32 {
  3207  		data.ArrBs[ii] = ii == int(i)
  3208  		//data.ArrStr[ii] = fmt.Sprintf("arr-%03d", i)
  3209  		data.ArrI8[ii] = int8(-i)
  3210  		data.ArrI16[ii] = int16(-i)
  3211  		data.ArrI32[ii] = int32(-i)
  3212  		data.ArrI64[ii] = int64(-i)
  3213  		data.ArrU8[ii] = uint8(i)
  3214  		data.ArrU16[ii] = uint16(i)
  3215  		data.ArrU32[ii] = uint32(i)
  3216  		data.ArrU64[ii] = uint64(i)
  3217  		data.ArrF32[ii] = float32(i)
  3218  		data.ArrF64[ii] = float64(i)
  3219  		data.ArrD16[ii] = root.Float16(i)
  3220  		data.ArrD32[ii] = root.Double32(i)
  3221  		data.ArrP2[ii] = TNestedP2{
  3222  			Px: float64(i),
  3223  			Py: float32(i),
  3224  		}
  3225  		data.ArrObj[ii] = *rbase.NewObjString(fmt.Sprintf("obj-%d", i))
  3226  	}
  3227  	data.N = int32(i) % 10
  3228  
  3229  	switch data.N {
  3230  	case 0:
  3231  		data.SliBs = nil
  3232  		//		data.SliStr = nil
  3233  		data.SliI8 = nil
  3234  		data.SliI16 = nil
  3235  		data.SliI32 = nil
  3236  		data.SliI64 = nil
  3237  		data.SliU8 = nil
  3238  		data.SliU16 = nil
  3239  		data.SliU32 = nil
  3240  		data.SliU64 = nil
  3241  		data.SliF32 = nil
  3242  		data.SliF64 = nil
  3243  		data.SliD16 = nil
  3244  		data.SliD32 = nil
  3245  		//		data.SliP2 = nil
  3246  		//		data.SliObj = nil
  3247  	default:
  3248  		data.SliBs = make([]bool, int(data.N))
  3249  		//		data.SliStr = make([]string, int(data.N))
  3250  		data.SliI8 = make([]int8, int(data.N))
  3251  		data.SliI16 = make([]int16, int(data.N))
  3252  		data.SliI32 = make([]int32, int(data.N))
  3253  		data.SliI64 = make([]int64, int(data.N))
  3254  		data.SliU8 = make([]uint8, int(data.N))
  3255  		data.SliU16 = make([]uint16, int(data.N))
  3256  		data.SliU32 = make([]uint32, int(data.N))
  3257  		data.SliU64 = make([]uint64, int(data.N))
  3258  		data.SliF32 = make([]float32, int(data.N))
  3259  		data.SliF64 = make([]float64, int(data.N))
  3260  		data.SliD16 = make([]root.Float16, int(data.N))
  3261  		data.SliD32 = make([]root.Double32, int(data.N))
  3262  		//		data.SliP2 = make([]TNestedP2, int(data.N))
  3263  		//		data.SliObj = make([]rbase.ObjString, int(data.N))
  3264  	}
  3265  	for ii := range int(data.N) {
  3266  		data.SliBs[ii] = (ii + 1) == int(i)
  3267  		//		data.SliStr[ii] = fmt.Sprintf("sli-%03d", i)
  3268  		data.SliI8[ii] = int8(-i)
  3269  		data.SliI16[ii] = int16(-i)
  3270  		data.SliI32[ii] = int32(-i)
  3271  		data.SliI64[ii] = int64(-i)
  3272  		data.SliU8[ii] = uint8(i)
  3273  		data.SliU16[ii] = uint16(i)
  3274  		data.SliU32[ii] = uint32(i)
  3275  		data.SliU64[ii] = uint64(i)
  3276  		data.SliF32[ii] = float32(i)
  3277  		data.SliF64[ii] = float64(i)
  3278  		data.SliD16[ii] = root.Float16(i)
  3279  		data.SliD32[ii] = root.Double32(i)
  3280  		//		data.SliP2[ii] = TNestedP2{
  3281  		//			Px: float64(i),
  3282  		//			Py: float32(i),
  3283  		//		}
  3284  		//		data.SliObj[ii] = *rbase.NewObjString(fmt.Sprintf("obj-%03d", i))
  3285  	}
  3286  
  3287  	switch data.N {
  3288  	case 0:
  3289  		data.StdVecBs = nil
  3290  		data.StdVecStr = nil
  3291  		data.StdVecI8 = nil
  3292  		data.StdVecI16 = nil
  3293  		data.StdVecI32 = nil
  3294  		data.StdVecI64 = nil
  3295  		data.StdVecU8 = nil
  3296  		data.StdVecU16 = nil
  3297  		data.StdVecU32 = nil
  3298  		data.StdVecU64 = nil
  3299  		data.StdVecF32 = nil
  3300  		data.StdVecF64 = nil
  3301  		data.StdVecD16 = nil
  3302  		data.StdVecD32 = nil
  3303  		data.StdVecP2 = nil
  3304  		data.StdVecObj = nil
  3305  	default:
  3306  		data.StdVecBs = make([]bool, int(data.N))
  3307  		data.StdVecStr = make([]string, int(data.N))
  3308  		data.StdVecI8 = make([]int8, int(data.N))
  3309  		data.StdVecI16 = make([]int16, int(data.N))
  3310  		data.StdVecI32 = make([]int32, int(data.N))
  3311  		data.StdVecI64 = make([]int64, int(data.N))
  3312  		data.StdVecU8 = make([]uint8, int(data.N))
  3313  		data.StdVecU16 = make([]uint16, int(data.N))
  3314  		data.StdVecU32 = make([]uint32, int(data.N))
  3315  		data.StdVecU64 = make([]uint64, int(data.N))
  3316  		data.StdVecF32 = make([]float32, int(data.N))
  3317  		data.StdVecF64 = make([]float64, int(data.N))
  3318  		data.StdVecD16 = make([]root.Float16, int(data.N))
  3319  		data.StdVecD32 = make([]root.Double32, int(data.N))
  3320  		data.StdVecP2 = make([]TNestedP2, int(data.N))
  3321  		data.StdVecObj = make([]rbase.ObjString, int(data.N))
  3322  	}
  3323  	for ii := range int(data.N) {
  3324  		data.StdVecBs[ii] = (ii + 1) == int(i)
  3325  		data.StdVecStr[ii] = fmt.Sprintf("std-%03d", i)
  3326  		data.StdVecI8[ii] = int8(-i)
  3327  		data.StdVecI16[ii] = int16(-i)
  3328  		data.StdVecI32[ii] = int32(-i)
  3329  		data.StdVecI64[ii] = int64(-i)
  3330  		data.StdVecU8[ii] = uint8(i)
  3331  		data.StdVecU16[ii] = uint16(i)
  3332  		data.StdVecU32[ii] = uint32(i)
  3333  		data.StdVecU64[ii] = uint64(i)
  3334  		data.StdVecF32[ii] = float32(i)
  3335  		data.StdVecF64[ii] = float64(i)
  3336  		data.StdVecD16[ii] = root.Float16(i)
  3337  		data.StdVecD32[ii] = root.Double32(i)
  3338  		data.StdVecP2[ii] = TNestedP2{
  3339  			Px: float64(i),
  3340  			Py: float32(i),
  3341  		}
  3342  		data.StdVecObj[ii] = *rbase.NewObjString(fmt.Sprintf("obj-%03d", i))
  3343  	}
  3344  
  3345  	switch data.N {
  3346  	case 0:
  3347  		data.StdVecVecF64 = nil
  3348  		data.StdVecVecStr = nil
  3349  		data.StdVecVecP2 = nil
  3350  	default:
  3351  		data.StdVecVecF64 = make([][]float64, data.N)
  3352  		data.StdVecVecStr = make([][]string, data.N)
  3353  		data.StdVecVecP2 = make([][]TNestedP2, data.N)
  3354  	}
  3355  	for ii := range int(data.N) {
  3356  		data.StdVecVecF64[ii] = []float64{
  3357  			float64(ii),
  3358  			float64(ii + 1),
  3359  			float64(ii + 2),
  3360  			float64(ii + 3),
  3361  		}
  3362  		data.StdVecVecStr[ii] = []string{
  3363  			fmt.Sprintf("vec-%03d", i),
  3364  			fmt.Sprintf("vec-%03d", i+1),
  3365  			fmt.Sprintf("vec-%03d", i+2),
  3366  			fmt.Sprintf("vec-%03d", i+3),
  3367  		}
  3368  		data.StdVecVecP2[ii] = []TNestedP2{
  3369  			{Px: float64(i), Py: float32(i)},
  3370  			{Px: float64(i + 1), Py: float32(i + 1)},
  3371  			{Px: float64(i + 2), Py: float32(i + 2)},
  3372  			{Px: float64(i + 3), Py: float32(i + 3)},
  3373  		}
  3374  	}
  3375  
  3376  	return data
  3377  }