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
17package array // import "github.com/apache/arrow/go/v6/arrow/array"
18
19import (
20	"fmt"
21	"strings"
22	"sync/atomic"
23
24	"github.com/apache/arrow/go/v6/arrow"
25	"github.com/apache/arrow/go/v6/arrow/bitutil"
26	"github.com/apache/arrow/go/v6/arrow/internal/debug"
27	"github.com/apache/arrow/go/v6/arrow/memory"
28	"golang.org/x/xerrors"
29)
30
31func NewIntervalData(data *Data) Interface {
32	switch data.dtype.(type) {
33	case *arrow.MonthIntervalType:
34		return NewMonthIntervalData(data)
35	case *arrow.DayTimeIntervalType:
36		return NewDayTimeIntervalData(data)
37	case *arrow.MonthDayNanoIntervalType:
38		return NewMonthDayNanoIntervalData(data)
39	default:
40		panic(xerrors.Errorf("arrow/array: unknown interval data type %T", data.dtype))
41	}
42}
43
44// A type which represents an immutable sequence of arrow.MonthInterval values.
45type MonthInterval struct {
46	array
47	values []arrow.MonthInterval
48}
49
50func NewMonthIntervalData(data *Data) *MonthInterval {
51	a := &MonthInterval{}
52	a.refCount = 1
53	a.setData(data)
54	return a
55}
56
57func (a *MonthInterval) Value(i int) arrow.MonthInterval            { return a.values[i] }
58func (a *MonthInterval) MonthIntervalValues() []arrow.MonthInterval { return a.values }
59
60func (a *MonthInterval) String() string {
61	o := new(strings.Builder)
62	o.WriteString("[")
63	for i, v := range a.values {
64		if i > 0 {
65			fmt.Fprintf(o, " ")
66		}
67		switch {
68		case a.IsNull(i):
69			o.WriteString("(null)")
70		default:
71			fmt.Fprintf(o, "%v", v)
72		}
73	}
74	o.WriteString("]")
75	return o.String()
76}
77
78func (a *MonthInterval) setData(data *Data) {
79	a.array.setData(data)
80	vals := data.buffers[1]
81	if vals != nil {
82		a.values = arrow.MonthIntervalTraits.CastFromBytes(vals.Bytes())
83		beg := a.array.data.offset
84		end := beg + a.array.data.length
85		a.values = a.values[beg:end]
86	}
87}
88
89func arrayEqualMonthInterval(left, right *MonthInterval) bool {
90	for i := 0; i < left.Len(); i++ {
91		if left.IsNull(i) {
92			continue
93		}
94		if left.Value(i) != right.Value(i) {
95			return false
96		}
97	}
98	return true
99}
100
101type MonthIntervalBuilder struct {
102	builder
103
104	data    *memory.Buffer
105	rawData []arrow.MonthInterval
106}
107
108func NewMonthIntervalBuilder(mem memory.Allocator) *MonthIntervalBuilder {
109	return &MonthIntervalBuilder{builder: builder{refCount: 1, mem: mem}}
110}
111
112// Release decreases the reference count by 1.
113// When the reference count goes to zero, the memory is freed.
114func (b *MonthIntervalBuilder) Release() {
115	debug.Assert(atomic.LoadInt64(&b.refCount) > 0, "too many releases")
116
117	if atomic.AddInt64(&b.refCount, -1) == 0 {
118		if b.nullBitmap != nil {
119			b.nullBitmap.Release()
120			b.nullBitmap = nil
121		}
122		if b.data != nil {
123			b.data.Release()
124			b.data = nil
125			b.rawData = nil
126		}
127	}
128}
129
130func (b *MonthIntervalBuilder) Append(v arrow.MonthInterval) {
131	b.Reserve(1)
132	b.UnsafeAppend(v)
133}
134
135func (b *MonthIntervalBuilder) AppendNull() {
136	b.Reserve(1)
137	b.UnsafeAppendBoolToBitmap(false)
138}
139
140func (b *MonthIntervalBuilder) UnsafeAppend(v arrow.MonthInterval) {
141	bitutil.SetBit(b.nullBitmap.Bytes(), b.length)
142	b.rawData[b.length] = v
143	b.length++
144}
145
146func (b *MonthIntervalBuilder) UnsafeAppendBoolToBitmap(isValid bool) {
147	if isValid {
148		bitutil.SetBit(b.nullBitmap.Bytes(), b.length)
149	} else {
150		b.nulls++
151	}
152	b.length++
153}
154
155// AppendValues will append the values in the v slice. The valid slice determines which values
156// in v are valid (not null). The valid slice must either be empty or be equal in length to v. If empty,
157// all values in v are appended and considered valid.
158func (b *MonthIntervalBuilder) AppendValues(v []arrow.MonthInterval, valid []bool) {
159	if len(v) != len(valid) && len(valid) != 0 {
160		panic("len(v) != len(valid) && len(valid) != 0")
161	}
162
163	if len(v) == 0 {
164		return
165	}
166
167	b.Reserve(len(v))
168	arrow.MonthIntervalTraits.Copy(b.rawData[b.length:], v)
169	b.builder.unsafeAppendBoolsToBitmap(valid, len(v))
170}
171
172func (b *MonthIntervalBuilder) init(capacity int) {
173	b.builder.init(capacity)
174
175	b.data = memory.NewResizableBuffer(b.mem)
176	bytesN := arrow.MonthIntervalTraits.BytesRequired(capacity)
177	b.data.Resize(bytesN)
178	b.rawData = arrow.MonthIntervalTraits.CastFromBytes(b.data.Bytes())
179}
180
181// Reserve ensures there is enough space for appending n elements
182// by checking the capacity and calling Resize if necessary.
183func (b *MonthIntervalBuilder) Reserve(n int) {
184	b.builder.reserve(n, b.Resize)
185}
186
187// Resize adjusts the space allocated by b to n elements. If n is greater than b.Cap(),
188// additional memory will be allocated. If n is smaller, the allocated memory may reduced.
189func (b *MonthIntervalBuilder) Resize(n int) {
190	nBuilder := n
191	if n < minBuilderCapacity {
192		n = minBuilderCapacity
193	}
194
195	if b.capacity == 0 {
196		b.init(n)
197	} else {
198		b.builder.resize(nBuilder, b.init)
199		b.data.Resize(arrow.MonthIntervalTraits.BytesRequired(n))
200		b.rawData = arrow.MonthIntervalTraits.CastFromBytes(b.data.Bytes())
201	}
202}
203
204// NewArray creates a MonthInterval array from the memory buffers used by the builder and resets the MonthIntervalBuilder
205// so it can be used to build a new array.
206func (b *MonthIntervalBuilder) NewArray() Interface {
207	return b.NewMonthIntervalArray()
208}
209
210// NewMonthIntervalArray creates a MonthInterval array from the memory buffers used by the builder and resets the MonthIntervalBuilder
211// so it can be used to build a new array.
212func (b *MonthIntervalBuilder) NewMonthIntervalArray() (a *MonthInterval) {
213	data := b.newData()
214	a = NewMonthIntervalData(data)
215	data.Release()
216	return
217}
218
219func (b *MonthIntervalBuilder) newData() (data *Data) {
220	bytesRequired := arrow.MonthIntervalTraits.BytesRequired(b.length)
221	if bytesRequired > 0 && bytesRequired < b.data.Len() {
222		// trim buffers
223		b.data.Resize(bytesRequired)
224	}
225	data = NewData(arrow.FixedWidthTypes.MonthInterval, b.length, []*memory.Buffer{b.nullBitmap, b.data}, nil, b.nulls, 0)
226	b.reset()
227
228	if b.data != nil {
229		b.data.Release()
230		b.data = nil
231		b.rawData = nil
232	}
233
234	return
235}
236
237// A type which represents an immutable sequence of arrow.DayTimeInterval values.
238type DayTimeInterval struct {
239	array
240	values []arrow.DayTimeInterval
241}
242
243func NewDayTimeIntervalData(data *Data) *DayTimeInterval {
244	a := &DayTimeInterval{}
245	a.refCount = 1
246	a.setData(data)
247	return a
248}
249
250func (a *DayTimeInterval) Value(i int) arrow.DayTimeInterval              { return a.values[i] }
251func (a *DayTimeInterval) DayTimeIntervalValues() []arrow.DayTimeInterval { return a.values }
252
253func (a *DayTimeInterval) String() string {
254	o := new(strings.Builder)
255	o.WriteString("[")
256	for i, v := range a.values {
257		if i > 0 {
258			fmt.Fprintf(o, " ")
259		}
260		switch {
261		case a.IsNull(i):
262			o.WriteString("(null)")
263		default:
264			fmt.Fprintf(o, "%v", v)
265		}
266	}
267	o.WriteString("]")
268	return o.String()
269}
270
271func (a *DayTimeInterval) setData(data *Data) {
272	a.array.setData(data)
273	vals := data.buffers[1]
274	if vals != nil {
275		a.values = arrow.DayTimeIntervalTraits.CastFromBytes(vals.Bytes())
276		beg := a.array.data.offset
277		end := beg + a.array.data.length
278		a.values = a.values[beg:end]
279	}
280}
281
282func arrayEqualDayTimeInterval(left, right *DayTimeInterval) bool {
283	for i := 0; i < left.Len(); i++ {
284		if left.IsNull(i) {
285			continue
286		}
287		if left.Value(i) != right.Value(i) {
288			return false
289		}
290	}
291	return true
292}
293
294type DayTimeIntervalBuilder struct {
295	builder
296
297	data    *memory.Buffer
298	rawData []arrow.DayTimeInterval
299}
300
301func NewDayTimeIntervalBuilder(mem memory.Allocator) *DayTimeIntervalBuilder {
302	return &DayTimeIntervalBuilder{builder: builder{refCount: 1, mem: mem}}
303}
304
305// Release decreases the reference count by 1.
306// When the reference count goes to zero, the memory is freed.
307func (b *DayTimeIntervalBuilder) Release() {
308	debug.Assert(atomic.LoadInt64(&b.refCount) > 0, "too many releases")
309
310	if atomic.AddInt64(&b.refCount, -1) == 0 {
311		if b.nullBitmap != nil {
312			b.nullBitmap.Release()
313			b.nullBitmap = nil
314		}
315		if b.data != nil {
316			b.data.Release()
317			b.data = nil
318			b.rawData = nil
319		}
320	}
321}
322
323func (b *DayTimeIntervalBuilder) Append(v arrow.DayTimeInterval) {
324	b.Reserve(1)
325	b.UnsafeAppend(v)
326}
327
328func (b *DayTimeIntervalBuilder) AppendNull() {
329	b.Reserve(1)
330	b.UnsafeAppendBoolToBitmap(false)
331}
332
333func (b *DayTimeIntervalBuilder) UnsafeAppend(v arrow.DayTimeInterval) {
334	bitutil.SetBit(b.nullBitmap.Bytes(), b.length)
335	b.rawData[b.length] = v
336	b.length++
337}
338
339func (b *DayTimeIntervalBuilder) UnsafeAppendBoolToBitmap(isValid bool) {
340	if isValid {
341		bitutil.SetBit(b.nullBitmap.Bytes(), b.length)
342	} else {
343		b.nulls++
344	}
345	b.length++
346}
347
348// AppendValues will append the values in the v slice. The valid slice determines which values
349// in v are valid (not null). The valid slice must either be empty or be equal in length to v. If empty,
350// all values in v are appended and considered valid.
351func (b *DayTimeIntervalBuilder) AppendValues(v []arrow.DayTimeInterval, valid []bool) {
352	if len(v) != len(valid) && len(valid) != 0 {
353		panic("len(v) != len(valid) && len(valid) != 0")
354	}
355
356	if len(v) == 0 {
357		return
358	}
359
360	b.Reserve(len(v))
361	arrow.DayTimeIntervalTraits.Copy(b.rawData[b.length:], v)
362	b.builder.unsafeAppendBoolsToBitmap(valid, len(v))
363}
364
365func (b *DayTimeIntervalBuilder) init(capacity int) {
366	b.builder.init(capacity)
367
368	b.data = memory.NewResizableBuffer(b.mem)
369	bytesN := arrow.DayTimeIntervalTraits.BytesRequired(capacity)
370	b.data.Resize(bytesN)
371	b.rawData = arrow.DayTimeIntervalTraits.CastFromBytes(b.data.Bytes())
372}
373
374// Reserve ensures there is enough space for appending n elements
375// by checking the capacity and calling Resize if necessary.
376func (b *DayTimeIntervalBuilder) Reserve(n int) {
377	b.builder.reserve(n, b.Resize)
378}
379
380// Resize adjusts the space allocated by b to n elements. If n is greater than b.Cap(),
381// additional memory will be allocated. If n is smaller, the allocated memory may reduced.
382func (b *DayTimeIntervalBuilder) Resize(n int) {
383	nBuilder := n
384	if n < minBuilderCapacity {
385		n = minBuilderCapacity
386	}
387
388	if b.capacity == 0 {
389		b.init(n)
390	} else {
391		b.builder.resize(nBuilder, b.init)
392		b.data.Resize(arrow.DayTimeIntervalTraits.BytesRequired(n))
393		b.rawData = arrow.DayTimeIntervalTraits.CastFromBytes(b.data.Bytes())
394	}
395}
396
397// NewArray creates a DayTimeInterval array from the memory buffers used by the builder and resets the DayTimeIntervalBuilder
398// so it can be used to build a new array.
399func (b *DayTimeIntervalBuilder) NewArray() Interface {
400	return b.NewDayTimeIntervalArray()
401}
402
403// NewDayTimeIntervalArray creates a DayTimeInterval array from the memory buffers used by the builder and resets the DayTimeIntervalBuilder
404// so it can be used to build a new array.
405func (b *DayTimeIntervalBuilder) NewDayTimeIntervalArray() (a *DayTimeInterval) {
406	data := b.newData()
407	a = NewDayTimeIntervalData(data)
408	data.Release()
409	return
410}
411
412func (b *DayTimeIntervalBuilder) newData() (data *Data) {
413	bytesRequired := arrow.DayTimeIntervalTraits.BytesRequired(b.length)
414	if bytesRequired > 0 && bytesRequired < b.data.Len() {
415		// trim buffers
416		b.data.Resize(bytesRequired)
417	}
418	data = NewData(arrow.FixedWidthTypes.DayTimeInterval, b.length, []*memory.Buffer{b.nullBitmap, b.data}, nil, b.nulls, 0)
419	b.reset()
420
421	if b.data != nil {
422		b.data.Release()
423		b.data = nil
424		b.rawData = nil
425	}
426
427	return
428}
429
430// A type which represents an immutable sequence of arrow.DayTimeInterval values.
431type MonthDayNanoInterval struct {
432	array
433	values []arrow.MonthDayNanoInterval
434}
435
436func NewMonthDayNanoIntervalData(data *Data) *MonthDayNanoInterval {
437	a := &MonthDayNanoInterval{}
438	a.refCount = 1
439	a.setData(data)
440	return a
441}
442
443func (a *MonthDayNanoInterval) Value(i int) arrow.MonthDayNanoInterval { return a.values[i] }
444func (a *MonthDayNanoInterval) MonthDayNanoIntervalValues() []arrow.MonthDayNanoInterval {
445	return a.values
446}
447
448func (a *MonthDayNanoInterval) String() string {
449	o := new(strings.Builder)
450	o.WriteString("[")
451	for i, v := range a.values {
452		if i > 0 {
453			fmt.Fprintf(o, " ")
454		}
455		switch {
456		case a.IsNull(i):
457			o.WriteString("(null)")
458		default:
459			fmt.Fprintf(o, "%v", v)
460		}
461	}
462	o.WriteString("]")
463	return o.String()
464}
465
466func (a *MonthDayNanoInterval) setData(data *Data) {
467	a.array.setData(data)
468	vals := data.buffers[1]
469	if vals != nil {
470		a.values = arrow.MonthDayNanoIntervalTraits.CastFromBytes(vals.Bytes())
471		beg := a.array.data.offset
472		end := beg + a.array.data.length
473		a.values = a.values[beg:end]
474	}
475}
476
477func arrayEqualMonthDayNanoInterval(left, right *MonthDayNanoInterval) bool {
478	for i := 0; i < left.Len(); i++ {
479		if left.IsNull(i) {
480			continue
481		}
482		if left.Value(i) != right.Value(i) {
483			return false
484		}
485	}
486	return true
487}
488
489type MonthDayNanoIntervalBuilder struct {
490	builder
491
492	data    *memory.Buffer
493	rawData []arrow.MonthDayNanoInterval
494}
495
496func NewMonthDayNanoIntervalBuilder(mem memory.Allocator) *MonthDayNanoIntervalBuilder {
497	return &MonthDayNanoIntervalBuilder{builder: builder{refCount: 1, mem: mem}}
498}
499
500// Release decreases the reference count by 1.
501// When the reference count goes to zero, the memory is freed.
502func (b *MonthDayNanoIntervalBuilder) Release() {
503	debug.Assert(atomic.LoadInt64(&b.refCount) > 0, "too many releases")
504
505	if atomic.AddInt64(&b.refCount, -1) == 0 {
506		if b.nullBitmap != nil {
507			b.nullBitmap.Release()
508			b.nullBitmap = nil
509		}
510		if b.data != nil {
511			b.data.Release()
512			b.data = nil
513			b.rawData = nil
514		}
515	}
516}
517
518func (b *MonthDayNanoIntervalBuilder) Append(v arrow.MonthDayNanoInterval) {
519	b.Reserve(1)
520	b.UnsafeAppend(v)
521}
522
523func (b *MonthDayNanoIntervalBuilder) AppendNull() {
524	b.Reserve(1)
525	b.UnsafeAppendBoolToBitmap(false)
526}
527
528func (b *MonthDayNanoIntervalBuilder) UnsafeAppend(v arrow.MonthDayNanoInterval) {
529	bitutil.SetBit(b.nullBitmap.Bytes(), b.length)
530	b.rawData[b.length] = v
531	b.length++
532}
533
534func (b *MonthDayNanoIntervalBuilder) UnsafeAppendBoolToBitmap(isValid bool) {
535	if isValid {
536		bitutil.SetBit(b.nullBitmap.Bytes(), b.length)
537	} else {
538		b.nulls++
539	}
540	b.length++
541}
542
543// AppendValues will append the values in the v slice. The valid slice determines which values
544// in v are valid (not null). The valid slice must either be empty or be equal in length to v. If empty,
545// all values in v are appended and considered valid.
546func (b *MonthDayNanoIntervalBuilder) AppendValues(v []arrow.MonthDayNanoInterval, valid []bool) {
547	if len(v) != len(valid) && len(valid) != 0 {
548		panic("len(v) != len(valid) && len(valid) != 0")
549	}
550
551	if len(v) == 0 {
552		return
553	}
554
555	b.Reserve(len(v))
556	arrow.MonthDayNanoIntervalTraits.Copy(b.rawData[b.length:], v)
557	b.builder.unsafeAppendBoolsToBitmap(valid, len(v))
558}
559
560func (b *MonthDayNanoIntervalBuilder) init(capacity int) {
561	b.builder.init(capacity)
562
563	b.data = memory.NewResizableBuffer(b.mem)
564	bytesN := arrow.MonthDayNanoIntervalTraits.BytesRequired(capacity)
565	b.data.Resize(bytesN)
566	b.rawData = arrow.MonthDayNanoIntervalTraits.CastFromBytes(b.data.Bytes())
567}
568
569// Reserve ensures there is enough space for appending n elements
570// by checking the capacity and calling Resize if necessary.
571func (b *MonthDayNanoIntervalBuilder) Reserve(n int) {
572	b.builder.reserve(n, b.Resize)
573}
574
575// Resize adjusts the space allocated by b to n elements. If n is greater than b.Cap(),
576// additional memory will be allocated. If n is smaller, the allocated memory may reduced.
577func (b *MonthDayNanoIntervalBuilder) Resize(n int) {
578	nBuilder := n
579	if n < minBuilderCapacity {
580		n = minBuilderCapacity
581	}
582
583	if b.capacity == 0 {
584		b.init(n)
585	} else {
586		b.builder.resize(nBuilder, b.init)
587		b.data.Resize(arrow.MonthDayNanoIntervalTraits.BytesRequired(n))
588		b.rawData = arrow.MonthDayNanoIntervalTraits.CastFromBytes(b.data.Bytes())
589	}
590}
591
592// NewArray creates a MonthDayNanoInterval array from the memory buffers used by the builder and resets the MonthDayNanoIntervalBuilder
593// so it can be used to build a new array.
594func (b *MonthDayNanoIntervalBuilder) NewArray() Interface {
595	return b.NewMonthDayNanoIntervalArray()
596}
597
598// NewMonthDayNanoIntervalArray creates a MonthDayNanoInterval array from the memory buffers used by the builder and resets the MonthDayNanoIntervalBuilder
599// so it can be used to build a new array.
600func (b *MonthDayNanoIntervalBuilder) NewMonthDayNanoIntervalArray() (a *MonthDayNanoInterval) {
601	data := b.newData()
602	a = NewMonthDayNanoIntervalData(data)
603	data.Release()
604	return
605}
606
607func (b *MonthDayNanoIntervalBuilder) newData() (data *Data) {
608	bytesRequired := arrow.MonthDayNanoIntervalTraits.BytesRequired(b.length)
609	if bytesRequired > 0 && bytesRequired < b.data.Len() {
610		// trim buffers
611		b.data.Resize(bytesRequired)
612	}
613	data = NewData(arrow.FixedWidthTypes.MonthDayNanoInterval, b.length, []*memory.Buffer{b.nullBitmap, b.data}, nil, b.nulls, 0)
614	b.reset()
615
616	if b.data != nil {
617		b.data.Release()
618		b.data = nil
619		b.rawData = nil
620	}
621
622	return
623}
624
625var (
626	_ Interface = (*MonthInterval)(nil)
627	_ Interface = (*DayTimeInterval)(nil)
628	_ Interface = (*MonthDayNanoInterval)(nil)
629
630	_ Builder = (*MonthIntervalBuilder)(nil)
631	_ Builder = (*DayTimeIntervalBuilder)(nil)
632	_ Builder = (*MonthDayNanoIntervalBuilder)(nil)
633)
634