// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package array

import (
	
	
	
	

	
	
	
)

// Data represents the memory and metadata of an Arrow array.
type Data struct {
	refCount atomic.Int64
	dtype    arrow.DataType
	nulls    int
	offset   int
	length   int

	// for dictionary arrays: buffers will be the null validity bitmap and the indexes that reference
	// values in the dictionary member. childData would be empty in a dictionary array
	buffers    []*memory.Buffer  // TODO(sgc): should this be an interface?
	childData  []arrow.ArrayData // TODO(sgc): managed by ListArray, StructArray and UnionArray types
	dictionary *Data             // only populated for dictionary arrays
}

// NewData creates a new Data.
func ( arrow.DataType,  int,  []*memory.Buffer,  []arrow.ArrayData, ,  int) *Data {
	for ,  := range  {
		if  != nil {
			.Retain()
		}
	}

	for ,  := range  {
		if  != nil {
			.Retain()
		}
	}

	 := &Data{
		dtype:     ,
		nulls:     ,
		length:    ,
		offset:    ,
		buffers:   ,
		childData: ,
	}
	.refCount.Add(1)
	return 
}

// NewDataWithDictionary creates a new data object, but also sets the provided dictionary into the data if it's not nil
func ( arrow.DataType,  int,  []*memory.Buffer, ,  int,  *Data) *Data {
	 := NewData(, , , nil, , )
	if  != nil {
		.Retain()
	}
	.dictionary = 
	return 
}

func ( *Data) () *Data {
	// don't pass the slices directly, otherwise it retains the connection
	// we need to make new slices and populate them with the same pointers
	 := make([]*memory.Buffer, len(.buffers))
	copy(, .buffers)
	 := make([]arrow.ArrayData, len(.childData))
	copy(, .childData)

	 := NewData(.dtype, .length, , , .nulls, .offset)
	.SetDictionary(.dictionary)
	return 
}

// Reset sets the Data for re-use.
func ( *Data) ( arrow.DataType,  int,  []*memory.Buffer,  []arrow.ArrayData, ,  int) {
	// Retain new buffers before releasing existing buffers in-case they're the same ones to prevent accidental premature
	// release.
	for ,  := range  {
		if  != nil {
			.Retain()
		}
	}
	for ,  := range .buffers {
		if  != nil {
			.Release()
		}
	}
	.buffers = 

	// Retain new children data before releasing existing children data in-case they're the same ones to prevent accidental
	// premature release.
	for ,  := range  {
		if  != nil {
			.Retain()
		}
	}
	for ,  := range .childData {
		if  != nil {
			.Release()
		}
	}
	.childData = 

	.dtype = 
	.length = 
	.nulls = 
	.offset = 
}

// Retain increases the reference count by 1.
// Retain may be called simultaneously from multiple goroutines.
func ( *Data) () {
	.refCount.Add(1)
}

// Release decreases the reference count by 1.
// When the reference count goes to zero, the memory is freed.
// Release may be called simultaneously from multiple goroutines.
func ( *Data) () {
	debug.Assert(.refCount.Load() > 0, "too many releases")

	if .refCount.Add(-1) == 0 {
		for ,  := range .buffers {
			if  != nil {
				.Release()
			}
		}

		for ,  := range .childData {
			if  != nil {
				.Release()
			}
		}

		if .dictionary != nil {
			.dictionary.()
		}
		.dictionary, .buffers, .childData = nil, nil, nil
	}
}

// DataType returns the DataType of the data.
func ( *Data) () arrow.DataType { return .dtype }

func ( *Data) ( int) { .nulls =  }

// NullN returns the number of nulls.
func ( *Data) () int { return .nulls }

// Len returns the length.
func ( *Data) () int { return .length }

// Offset returns the offset.
func ( *Data) () int { return .offset }

// Buffers returns the buffers.
func ( *Data) () []*memory.Buffer { return .buffers }

func ( *Data) () []arrow.ArrayData { return .childData }

// Dictionary returns the ArrayData object for the dictionary member, or nil
func ( *Data) () arrow.ArrayData { return .dictionary }

// SetDictionary allows replacing the dictionary for this particular Data object
func ( *Data) ( arrow.ArrayData) {
	if .dictionary != nil {
		.dictionary.Release()
		.dictionary = nil
	}
	if .(*Data) != nil {
		.Retain()
		.dictionary = .(*Data)
	}
}

// SizeInBytes returns the size of the Data and any children and/or dictionary in bytes by
// recursively examining the nested structures of children and/or dictionary.
// The value returned is an upper-bound since offset is not taken into account.
func ( *Data) () uint64 {
	var  uint64

	if  == nil {
		return 0
	}

	for ,  := range .Buffers() {
		if  != nil {
			 += uint64(.Len())
		}
	}
	for ,  := range .Children() {
		 += .SizeInBytes()
	}
	if .dictionary != nil {
		 += .dictionary.()
	}

	return 
}

// NewSliceData returns a new slice that shares backing data with the input.
// The returned Data slice starts at i and extends j-i elements, such as:
//
//	slice := data[i:j]
//
// The returned value must be Release'd after use.
//
// NewSliceData panics if the slice is outside the valid range of the input Data.
// NewSliceData panics if j < i.
func ( arrow.ArrayData, ,  int64) arrow.ArrayData {
	if  > int64(.Len()) ||  >  || .Offset()+int() > .Offset()+.Len() {
		panic("arrow/array: index out of range")
	}

	for ,  := range .Buffers() {
		if  != nil {
			.Retain()
		}
	}

	for ,  := range .Children() {
		if  != nil {
			.Retain()
		}
	}

	if .(*Data).dictionary != nil {
		.(*Data).dictionary.Retain()
	}

	 := &Data{
		dtype:      .DataType(),
		nulls:      UnknownNullCount,
		length:     int( - ),
		offset:     .Offset() + int(),
		buffers:    .Buffers(),
		childData:  .Children(),
		dictionary: .(*Data).dictionary,
	}
	.refCount.Add(1)

	if .NullN() == 0 {
		.nulls = 0
	}

	return 
}

func ( *maphash.Hash,  arrow.ArrayData) {
	 := .(*Data)

	.Write((*[bits.UintSize / 8]byte)(unsafe.Pointer(&.length))[:])
	.Write((*[bits.UintSize / 8]byte)(unsafe.Pointer(&.length))[:])
	if len(.buffers) > 0 && .buffers[0] != nil {
		.Write(.buffers[0].Bytes())
	}
	for ,  := range .childData {
		(, )
	}
}