github.com/wrgl/wrgl@v0.14.0/pkg/objects/float_list.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright © 2022 Wrangle Ltd
     3  
     4  package objects
     5  
     6  import (
     7  	"encoding/binary"
     8  	"io"
     9  	"math"
    10  )
    11  
    12  // FloatListEncoder encodes string slice. Max bytes size for each string is 65536 bytes
    13  type FloatListEncoder struct {
    14  	buf []byte
    15  }
    16  
    17  func NewFloatListEncoder() *FloatListEncoder {
    18  	return &FloatListEncoder{
    19  		buf: make([]byte, 0, 256),
    20  	}
    21  }
    22  
    23  func (e *FloatListEncoder) Encode(sl []float64) []byte {
    24  	l := uint32(len(sl))
    25  	bufLen := 8*int(l) + 4
    26  	if bufLen > cap(e.buf) {
    27  		e.buf = make([]byte, bufLen)
    28  	} else {
    29  		e.buf = e.buf[:bufLen]
    30  	}
    31  	binary.BigEndian.PutUint32(e.buf, l)
    32  	for i, f := range sl {
    33  		bits := math.Float64bits(f)
    34  		binary.BigEndian.PutUint64(e.buf[4+i*8:], bits)
    35  	}
    36  	return e.buf
    37  }
    38  
    39  // FloatListDecoder decodes string slice.
    40  type FloatListDecoder struct {
    41  	sl  []float64
    42  	buf []byte
    43  	pos int64
    44  }
    45  
    46  func NewFloatListDecoder(reuseRecords bool) *FloatListDecoder {
    47  	d := &FloatListDecoder{
    48  		buf: make([]byte, 8),
    49  	}
    50  	if reuseRecords {
    51  		d.sl = make([]float64, 0, 256)
    52  	}
    53  	return d
    54  }
    55  
    56  func (d *FloatListDecoder) makeFloatSlice(n uint32) []float64 {
    57  	if d.sl == nil {
    58  		return make([]float64, 0, n)
    59  	}
    60  	if n > uint32(cap(d.sl)) {
    61  		d.sl = make([]float64, n)
    62  	}
    63  	return d.sl[:0]
    64  }
    65  
    66  func (d *FloatListDecoder) Decode(b []byte) []float64 {
    67  	n := binary.BigEndian.Uint32(b)
    68  	sl := d.makeFloatSlice(n)
    69  	var i uint32
    70  	for i = 0; i < n; i++ {
    71  		bits := binary.BigEndian.Uint64(b[4+8*i:])
    72  		sl = append(sl, math.Float64frombits(bits))
    73  	}
    74  	return sl
    75  }
    76  
    77  func (d *FloatListDecoder) readUint32(r io.Reader) (uint32, error) {
    78  	n, err := r.Read(d.buf[:4])
    79  	if err != nil {
    80  		return 0, err
    81  	}
    82  	d.pos += int64(n)
    83  	return binary.BigEndian.Uint32(d.buf), nil
    84  }
    85  
    86  func (d *FloatListDecoder) readFloat64(r io.Reader) (float64, error) {
    87  	n, err := r.Read(d.buf)
    88  	if err != nil {
    89  		return 0, err
    90  	}
    91  	d.pos += int64(n)
    92  	bits := binary.BigEndian.Uint64(d.buf)
    93  	return math.Float64frombits(bits), nil
    94  }
    95  
    96  func (d *FloatListDecoder) Read(r io.Reader) (int64, []float64, error) {
    97  	d.pos = 0
    98  	n, err := d.readUint32(r)
    99  	if err != nil {
   100  		return d.pos, nil, err
   101  	}
   102  	sl := d.makeFloatSlice(n)
   103  	var i uint32
   104  	for i = 0; i < n; i++ {
   105  		f, err := d.readFloat64(r)
   106  		if err != nil {
   107  			return d.pos, nil, err
   108  		}
   109  		sl = append(sl, f)
   110  	}
   111  	return d.pos, sl, nil
   112  }