package array
import (
"bytes"
"fmt"
"reflect"
"strings"
"github.com/apache/arrow-go/v18/arrow"
"github.com/apache/arrow-go/v18/arrow/bitutil"
"github.com/apache/arrow-go/v18/arrow/decimal"
"github.com/apache/arrow-go/v18/arrow/internal/debug"
"github.com/apache/arrow-go/v18/arrow/memory"
"github.com/apache/arrow-go/v18/internal/json"
)
type baseDecimal[T interface {
decimal .DecimalTypes
decimal .Num [T ]
}] struct {
array
values []T
}
func newDecimalData[T interface {
decimal .DecimalTypes
decimal .Num [T ]
}](data arrow .ArrayData ) *baseDecimal [T ] {
a := &baseDecimal [T ]{}
a .refCount .Add (1 )
a .setData (data .(*Data ))
return a
}
func (a *baseDecimal [T ]) Value (i int ) T { return a .values [i ] }
func (a *baseDecimal [T ]) ValueStr (i int ) string {
if a .IsNull (i ) {
return NullValueStr
}
return a .GetOneForMarshal (i ).(string )
}
func (a *baseDecimal [T ]) Values () []T { return a .values }
func (a *baseDecimal [T ]) String () string {
o := new (strings .Builder )
o .WriteString ("[" )
for i := 0 ; i < a .Len (); i ++ {
if i > 0 {
fmt .Fprintf (o , " " )
}
switch {
case a .IsNull (i ):
o .WriteString (NullValueStr )
default :
fmt .Fprintf (o , "%v" , a .Value (i ))
}
}
o .WriteString ("]" )
return o .String ()
}
func (a *baseDecimal [T ]) setData (data *Data ) {
a .array .setData (data )
vals := data .buffers [1 ]
if vals != nil {
a .values = arrow .GetData [T ](vals .Bytes ())
beg := a .data .offset
end := beg + a .data .length
a .values = a .values [beg :end ]
}
}
func (a *baseDecimal [T ]) GetOneForMarshal (i int ) any {
if a .IsNull (i ) {
return nil
}
typ := a .DataType ().(arrow .DecimalType )
n , scale := a .Value (i ), typ .GetScale ()
return n .ToBigFloat (scale ).Text ('g' , int (typ .GetPrecision ()))
}
func (a *baseDecimal [T ]) MarshalJSON () ([]byte , error ) {
vals := make ([]any , a .Len ())
for i := 0 ; i < a .Len (); i ++ {
vals [i ] = a .GetOneForMarshal (i )
}
return json .Marshal (vals )
}
func arrayEqualDecimal[T interface {
decimal .DecimalTypes
decimal .Num [T ]
}](left , right *baseDecimal [T ]) bool {
for i := 0 ; i < left .Len (); i ++ {
if left .IsNull (i ) {
continue
}
if left .Value (i ) != right .Value (i ) {
return false
}
}
return true
}
type Decimal32 = baseDecimal [decimal .Decimal32 ]
func NewDecimal32Data (data arrow .ArrayData ) *Decimal32 {
return newDecimalData [decimal .Decimal32 ](data )
}
type Decimal64 = baseDecimal [decimal .Decimal64 ]
func NewDecimal64Data (data arrow .ArrayData ) *Decimal64 {
return newDecimalData [decimal .Decimal64 ](data )
}
type Decimal128 = baseDecimal [decimal .Decimal128 ]
func NewDecimal128Data (data arrow .ArrayData ) *Decimal128 {
return newDecimalData [decimal .Decimal128 ](data )
}
type Decimal256 = baseDecimal [decimal .Decimal256 ]
func NewDecimal256Data (data arrow .ArrayData ) *Decimal256 {
return newDecimalData [decimal .Decimal256 ](data )
}
type (
Decimal32Builder = baseDecimalBuilder [decimal .Decimal32 ]
Decimal64Builder = baseDecimalBuilder [decimal .Decimal64 ]
Decimal128Builder struct {
*baseDecimalBuilder [decimal .Decimal128 ]
}
)
func (b *Decimal128Builder ) NewDecimal128Array () *Decimal128 {
return b .NewDecimalArray ()
}
type Decimal256Builder struct {
*baseDecimalBuilder [decimal .Decimal256 ]
}
func (b *Decimal256Builder ) NewDecimal256Array () *Decimal256 {
return b .NewDecimalArray ()
}
type baseDecimalBuilder[T interface {
decimal .DecimalTypes
decimal .Num [T ]
}] struct {
builder
traits decimal .Traits [T ]
dtype arrow .DecimalType
data *memory .Buffer
rawData []T
}
func newDecimalBuilder[T interface {
decimal .DecimalTypes
decimal .Num [T ]
}, DT arrow .DecimalType ](mem memory .Allocator , dtype DT ) *baseDecimalBuilder [T ] {
bdb := &baseDecimalBuilder [T ]{
builder : builder {mem : mem },
dtype : dtype ,
}
bdb .refCount .Add (1 )
return bdb
}
func (b *baseDecimalBuilder [T ]) Type () arrow .DataType { return b .dtype }
func (b *baseDecimalBuilder [T ]) Release () {
debug .Assert (b .refCount .Load () > 0 , "too many releases" )
if b .refCount .Add (-1 ) == 0 {
if b .nullBitmap != nil {
b .nullBitmap .Release ()
b .nullBitmap = nil
}
if b .data != nil {
b .data .Release ()
b .data , b .rawData = nil , nil
}
}
}
func (b *baseDecimalBuilder [T ]) Append (v T ) {
b .Reserve (1 )
b .UnsafeAppend (v )
}
func (b *baseDecimalBuilder [T ]) UnsafeAppend (v T ) {
bitutil .SetBit (b .nullBitmap .Bytes (), b .length )
b .rawData [b .length ] = v
b .length ++
}
func (b *baseDecimalBuilder [T ]) AppendNull () {
b .Reserve (1 )
b .UnsafeAppendBoolToBitmap (false )
}
func (b *baseDecimalBuilder [T ]) AppendNulls (n int ) {
for i := 0 ; i < n ; i ++ {
b .AppendNull ()
}
}
func (b *baseDecimalBuilder [T ]) AppendEmptyValue () {
var empty T
b .Append (empty )
}
func (b *baseDecimalBuilder [T ]) AppendEmptyValues (n int ) {
for i := 0 ; i < n ; i ++ {
b .AppendEmptyValue ()
}
}
func (b *baseDecimalBuilder [T ]) UnsafeAppendBoolToBitmap (isValid bool ) {
if isValid {
bitutil .SetBit (b .nullBitmap .Bytes (), b .length )
} else {
b .nulls ++
}
b .length ++
}
func (b *baseDecimalBuilder [T ]) AppendValues (v []T , valid []bool ) {
if len (v ) != len (valid ) && len (valid ) != 0 {
panic ("len(v) != len(valid) && len(valid) != 0" )
}
if len (v ) == 0 {
return
}
b .Reserve (len (v ))
if len (v ) > 0 {
copy (b .rawData [b .length :], v )
}
b .unsafeAppendBoolsToBitmap (valid , len (v ))
}
func (b *baseDecimalBuilder [T ]) init (capacity int ) {
b .builder .init (capacity )
b .data = memory .NewResizableBuffer (b .mem )
bytesN := int (reflect .TypeFor [T ]().Size ()) * capacity
b .data .Resize (bytesN )
b .rawData = arrow .GetData [T ](b .data .Bytes ())
}
func (b *baseDecimalBuilder [T ]) Reserve (n int ) {
b .reserve (n , b .Resize )
}
func (b *baseDecimalBuilder [T ]) Resize (n int ) {
nBuilder := n
if n < minBuilderCapacity {
n = minBuilderCapacity
}
if b .capacity == 0 {
b .init (n )
} else {
b .resize (nBuilder , b .init )
b .data .Resize (b .traits .BytesRequired (n ))
b .rawData = arrow .GetData [T ](b .data .Bytes ())
}
}
func (b *baseDecimalBuilder [T ]) NewDecimalArray () (a *baseDecimal [T ]) {
data := b .newData ()
a = newDecimalData [T ](data )
data .Release ()
return
}
func (b *baseDecimalBuilder [T ]) NewArray () arrow .Array {
return b .NewDecimalArray ()
}
func (b *baseDecimalBuilder [T ]) newData () (data *Data ) {
bytesRequired := b .traits .BytesRequired (b .length )
if bytesRequired > 0 && bytesRequired < b .data .Len () {
b .data .Resize (bytesRequired )
}
data = NewData (b .dtype , b .length , []*memory .Buffer {b .nullBitmap , b .data }, nil , b .nulls , 0 )
b .reset ()
if b .data != nil {
b .data .Release ()
b .data , b .rawData = nil , nil
}
return
}
func (b *baseDecimalBuilder [T ]) AppendValueFromString (s string ) error {
if s == NullValueStr {
b .AppendNull ()
return nil
}
val , err := b .traits .FromString (s , b .dtype .GetPrecision (), b .dtype .GetScale ())
if err != nil {
b .AppendNull ()
return err
}
b .Append (val )
return nil
}
func (b *baseDecimalBuilder [T ]) UnmarshalOne (dec *json .Decoder ) error {
t , err := dec .Token ()
if err != nil {
return err
}
var token T
switch v := t .(type ) {
case float64 :
token , err = b .traits .FromFloat64 (v , b .dtype .GetPrecision (), b .dtype .GetScale ())
if err != nil {
return err
}
b .Append (token )
case string :
token , err = b .traits .FromString (v , b .dtype .GetPrecision (), b .dtype .GetScale ())
if err != nil {
return err
}
b .Append (token )
case json .Number :
token , err = b .traits .FromString (v .String (), b .dtype .GetPrecision (), b .dtype .GetScale ())
if err != nil {
return err
}
b .Append (token )
case nil :
b .AppendNull ()
default :
return &json .UnmarshalTypeError {
Value : fmt .Sprint (t ),
Type : reflect .TypeFor [T ](),
Offset : dec .InputOffset (),
}
}
return nil
}
func (b *baseDecimalBuilder [T ]) Unmarshal (dec *json .Decoder ) error {
for dec .More () {
if err := b .UnmarshalOne (dec ); err != nil {
return err
}
}
return nil
}
func (b *baseDecimalBuilder [T ]) UnmarshalJSON (data []byte ) error {
dec := json .NewDecoder (bytes .NewReader (data ))
t , err := dec .Token ()
if err != nil {
return err
}
if delim , ok := t .(json .Delim ); !ok || delim != '[' {
return fmt .Errorf ("decimal builder must unpack from json array, found %s" , delim )
}
return b .Unmarshal (dec )
}
func NewDecimal32Builder (mem memory .Allocator , dtype *arrow .Decimal32Type ) *Decimal32Builder {
b := newDecimalBuilder [decimal .Decimal32 ](mem , dtype )
b .traits = decimal .Dec32Traits
return b
}
func NewDecimal64Builder (mem memory .Allocator , dtype *arrow .Decimal64Type ) *Decimal64Builder {
b := newDecimalBuilder [decimal .Decimal64 ](mem , dtype )
b .traits = decimal .Dec64Traits
return b
}
func NewDecimal128Builder (mem memory .Allocator , dtype *arrow .Decimal128Type ) *Decimal128Builder {
b := newDecimalBuilder [decimal .Decimal128 ](mem , dtype )
b .traits = decimal .Dec128Traits
return &Decimal128Builder {b }
}
func NewDecimal256Builder (mem memory .Allocator , dtype *arrow .Decimal256Type ) *Decimal256Builder {
b := newDecimalBuilder [decimal .Decimal256 ](mem , dtype )
b .traits = decimal .Dec256Traits
return &Decimal256Builder {b }
}
var (
_ arrow .Array = (*Decimal32 )(nil )
_ arrow .Array = (*Decimal64 )(nil )
_ arrow .Array = (*Decimal128 )(nil )
_ arrow .Array = (*Decimal256 )(nil )
_ Builder = (*Decimal32Builder )(nil )
_ Builder = (*Decimal64Builder )(nil )
_ Builder = (*Decimal128Builder )(nil )
_ Builder = (*Decimal256Builder )(nil )
_ arrow .TypedArray [decimal .Decimal32 ] = (*Decimal32 )(nil )
_ arrow .TypedArray [decimal .Decimal64 ] = (*Decimal64 )(nil )
_ arrow .TypedArray [decimal .Decimal128 ] = (*Decimal128 )(nil )
_ arrow .TypedArray [decimal .Decimal256 ] = (*Decimal256 )(nil )
)
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .