github.com/apache/arrow/go/v16@v16.1.0/arrow/array/booleanbuilder.go (about) 1 // Licensed to the Apache Software Foundation (ASF) under one 2 // or more contributor license agreements. See the NOTICE file 3 // distributed with this work for additional information 4 // regarding copyright ownership. The ASF licenses this file 5 // to you under the Apache License, Version 2.0 (the 6 // "License"); you may not use this file except in compliance 7 // with the License. You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 17 package array 18 19 import ( 20 "bytes" 21 "fmt" 22 "reflect" 23 "strconv" 24 "sync/atomic" 25 26 "github.com/apache/arrow/go/v16/arrow" 27 "github.com/apache/arrow/go/v16/arrow/bitutil" 28 "github.com/apache/arrow/go/v16/arrow/internal/debug" 29 "github.com/apache/arrow/go/v16/arrow/memory" 30 "github.com/apache/arrow/go/v16/internal/json" 31 ) 32 33 type BooleanBuilder struct { 34 builder 35 36 data *memory.Buffer 37 rawData []byte 38 } 39 40 func NewBooleanBuilder(mem memory.Allocator) *BooleanBuilder { 41 return &BooleanBuilder{builder: builder{refCount: 1, mem: mem}} 42 } 43 44 func (b *BooleanBuilder) Type() arrow.DataType { return arrow.FixedWidthTypes.Boolean } 45 46 // Release decreases the reference count by 1. 47 // When the reference count goes to zero, the memory is freed. 48 // Release may be called simultaneously from multiple goroutines. 49 func (b *BooleanBuilder) Release() { 50 debug.Assert(atomic.LoadInt64(&b.refCount) > 0, "too many releases") 51 52 if atomic.AddInt64(&b.refCount, -1) == 0 { 53 if b.nullBitmap != nil { 54 b.nullBitmap.Release() 55 b.nullBitmap = nil 56 } 57 if b.data != nil { 58 b.data.Release() 59 b.data = nil 60 b.rawData = nil 61 } 62 } 63 } 64 65 func (b *BooleanBuilder) Append(v bool) { 66 b.Reserve(1) 67 b.UnsafeAppend(v) 68 } 69 70 func (b *BooleanBuilder) AppendByte(v byte) { 71 b.Reserve(1) 72 b.UnsafeAppend(v != 0) 73 } 74 75 func (b *BooleanBuilder) AppendNull() { 76 b.Reserve(1) 77 b.UnsafeAppendBoolToBitmap(false) 78 } 79 80 func (b *BooleanBuilder) AppendNulls(n int) { 81 for i := 0; i < n; i++ { 82 b.AppendNull() 83 } 84 } 85 86 func (b *BooleanBuilder) AppendEmptyValue() { 87 b.Reserve(1) 88 b.UnsafeAppend(false) 89 } 90 91 func (b *BooleanBuilder) AppendEmptyValues(n int) { 92 for i := 0; i < n; i++ { 93 b.AppendEmptyValue() 94 } 95 } 96 97 func (b *BooleanBuilder) AppendValueFromString(s string) error { 98 if s == NullValueStr { 99 b.AppendNull() 100 return nil 101 } 102 val, err := strconv.ParseBool(s) 103 if err != nil { 104 return err 105 } 106 b.Append(val) 107 return nil 108 } 109 110 func (b *BooleanBuilder) UnsafeAppend(v bool) { 111 bitutil.SetBit(b.nullBitmap.Bytes(), b.length) 112 if v { 113 bitutil.SetBit(b.rawData, b.length) 114 } else { 115 bitutil.ClearBit(b.rawData, b.length) 116 } 117 b.length++ 118 } 119 120 func (b *BooleanBuilder) AppendValues(v []bool, valid []bool) { 121 if len(v) != len(valid) && len(valid) != 0 { 122 panic("len(v) != len(valid) && len(valid) != 0") 123 } 124 125 if len(v) == 0 { 126 return 127 } 128 129 b.Reserve(len(v)) 130 for i, vv := range v { 131 bitutil.SetBitTo(b.rawData, b.length+i, vv) 132 } 133 b.builder.unsafeAppendBoolsToBitmap(valid, len(v)) 134 } 135 136 func (b *BooleanBuilder) init(capacity int) { 137 b.builder.init(capacity) 138 139 b.data = memory.NewResizableBuffer(b.mem) 140 bytesN := arrow.BooleanTraits.BytesRequired(capacity) 141 b.data.Resize(bytesN) 142 b.rawData = b.data.Bytes() 143 } 144 145 // Reserve ensures there is enough space for appending n elements 146 // by checking the capacity and calling Resize if necessary. 147 func (b *BooleanBuilder) Reserve(n int) { 148 b.builder.reserve(n, b.Resize) 149 } 150 151 // Resize adjusts the space allocated by b to n elements. If n is greater than b.Cap(), 152 // additional memory will be allocated. If n is smaller, the allocated memory may reduced. 153 func (b *BooleanBuilder) Resize(n int) { 154 if n < minBuilderCapacity { 155 n = minBuilderCapacity 156 } 157 158 if b.capacity == 0 { 159 b.init(n) 160 } else { 161 b.builder.resize(n, b.init) 162 b.data.Resize(arrow.BooleanTraits.BytesRequired(n)) 163 b.rawData = b.data.Bytes() 164 } 165 } 166 167 // NewArray creates a Boolean array from the memory buffers used by the builder and resets the BooleanBuilder 168 // so it can be used to build a new array. 169 func (b *BooleanBuilder) NewArray() arrow.Array { 170 return b.NewBooleanArray() 171 } 172 173 // NewBooleanArray creates a Boolean array from the memory buffers used by the builder and resets the BooleanBuilder 174 // so it can be used to build a new array. 175 func (b *BooleanBuilder) NewBooleanArray() (a *Boolean) { 176 data := b.newData() 177 a = NewBooleanData(data) 178 data.Release() 179 return 180 } 181 182 func (b *BooleanBuilder) newData() *Data { 183 bytesRequired := arrow.BooleanTraits.BytesRequired(b.length) 184 if bytesRequired > 0 && bytesRequired < b.data.Len() { 185 // trim buffers 186 b.data.Resize(bytesRequired) 187 } 188 res := NewData(arrow.FixedWidthTypes.Boolean, b.length, []*memory.Buffer{b.nullBitmap, b.data}, nil, b.nulls, 0) 189 b.reset() 190 191 if b.data != nil { 192 b.data.Release() 193 b.data = nil 194 b.rawData = nil 195 } 196 197 return res 198 } 199 200 func (b *BooleanBuilder) UnmarshalOne(dec *json.Decoder) error { 201 t, err := dec.Token() 202 if err != nil { 203 return err 204 } 205 206 switch v := t.(type) { 207 case bool: 208 b.Append(v) 209 case string: 210 val, err := strconv.ParseBool(v) 211 if err != nil { 212 return err 213 } 214 b.Append(val) 215 case json.Number: 216 val, err := strconv.ParseBool(v.String()) 217 if err != nil { 218 return err 219 } 220 b.Append(val) 221 case nil: 222 b.AppendNull() 223 default: 224 return &json.UnmarshalTypeError{ 225 Value: fmt.Sprint(t), 226 Type: reflect.TypeOf(true), 227 Offset: dec.InputOffset(), 228 } 229 } 230 return nil 231 } 232 233 func (b *BooleanBuilder) Unmarshal(dec *json.Decoder) error { 234 for dec.More() { 235 if err := b.UnmarshalOne(dec); err != nil { 236 return err 237 } 238 } 239 return nil 240 } 241 242 func (b *BooleanBuilder) UnmarshalJSON(data []byte) error { 243 dec := json.NewDecoder(bytes.NewReader(data)) 244 dec.UseNumber() 245 t, err := dec.Token() 246 if err != nil { 247 return err 248 } 249 250 if delim, ok := t.(json.Delim); !ok || delim != '[' { 251 return fmt.Errorf("boolean builder must unpack from json array, found %s", delim) 252 } 253 254 return b.Unmarshal(dec) 255 } 256 257 func (b *BooleanBuilder) Value(i int) bool { 258 return bitutil.BitIsSet(b.rawData, i) 259 } 260 261 var ( 262 _ Builder = (*BooleanBuilder)(nil) 263 )