github.com/apache/arrow/go/v16@v16.1.0/arrow/compute/internal/kernels/scalar_boolean.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  //go:build go1.18
    18  
    19  package kernels
    20  
    21  import (
    22  	"github.com/apache/arrow/go/v16/arrow/bitutil"
    23  	"github.com/apache/arrow/go/v16/arrow/compute/exec"
    24  	"github.com/apache/arrow/go/v16/arrow/scalar"
    25  )
    26  
    27  type computeWordFN func(leftTrue, leftFalse, rightTrue, rightFalse uint64) (outValid, outData uint64)
    28  
    29  func computeKleene(computeWord computeWordFN, ctx *exec.KernelCtx, left, right *exec.ArraySpan, out *exec.ExecResult) error {
    30  	var (
    31  		inBMs = [4]bitutil.Bitmap{
    32  			{Data: left.Buffers[0].Buf, Offset: left.Offset, Len: left.Len},
    33  			{Data: left.Buffers[1].Buf, Offset: left.Offset, Len: left.Len},
    34  			{Data: right.Buffers[1].Buf, Offset: right.Offset, Len: right.Len},
    35  			{Data: right.Buffers[0].Buf, Offset: right.Offset, Len: right.Len},
    36  		}
    37  		outBMs = [2]bitutil.Bitmap{
    38  			{Data: out.Buffers[0].Buf, Offset: out.Offset, Len: out.Len},
    39  			{Data: out.Buffers[1].Buf, Offset: out.Offset, Len: out.Len},
    40  		}
    41  		apply = func(leftValid, leftData uint64, rightValid, rightData uint64) (outValidity, outData uint64) {
    42  			leftTrue, leftFalse := leftValid&leftData, leftValid&^leftData
    43  			rightTrue, rightFalse := rightValid&rightData, rightValid&^rightData
    44  			return computeWord(leftTrue, leftFalse, rightTrue, rightFalse)
    45  		}
    46  	)
    47  
    48  	switch {
    49  	case right.UpdateNullCount() == 0:
    50  		return bitutil.VisitWordsAndWrite(inBMs[:3], outBMs[:],
    51  			func(in, out []uint64) {
    52  				out[0], out[1] = apply(in[0], in[1], ^uint64(0), in[2])
    53  			})
    54  	case left.UpdateNullCount() == 0:
    55  		return bitutil.VisitWordsAndWrite(inBMs[1:], outBMs[:],
    56  			func(in, out []uint64) {
    57  				out[0], out[1] = apply(^uint64(0), in[0], in[2], in[1])
    58  			})
    59  	default:
    60  		return bitutil.VisitWordsAndWrite(inBMs[:], outBMs[:],
    61  			func(in, out []uint64) {
    62  				out[0], out[1] = apply(in[0], in[1], in[3], in[2])
    63  			})
    64  	}
    65  }
    66  
    67  type AndOpKernel struct {
    68  	commutativeBinaryKernel[AndOpKernel]
    69  }
    70  
    71  func (AndOpKernel) Call(ctx *exec.KernelCtx, left, right *exec.ArraySpan, out *exec.ExecResult) error {
    72  	bitutil.BitmapAnd(left.Buffers[1].Buf, right.Buffers[1].Buf,
    73  		left.Offset, right.Offset, out.Buffers[1].Buf, out.Offset, left.Len)
    74  	return nil
    75  }
    76  
    77  func (AndOpKernel) CallScalarLeft(ctx *exec.KernelCtx, left scalar.Scalar, right *exec.ArraySpan, out *exec.ExecResult) error {
    78  	if !left.IsValid() {
    79  		return nil
    80  	}
    81  
    82  	outBM := out.Buffers[1].Buf
    83  	if left.(*scalar.Boolean).Value {
    84  		bitutil.CopyBitmap(right.Buffers[1].Buf, int(right.Offset),
    85  			int(right.Len), outBM, int(out.Offset))
    86  	} else {
    87  		bitutil.SetBitsTo(outBM, out.Offset, out.Len, false)
    88  	}
    89  	return nil
    90  }
    91  
    92  type KleeneAndOpKernel struct {
    93  	commutativeBinaryKernel[KleeneAndOpKernel]
    94  }
    95  
    96  func (KleeneAndOpKernel) Call(ctx *exec.KernelCtx, left, right *exec.ArraySpan, out *exec.ExecResult) error {
    97  	if left.UpdateNullCount() == 0 && right.UpdateNullCount() == 0 {
    98  		bitutil.SetBitsTo(out.Buffers[0].Buf, out.Offset, out.Len, true)
    99  		out.Nulls = 0
   100  		return (AndOpKernel{}).Call(ctx, left, right, out)
   101  	}
   102  
   103  	computeWord := func(leftTrue, leftFalse, rightTrue, rightFalse uint64) (outValid, outData uint64) {
   104  		return leftFalse | rightFalse | (leftTrue & rightTrue), leftTrue & rightTrue
   105  	}
   106  	return computeKleene(computeWord, ctx, left, right, out)
   107  }
   108  
   109  func (KleeneAndOpKernel) CallScalarLeft(ctx *exec.KernelCtx, left scalar.Scalar, right *exec.ArraySpan, out *exec.ExecResult) error {
   110  	var (
   111  		leftTrue  = left.IsValid() && left.(*scalar.Boolean).Value
   112  		leftFalse = left.IsValid() && !left.(*scalar.Boolean).Value
   113  	)
   114  
   115  	switch {
   116  	case leftFalse:
   117  		bitutil.SetBitsTo(out.Buffers[0].Buf, out.Offset, out.Len, true)
   118  		out.Nulls = 0
   119  		bitutil.SetBitsTo(out.Buffers[1].Buf, out.Offset, out.Len, false)
   120  	case leftTrue:
   121  		if right.UpdateNullCount() == 0 {
   122  			bitutil.SetBitsTo(out.Buffers[0].Buf, out.Offset, out.Len, true)
   123  			out.Nulls = 0
   124  		} else {
   125  			bitutil.CopyBitmap(right.Buffers[0].Buf, int(right.Offset), int(right.Len),
   126  				out.Buffers[0].Buf, int(out.Offset))
   127  		}
   128  		bitutil.CopyBitmap(right.Buffers[1].Buf, int(right.Offset), int(right.Len),
   129  			out.Buffers[1].Buf, int(out.Offset))
   130  	default: // scalar was null: out[i] is valid iff right[i] was false
   131  		if right.UpdateNullCount() == 0 {
   132  			bitutil.InvertBitmap(right.Buffers[1].Buf, int(right.Offset), int(right.Len),
   133  				out.Buffers[0].Buf, int(out.Offset))
   134  		} else {
   135  			bitutil.BitmapAndNot(right.Buffers[0].Buf, right.Buffers[1].Buf, right.Offset,
   136  				right.Offset, out.Buffers[0].Buf, out.Offset, right.Len)
   137  		}
   138  		bitutil.CopyBitmap(right.Buffers[1].Buf, int(right.Offset), int(right.Len),
   139  			out.Buffers[1].Buf, int(out.Offset))
   140  	}
   141  	return nil
   142  }
   143  
   144  type OrOpKernel struct {
   145  	commutativeBinaryKernel[OrOpKernel]
   146  }
   147  
   148  func (OrOpKernel) Call(ctx *exec.KernelCtx, left, right *exec.ArraySpan, out *exec.ExecResult) error {
   149  	bitutil.BitmapOr(left.Buffers[1].Buf, right.Buffers[1].Buf,
   150  		left.Offset, right.Offset, out.Buffers[1].Buf, out.Offset, left.Len)
   151  	return nil
   152  }
   153  
   154  func (OrOpKernel) CallScalarLeft(ctx *exec.KernelCtx, left scalar.Scalar, right *exec.ArraySpan, out *exec.ExecResult) error {
   155  	if !left.IsValid() {
   156  		return nil
   157  	}
   158  
   159  	outBM := out.Buffers[1].Buf
   160  	if left.(*scalar.Boolean).Value {
   161  		bitutil.SetBitsTo(outBM, out.Offset, out.Len, true)
   162  	} else {
   163  		bitutil.CopyBitmap(right.Buffers[1].Buf, int(right.Offset),
   164  			int(right.Len), outBM, int(out.Offset))
   165  	}
   166  	return nil
   167  }
   168  
   169  type KleeneOrOpKernel struct {
   170  	commutativeBinaryKernel[KleeneOrOpKernel]
   171  }
   172  
   173  func (KleeneOrOpKernel) Call(ctx *exec.KernelCtx, left, right *exec.ArraySpan, out *exec.ExecResult) error {
   174  	if left.UpdateNullCount() == 0 && right.UpdateNullCount() == 0 {
   175  		bitutil.SetBitsTo(out.Buffers[0].Buf, out.Offset, out.Len, true)
   176  		out.Nulls = 0
   177  		return (OrOpKernel{}).Call(ctx, left, right, out)
   178  	}
   179  
   180  	computeWord := func(leftTrue, leftFalse, rightTrue, rightFalse uint64) (outValid, outData uint64) {
   181  		return leftTrue | rightTrue | (leftFalse & rightFalse), leftTrue | rightTrue
   182  	}
   183  	return computeKleene(computeWord, ctx, left, right, out)
   184  }
   185  
   186  func (KleeneOrOpKernel) CallScalarLeft(ctx *exec.KernelCtx, left scalar.Scalar, right *exec.ArraySpan, out *exec.ExecResult) error {
   187  	var (
   188  		leftTrue  = left.IsValid() && left.(*scalar.Boolean).Value
   189  		leftFalse = left.IsValid() && !left.(*scalar.Boolean).Value
   190  	)
   191  
   192  	switch {
   193  	case leftTrue:
   194  		bitutil.SetBitsTo(out.Buffers[0].Buf, out.Offset, out.Len, true)
   195  		out.Nulls = 0
   196  		bitutil.SetBitsTo(out.Buffers[1].Buf, out.Offset, out.Len, true) // all true case
   197  	case leftFalse:
   198  		if right.UpdateNullCount() == 0 {
   199  			bitutil.SetBitsTo(out.Buffers[0].Buf, out.Offset, out.Len, true)
   200  			out.Nulls = 0
   201  		} else {
   202  			bitutil.CopyBitmap(right.Buffers[0].Buf, int(right.Offset), int(right.Len),
   203  				out.Buffers[0].Buf, int(out.Offset))
   204  		}
   205  		bitutil.CopyBitmap(right.Buffers[1].Buf, int(right.Offset), int(right.Len),
   206  			out.Buffers[1].Buf, int(out.Offset))
   207  	default: // scalar was null: out[i] is valid iff right[i] was true
   208  		if right.UpdateNullCount() == 0 {
   209  			bitutil.CopyBitmap(right.Buffers[1].Buf, int(right.Offset), int(right.Len),
   210  				out.Buffers[0].Buf, int(out.Offset))
   211  		} else {
   212  			bitutil.BitmapAnd(right.Buffers[0].Buf, right.Buffers[1].Buf, right.Offset,
   213  				right.Offset, out.Buffers[0].Buf, out.Offset, right.Len)
   214  		}
   215  		bitutil.CopyBitmap(right.Buffers[1].Buf, int(right.Offset), int(right.Len),
   216  			out.Buffers[1].Buf, int(out.Offset))
   217  	}
   218  	return nil
   219  }
   220  
   221  type XorOpKernel struct {
   222  	commutativeBinaryKernel[XorOpKernel]
   223  }
   224  
   225  func (XorOpKernel) Call(ctx *exec.KernelCtx, left, right *exec.ArraySpan, out *exec.ExecResult) error {
   226  	bitutil.BitmapXor(left.Buffers[1].Buf, right.Buffers[1].Buf,
   227  		left.Offset, right.Offset, out.Buffers[1].Buf, out.Offset, out.Len)
   228  	return nil
   229  }
   230  
   231  func (XorOpKernel) CallScalarLeft(ctx *exec.KernelCtx, left scalar.Scalar, right *exec.ArraySpan, out *exec.ExecResult) error {
   232  	if !left.IsValid() {
   233  		return nil
   234  	}
   235  
   236  	outBM := out.Buffers[1].Buf
   237  	if left.(*scalar.Boolean).Value {
   238  		bitutil.InvertBitmap(right.Buffers[1].Buf, int(right.Offset), int(right.Len),
   239  			outBM, int(out.Offset))
   240  	} else {
   241  		bitutil.CopyBitmap(right.Buffers[1].Buf, int(right.Offset), int(right.Len),
   242  			outBM, int(out.Offset))
   243  	}
   244  	return nil
   245  }
   246  
   247  func invertScalar(in scalar.Scalar) *scalar.Boolean {
   248  	if in.IsValid() {
   249  		return scalar.NewBooleanScalar(!in.(*scalar.Boolean).Value)
   250  	}
   251  	return in.(*scalar.Boolean)
   252  }
   253  
   254  type AndNotOpKernel struct{}
   255  
   256  func (AndNotOpKernel) Call(ctx *exec.KernelCtx, left, right *exec.ArraySpan, out *exec.ExecResult) error {
   257  	bitutil.BitmapAndNot(left.Buffers[1].Buf, right.Buffers[1].Buf, left.Offset, right.Offset,
   258  		out.Buffers[1].Buf, out.Offset, right.Len)
   259  	return nil
   260  }
   261  
   262  func (AndNotOpKernel) CallScalarLeft(ctx *exec.KernelCtx, left scalar.Scalar, right *exec.ArraySpan, out *exec.ExecResult) error {
   263  	if !left.IsValid() {
   264  		return nil
   265  	}
   266  
   267  	outBM := out.Buffers[1].Buf
   268  	if left.(*scalar.Boolean).Value {
   269  		bitutil.InvertBitmap(right.Buffers[1].Buf, int(right.Offset), int(right.Len),
   270  			outBM, int(out.Offset))
   271  	} else {
   272  		bitutil.SetBitsTo(outBM, out.Offset, out.Len, false)
   273  	}
   274  	return nil
   275  }
   276  
   277  func (AndNotOpKernel) CallScalarRight(ctx *exec.KernelCtx, left *exec.ArraySpan, right scalar.Scalar, out *exec.ExecResult) error {
   278  	return (AndOpKernel{}).CallScalarRight(ctx, left, invertScalar(right), out)
   279  }
   280  
   281  type KleeneAndNotOpKernel struct{}
   282  
   283  func (KleeneAndNotOpKernel) Call(ctx *exec.KernelCtx, left, right *exec.ArraySpan, out *exec.ExecResult) error {
   284  	if left.UpdateNullCount() == 0 && right.UpdateNullCount() == 0 {
   285  		bitutil.SetBitsTo(out.Buffers[0].Buf, out.Offset, out.Len, true)
   286  		out.Nulls = 0
   287  		return (AndNotOpKernel{}).Call(ctx, left, right, out)
   288  	}
   289  
   290  	computeWord := func(leftTrue, leftFalse, rightTrue, rightFalse uint64) (outValid, outData uint64) {
   291  		return leftFalse | rightTrue | (leftTrue & rightFalse), leftTrue & rightFalse
   292  	}
   293  
   294  	return computeKleene(computeWord, ctx, left, right, out)
   295  }
   296  
   297  func (KleeneAndNotOpKernel) CallScalarLeft(ctx *exec.KernelCtx, left scalar.Scalar, right *exec.ArraySpan, out *exec.ExecResult) error {
   298  	var (
   299  		leftTrue  = left.IsValid() && left.(*scalar.Boolean).Value
   300  		leftFalse = left.IsValid() && !left.(*scalar.Boolean).Value
   301  	)
   302  
   303  	switch {
   304  	case leftFalse:
   305  		bitutil.SetBitsTo(out.Buffers[0].Buf, out.Offset, out.Len, true)
   306  		out.Nulls = 0
   307  		bitutil.SetBitsTo(out.Buffers[1].Buf, out.Offset, out.Len, false)
   308  	case leftTrue:
   309  		if right.UpdateNullCount() == 0 {
   310  			bitutil.SetBitsTo(out.Buffers[0].Buf, out.Offset, out.Len, true)
   311  			out.Nulls = 0
   312  		} else {
   313  			bitutil.CopyBitmap(right.Buffers[0].Buf, int(right.Offset), int(right.Len),
   314  				out.Buffers[0].Buf, int(out.Offset))
   315  		}
   316  		bitutil.InvertBitmap(right.Buffers[1].Buf, int(right.Offset), int(right.Len),
   317  			out.Buffers[1].Buf, int(out.Offset))
   318  	default: // scalar was null: out[i] is valid iff right[i] was true
   319  		if right.UpdateNullCount() == 0 {
   320  			bitutil.CopyBitmap(right.Buffers[1].Buf, int(right.Offset), int(right.Len),
   321  				out.Buffers[0].Buf, int(out.Offset))
   322  		} else {
   323  			bitutil.BitmapAnd(right.Buffers[0].Buf, right.Buffers[1].Buf, right.Offset, right.Offset,
   324  				out.Buffers[0].Buf, out.Offset, right.Len)
   325  		}
   326  		bitutil.InvertBitmap(right.Buffers[1].Buf, int(right.Offset), int(right.Len),
   327  			out.Buffers[1].Buf, int(out.Offset))
   328  	}
   329  	return nil
   330  }
   331  
   332  func (KleeneAndNotOpKernel) CallScalarRight(ctx *exec.KernelCtx, left *exec.ArraySpan, right scalar.Scalar, out *exec.ExecResult) error {
   333  	return (KleeneAndOpKernel{}).CallScalarRight(ctx, left, invertScalar(right), out)
   334  }