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
18
19import (
20	"strings"
21	"sync/atomic"
22
23	"github.com/apache/arrow/go/v6/arrow"
24	"github.com/apache/arrow/go/v6/arrow/internal/debug"
25	"github.com/apache/arrow/go/v6/arrow/memory"
26)
27
28// Null represents an immutable, degenerate array with no physical storage.
29type Null struct {
30	array
31}
32
33// NewNull returns a new Null array value of size n.
34func NewNull(n int) *Null {
35	a := &Null{}
36	a.refCount = 1
37	data := NewData(
38		arrow.Null, n,
39		[]*memory.Buffer{nil},
40		nil,
41		n,
42		0,
43	)
44	a.setData(data)
45	data.Release()
46	return a
47}
48
49// NewNullData returns a new Null array value, from data.
50func NewNullData(data *Data) *Null {
51	a := &Null{}
52	a.refCount = 1
53	a.setData(data)
54	return a
55}
56
57func (a *Null) String() string {
58	o := new(strings.Builder)
59	o.WriteString("[")
60	for i := 0; i < a.Len(); i++ {
61		if i > 0 {
62			o.WriteString(" ")
63		}
64		o.WriteString("(null)")
65	}
66	o.WriteString("]")
67	return o.String()
68}
69
70func (a *Null) setData(data *Data) {
71	a.array.setData(data)
72	a.array.nullBitmapBytes = nil
73	a.array.data.nulls = a.array.data.length
74}
75
76type NullBuilder struct {
77	builder
78}
79
80// NewNullBuilder returns a builder, using the provided memory allocator.
81func NewNullBuilder(mem memory.Allocator) *NullBuilder {
82	return &NullBuilder{builder: builder{refCount: 1, mem: mem}}
83}
84
85// Release decreases the reference count by 1.
86// When the reference count goes to zero, the memory is freed.
87func (b *NullBuilder) Release() {
88	debug.Assert(atomic.LoadInt64(&b.refCount) > 0, "too many releases")
89
90	if atomic.AddInt64(&b.refCount, -1) == 0 {
91		if b.nullBitmap != nil {
92			b.nullBitmap.Release()
93			b.nullBitmap = nil
94		}
95	}
96}
97
98func (b *NullBuilder) AppendNull() {
99	b.builder.length++
100	b.builder.nulls++
101}
102
103func (*NullBuilder) Reserve(size int) {}
104func (*NullBuilder) Resize(size int)  {}
105
106func (*NullBuilder) init(cap int)                       {}
107func (*NullBuilder) resize(newBits int, init func(int)) {}
108
109// NewArray creates a Null array from the memory buffers used by the builder and resets the NullBuilder
110// so it can be used to build a new array.
111func (b *NullBuilder) NewArray() Interface {
112	return b.NewNullArray()
113}
114
115// NewNullArray creates a Null array from the memory buffers used by the builder and resets the NullBuilder
116// so it can be used to build a new array.
117func (b *NullBuilder) NewNullArray() (a *Null) {
118	data := b.newData()
119	a = NewNullData(data)
120	data.Release()
121	return
122}
123
124func (b *NullBuilder) newData() (data *Data) {
125	data = NewData(
126		arrow.Null, b.length,
127		[]*memory.Buffer{nil},
128		nil,
129		b.nulls,
130		0,
131	)
132	b.reset()
133
134	return
135}
136
137var (
138	_ Interface = (*Null)(nil)
139	_ Builder   = (*NullBuilder)(nil)
140)
141