go-hep.org/x/hep@v0.38.1/groot/rbytes/wbuffer.go (about)

     1  // Copyright ©2018 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 rbytes
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/binary"
    10  	"encoding/hex"
    11  	"fmt"
    12  	"io"
    13  	"math"
    14  	"reflect"
    15  
    16  	"go-hep.org/x/hep/groot/root"
    17  	"go-hep.org/x/hep/groot/rvers"
    18  )
    19  
    20  type wbuff struct {
    21  	p []byte // buffer of data to write on
    22  	c int    // current position in buffer of data
    23  }
    24  
    25  func (w *wbuff) Write(p []byte) (int, error) {
    26  	if w.c >= len(w.p) {
    27  		return 0, io.EOF
    28  	}
    29  	n := copy(w.p[w.c:], p)
    30  	w.c += n
    31  	return n, nil
    32  }
    33  
    34  // grow grows the buffer's capacity, if necessary, to guarantee space foranother n bytes.
    35  // After grow(n), at least n bytes can be written to the buffer without
    36  // another allocation.
    37  // If n is negative, grow will panic.
    38  func (w *wbuff) grow(n int) {
    39  	if n < 0 {
    40  		panic(fmt.Errorf("rbytes: negative count"))
    41  	}
    42  	if n == 0 {
    43  		return
    44  	}
    45  	var (
    46  		plen = len(w.p)
    47  		pcap = cap(w.p)
    48  		nlen = plen + n
    49  	)
    50  	if nlen < pcap {
    51  		w.p = w.p[:nlen]
    52  		return
    53  	}
    54  	if pcap < nlen {
    55  		const sz = 4 * 1024
    56  		pcap = ((nlen / sz) + 1) * sz
    57  	}
    58  	w.p = append(w.p[:cap(w.p)], make([]byte, 2*pcap)...)
    59  	w.p = w.p[:nlen:cap(w.p)]
    60  }
    61  
    62  // WBuffer is a write-only ROOT buffer for streaming.
    63  type WBuffer struct {
    64  	w      wbuff
    65  	err    error
    66  	offset uint32
    67  	refs   map[any]int64
    68  	sictx  StreamerInfoContext
    69  }
    70  
    71  func NewWBuffer(data []byte, refs map[any]int64, offset uint32, ctx StreamerInfoContext) *WBuffer {
    72  	if refs == nil {
    73  		refs = make(map[any]int64)
    74  	}
    75  
    76  	return &WBuffer{
    77  		w:      wbuff{p: data, c: 0},
    78  		refs:   refs,
    79  		offset: offset,
    80  		sictx:  ctx,
    81  	}
    82  }
    83  
    84  // StreamerInfo returns the named StreamerInfo.
    85  // If version is negative, the latest version should be returned.
    86  func (w *WBuffer) StreamerInfo(name string, version int) (StreamerInfo, error) {
    87  	if w.sictx == nil {
    88  		return nil, fmt.Errorf("rbytes: no streamers")
    89  	}
    90  	return w.sictx.StreamerInfo(name, version)
    91  }
    92  
    93  func (w *WBuffer) Grow(n int)     { w.w.grow(n) }
    94  func (w *WBuffer) buffer() []byte { return w.w.p[:w.w.c] }
    95  func (w *WBuffer) Bytes() []byte  { return w.w.p[:w.w.c] }
    96  
    97  func (w *WBuffer) Err() error       { return w.err }
    98  func (w *WBuffer) SetErr(err error) { w.err = err }
    99  
   100  func (w *WBuffer) Pos() int64 {
   101  	return int64(w.w.c) + int64(w.offset)
   102  }
   103  
   104  func (w *WBuffer) Len() int64 {
   105  	return int64(w.w.c)
   106  }
   107  
   108  func (w *WBuffer) SetPos(pos int64) { w.setPos(pos) }
   109  func (w *WBuffer) setPos(pos int64) {
   110  	pos -= int64(w.offset)
   111  	w.w.c = int(pos)
   112  }
   113  
   114  func (w *WBuffer) DumpHex(n int) {
   115  	buf := w.buffer()
   116  	if len(buf) > n {
   117  		buf = buf[:n]
   118  	}
   119  	fmt.Printf("--- hex --- (pos=%d len=%d end=%d)\n%s\n", w.Pos(), n, w.Len(), string(hex.Dump(buf)))
   120  }
   121  
   122  func (w *WBuffer) Write(p []byte) (int, error) {
   123  	if w.err != nil {
   124  		return 0, w.err
   125  	}
   126  	w.w.grow(len(p))
   127  	n, err := w.w.Write(p)
   128  	w.err = err
   129  	return n, w.err
   130  }
   131  
   132  func (w *WBuffer) WriteHeader(typename string, vers int16) Header {
   133  	hdr := Header{
   134  		Name: typename,
   135  		Pos:  w.Pos(),
   136  		Vers: vers,
   137  	}
   138  	if w.err != nil {
   139  		return hdr
   140  	}
   141  
   142  	w.w.grow(6)
   143  	w.writeU32(0) // byte-count placeholder
   144  	w.writeU16(uint16(vers))
   145  
   146  	return hdr
   147  }
   148  
   149  func (w *WBuffer) SetHeader(hdr Header) (int, error) {
   150  	if w.err != nil {
   151  		return 0, w.err
   152  	}
   153  
   154  	cur := w.Pos()
   155  	cnt := cur - hdr.Pos - 4
   156  	w.setPos(hdr.Pos)
   157  	w.WriteU32(uint32(cnt | kByteCountMask))
   158  	w.setPos(cur)
   159  
   160  	return int(cnt + 4), w.err
   161  }
   162  
   163  func (w *WBuffer) WriteObject(obj Marshaler) {
   164  	if w.err != nil {
   165  		return
   166  	}
   167  
   168  	if v := reflect.ValueOf(obj); (v == reflect.Value{}) || v.IsNil() {
   169  		w.WriteU32(0) // NULL pointer
   170  		return
   171  	}
   172  
   173  	_, w.err = obj.MarshalROOT(w)
   174  }
   175  
   176  func (w *WBuffer) WriteObjectAny(obj root.Object) {
   177  	if w.err != nil {
   178  		return
   179  	}
   180  
   181  	if v := reflect.ValueOf(obj); (v == reflect.Value{}) || v.IsNil() {
   182  		w.WriteU32(0) // NULL pointer
   183  		return
   184  	}
   185  
   186  	pos := w.Pos()
   187  	w.WriteU32(0) // placeholder for bytecount.
   188  
   189  	bcnt := w.WriteClass(pos, obj)
   190  	if w.err != nil {
   191  		return
   192  	}
   193  	end := w.Pos()
   194  	w.setPos(pos)
   195  	w.writeU32(bcnt)
   196  	w.setPos(end)
   197  }
   198  
   199  func (w *WBuffer) WriteClass(beg int64, obj root.Object) uint32 {
   200  	if w.err != nil {
   201  		return 0
   202  	}
   203  
   204  	start := w.Pos()
   205  	if ref64, dup := w.refs[obj]; dup {
   206  		// we've already seen this value.
   207  		w.WriteU32(uint32(ref64))
   208  		bcnt := w.Pos() - start
   209  		return uint32(bcnt | kByteCountMask)
   210  	}
   211  
   212  	class := obj.Class()
   213  	ref64, ok := w.refs[class]
   214  	if !ok {
   215  		// first time we see this type
   216  		w.WriteU32(uint32(kNewClassTag))
   217  		w.WriteCString(class)
   218  		w.refs[class] = (start + kMapOffset) | kClassMask
   219  
   220  		// add to refs before writing value, to handle self reference
   221  		w.refs[obj] = beg + kMapOffset
   222  
   223  		mobj := obj.(Marshaler)
   224  		if _, err := mobj.MarshalROOT(w); err != nil {
   225  			return 0
   226  		}
   227  
   228  		bcnt := w.Pos() - start
   229  		return uint32(bcnt | kByteCountMask)
   230  	}
   231  
   232  	// first time we see this value
   233  	w.WriteU32(uint32(ref64) | kClassMask)
   234  	if _, err := obj.(Marshaler).MarshalROOT(w); err != nil {
   235  		return 0
   236  	}
   237  
   238  	w.refs[obj] = beg + kMapOffset
   239  	bcnt := w.Pos() - start
   240  	return uint32(bcnt | kByteCountMask)
   241  }
   242  
   243  func (w *WBuffer) write(v []byte) {
   244  	if w.err != nil {
   245  		return
   246  	}
   247  	w.w.grow(len(v))
   248  	_, w.err = w.w.Write(v)
   249  }
   250  
   251  func (w *WBuffer) WriteI8(v int8) {
   252  	if w.err != nil {
   253  		return
   254  	}
   255  	w.w.grow(1)
   256  	w.writeI8(v)
   257  }
   258  
   259  func (w *WBuffer) writeI8(v int8) {
   260  	w.w.p[w.w.c] = byte(v)
   261  	w.w.c++
   262  }
   263  
   264  func (w *WBuffer) writeI32(v int32) {
   265  	const sz = 4
   266  	beg := w.w.c
   267  	end := w.w.c + sz
   268  	binary.BigEndian.PutUint32(w.w.p[beg:end], uint32(v))
   269  	w.w.c += sz
   270  }
   271  
   272  func (w *WBuffer) WriteU8(v uint8) {
   273  	if w.err != nil {
   274  		return
   275  	}
   276  	w.w.grow(1)
   277  	w.writeU8(v)
   278  }
   279  
   280  func (w *WBuffer) writeU8(v uint8) {
   281  	w.w.p[w.w.c] = v
   282  	w.w.c++
   283  }
   284  
   285  func (w *WBuffer) writeU16(v uint16) {
   286  	const sz = 2
   287  	beg := w.w.c
   288  	end := w.w.c + sz
   289  	binary.BigEndian.PutUint16(w.w.p[beg:end], uint16(v))
   290  	w.w.c += sz
   291  }
   292  
   293  func (w *WBuffer) writeU32(v uint32) {
   294  	const sz = 4
   295  	beg := w.w.c
   296  	end := w.w.c + sz
   297  	binary.BigEndian.PutUint32(w.w.p[beg:end], v)
   298  	w.w.c += sz
   299  }
   300  
   301  func (w *WBuffer) writeF32(v float32) {
   302  	const sz = 4
   303  	beg := w.w.c
   304  	end := w.w.c + sz
   305  	binary.BigEndian.PutUint32(w.w.p[beg:end], math.Float32bits(v))
   306  	w.w.c += sz
   307  }
   308  
   309  func (w *WBuffer) WriteF16(v root.Float16, elm StreamerElement) {
   310  	if w.err != nil {
   311  		return
   312  	}
   313  	switch {
   314  	case elm != nil && elm.Factor() != 0:
   315  		// range specified.
   316  		// normalize the float64 to the range and convert to an integer,
   317  		// according to the provided scaling factor.
   318  		var (
   319  			x   = float64(v)
   320  			min = float64(elm.XMin())
   321  			max = float64(elm.XMax())
   322  		)
   323  		if x < min {
   324  			x = min
   325  		}
   326  		if x > max {
   327  			x = max
   328  		}
   329  		u32 := uint32(0.5 + elm.Factor()*(x-min))
   330  		w.w.grow(4)
   331  		w.writeU32(u32)
   332  	default:
   333  		var nbits uint32
   334  		if elm != nil {
   335  			nbits = uint32(elm.XMin())
   336  		}
   337  		if nbits == 0 {
   338  			nbits = 12
   339  		}
   340  		// no range, but nbits.
   341  		// truncate mantissa to nbits.
   342  		u32 := math.Float32bits(float32(v))
   343  		exp := uint8(0x000000ff & ((u32 << 1) >> 24))
   344  		man := uint16(((1 << (nbits + 1)) - 1) & (u32 >> (23 - nbits - 1)))
   345  		man++
   346  		man = man >> 1
   347  		if man&1<<nbits != 0 {
   348  			man = (1 << nbits) - 1
   349  		}
   350  		if v < 0 {
   351  			man |= 1 << (nbits + 1)
   352  		}
   353  		w.w.grow(3)
   354  		w.writeU8(exp)
   355  		w.writeU16(man)
   356  	}
   357  }
   358  
   359  func (w *WBuffer) WriteD32(v root.Double32, elm StreamerElement) {
   360  	if w.err != nil {
   361  		return
   362  	}
   363  	switch {
   364  	case elm != nil && elm.Factor() != 0:
   365  		// range specified.
   366  		// normalize the float64 to the range and convert to an integer,
   367  		// according to the provided scaling factor.
   368  		var (
   369  			min = root.Double32(elm.XMin())
   370  			max = root.Double32(elm.XMax())
   371  		)
   372  		if v < min {
   373  			v = min
   374  		}
   375  		if v > max {
   376  			v = max
   377  		}
   378  		u32 := uint32(0.5 + elm.Factor()*float64(v-min))
   379  		w.w.grow(4)
   380  		w.writeU32(u32)
   381  	default:
   382  		var nbits uint32
   383  		if elm != nil {
   384  			nbits = uint32(elm.XMin())
   385  		}
   386  		switch {
   387  		case nbits == 0:
   388  			// no range, no bits: convert to float32
   389  			w.w.grow(4)
   390  			w.writeF32(float32(v))
   391  		default:
   392  			// no range, but nbits.
   393  			// truncate mantissa to nbits.
   394  			u32 := math.Float32bits(float32(v))
   395  			exp := uint8(0x000000ff & ((u32 << 1) >> 24))
   396  			man := uint16(((1 << (nbits + 1)) - 1) & (u32 >> (23 - nbits - 1)))
   397  			man++
   398  			man = man >> 1
   399  			if man&1<<nbits != 0 {
   400  				man = (1 << nbits) - 1
   401  			}
   402  			if v < 0 {
   403  				man |= 1 << (nbits + 1)
   404  			}
   405  			w.w.grow(3)
   406  			w.writeU8(exp)
   407  			w.writeU16(man)
   408  		}
   409  	}
   410  }
   411  
   412  func (w *WBuffer) WriteBool(v bool) {
   413  	var o uint8
   414  	if v {
   415  		o = 1
   416  	}
   417  	w.w.grow(1)
   418  	w.writeU8(o)
   419  }
   420  
   421  func (w *WBuffer) WriteStdString(v string) {
   422  	if w.err != nil {
   423  		return
   424  	}
   425  
   426  	hdr := w.WriteHeader("string", rvers.StreamerBaseSTL)
   427  	w.WriteString(v)
   428  	_, err := w.SetHeader(hdr)
   429  	if err != nil {
   430  		w.SetErr(err)
   431  	}
   432  }
   433  
   434  func (w *WBuffer) WriteString(v string) {
   435  	if w.err != nil {
   436  		return
   437  	}
   438  	l := len(v)
   439  	if l < 255 {
   440  		w.w.grow(1 + l)
   441  		w.writeU8(uint8(l))
   442  		if l > 0 {
   443  			w.write([]byte(v))
   444  		}
   445  		return
   446  	}
   447  	w.w.grow(1 + 4 + l)
   448  	w.writeU8(255)
   449  	w.writeU32(uint32(l))
   450  	w.write([]byte(v))
   451  }
   452  
   453  func (w *WBuffer) writeString(v string) {
   454  	if w.err != nil {
   455  		return
   456  	}
   457  	l := len(v)
   458  	if l < 255 {
   459  		w.writeU8(uint8(l))
   460  		w.write([]byte(v))
   461  		return
   462  	}
   463  	w.writeU8(255)
   464  	w.writeU32(uint32(l))
   465  	w.write([]byte(v))
   466  }
   467  
   468  func (w *WBuffer) WriteCString(v string) {
   469  	if w.err != nil {
   470  		return
   471  	}
   472  	b := []byte(v)
   473  	i := bytes.Index(b, []byte{0})
   474  	switch {
   475  	case i < 0:
   476  		b = append(b, 0)
   477  		w.write(b)
   478  	default:
   479  		b = b[:i+1]
   480  		w.write(b)
   481  	}
   482  }
   483  
   484  func (w *WBuffer) WriteStaticArrayI32(v []int32) {
   485  	if w.err != nil {
   486  		return
   487  	}
   488  	w.w.grow(4 + 4*len(v))
   489  	w.writeI32(int32(len(v)))
   490  	for _, v := range v {
   491  		w.writeI32(v)
   492  	}
   493  }
   494  
   495  func (w *WBuffer) WriteArrayBool(v []bool) {
   496  	if w.err != nil {
   497  		return
   498  	}
   499  	w.w.grow(len(v))
   500  	for _, v := range v {
   501  		var b byte = 0
   502  		if v {
   503  			b = 1
   504  		}
   505  		w.writeU8(b)
   506  	}
   507  }
   508  
   509  func (w *WBuffer) WriteArrayI8(v []int8) {
   510  	if w.err != nil {
   511  		return
   512  	}
   513  	w.w.grow(len(v))
   514  	for _, v := range v {
   515  		w.writeI8(v)
   516  	}
   517  }
   518  
   519  func (w *WBuffer) WriteArrayU8(v []uint8) {
   520  	if w.err != nil {
   521  		return
   522  	}
   523  	w.w.grow(len(v))
   524  	for _, v := range v {
   525  		w.writeU8(v)
   526  	}
   527  }
   528  
   529  func (w *WBuffer) WriteArrayF16(v []root.Float16, elm StreamerElement) {
   530  	for _, v := range v {
   531  		w.WriteF16(v, elm)
   532  	}
   533  }
   534  
   535  func (w *WBuffer) WriteArrayD32(v []root.Double32, elm StreamerElement) {
   536  	for _, v := range v {
   537  		w.WriteD32(v, elm)
   538  	}
   539  }
   540  
   541  func (w *WBuffer) strlen(v string) int {
   542  	l := len(v)
   543  	if l < 255 {
   544  		return 1 + l
   545  	}
   546  	return 1 + 4 + l
   547  }
   548  
   549  func (w *WBuffer) WriteArrayString(v []string) {
   550  	if w.err != nil {
   551  		return
   552  	}
   553  	n := 0
   554  	for _, v := range v {
   555  		n += w.strlen(v)
   556  	}
   557  	w.w.grow(n)
   558  
   559  	for _, v := range v {
   560  		w.writeString(v)
   561  	}
   562  }
   563  
   564  func (w *WBuffer) WriteStdVectorStrs(v []string) {
   565  	if w.err != nil {
   566  		return
   567  	}
   568  
   569  	hdr := w.WriteHeader("vector<string>", rvers.StreamerBaseSTL)
   570  	w.WriteI32(int32(len(v)))
   571  
   572  	n := 0
   573  	for _, v := range v {
   574  		n += w.strlen(v)
   575  	}
   576  	w.w.grow(n)
   577  
   578  	for _, v := range v {
   579  		w.writeString(v)
   580  	}
   581  	_, _ = w.SetHeader(hdr)
   582  }
   583  
   584  func (w *WBuffer) WriteStdBitset(v []uint8) {
   585  	n := len(v)
   586  	w.w.grow(n)
   587  	for i := range v {
   588  		w.writeU8(v[n-1-i])
   589  	}
   590  }
   591  
   592  var (
   593  	_ StreamerInfoContext = (*WBuffer)(nil)
   594  )