blob: 2bdbb5128aaf22a04cde72d7df72826ed068ae84 [file] [log] [blame]
/*
* 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 org.apache.drill.exec.expr.fn.impl;
import io.netty.buffer.DrillBuf;
import io.netty.util.internal.PlatformDependent;
import org.apache.drill.exec.util.DecimalUtility;
import com.google.common.primitives.UnsignedLongs;
import static org.apache.drill.exec.memory.BoundsChecking.rangeCheck;
public class ByteFunctionHelpers {
static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(ByteFunctionHelpers.class);
/**
* Helper function to check for equality of bytes in two DrillBuffers
*
* @param left Left DrillBuf for comparison
* @param lStart start offset in the buffer
* @param lEnd end offset in the buffer
* @param right Right DrillBuf for comparison
* @param rStart start offset in the buffer
* @param rEnd end offset in the buffer
* @return 1 if left input is greater, -1 if left input is smaller, 0 otherwise
*/
public static final int equal(final DrillBuf left, int lStart, int lEnd, final DrillBuf right, int rStart, int rEnd){
rangeCheck(left, lStart, lEnd, right, rStart, rEnd);
return memEqual(left.memoryAddress(), lStart, lEnd, right.memoryAddress(), rStart, rEnd);
}
private static final int memEqual(final long laddr, int lStart, int lEnd, final long raddr, int rStart,
final int rEnd) {
int n = lEnd - lStart;
if (n == rEnd - rStart) {
long lPos = laddr + lStart;
long rPos = raddr + rStart;
while (n > 7) {
long leftLong = PlatformDependent.getLong(lPos);
long rightLong = PlatformDependent.getLong(rPos);
if (leftLong != rightLong) {
return 0;
}
lPos += 8;
rPos += 8;
n -= 8;
}
while (n-- != 0) {
byte leftByte = PlatformDependent.getByte(lPos);
byte rightByte = PlatformDependent.getByte(rPos);
if (leftByte != rightByte) {
return 0;
}
lPos++;
rPos++;
}
return 1;
} else {
return 0;
}
}
/**
* Helper function to compare a set of bytes in two DrillBuffers.
*
* Function will check data before completing in the case that
*
* @param left Left DrillBuf to compare
* @param lStart start offset in the buffer
* @param lEnd end offset in the buffer
* @param right Right DrillBuf to compare
* @param rStart start offset in the buffer
* @param rEnd end offset in the buffer
* @return 1 if left input is greater, -1 if left input is smaller, 0 otherwise
*/
public static final int compare(final DrillBuf left, int lStart, int lEnd, final DrillBuf right, int rStart, int rEnd){
rangeCheck(left, lStart, lEnd, right, rStart, rEnd);
return memcmp(left.memoryAddress(), lStart, lEnd, right.memoryAddress(), rStart, rEnd);
}
private static final int memcmp(final long laddr, int lStart, int lEnd, final long raddr, int rStart, final int rEnd) {
int lLen = lEnd - lStart;
int rLen = rEnd - rStart;
int n = Math.min(rLen, lLen);
long lPos = laddr + lStart;
long rPos = raddr + rStart;
while (n > 7) {
long leftLong = PlatformDependent.getLong(lPos);
long rightLong = PlatformDependent.getLong(rPos);
if (leftLong != rightLong) {
return UnsignedLongs.compare(Long.reverseBytes(leftLong), Long.reverseBytes(rightLong));
}
lPos += 8;
rPos += 8;
n -= 8;
}
while (n-- != 0) {
byte leftByte = PlatformDependent.getByte(lPos);
byte rightByte = PlatformDependent.getByte(rPos);
if (leftByte != rightByte) {
return ((leftByte & 0xFF) - (rightByte & 0xFF)) > 0 ? 1 : -1;
}
lPos++;
rPos++;
}
if (lLen == rLen) {
return 0;
}
return lLen > rLen ? 1 : -1;
}
/**
* Helper function to compare a set of bytes in DrillBuf to a ByteArray.
*
* @param left Left DrillBuf for comparison purposes
* @param lStart start offset in the buffer
* @param lEnd end offset in the buffer
* @param right second input to be compared
* @param rStart start offset in the byte array
* @param rEnd end offset in the byte array
* @return 1 if left input is greater, -1 if left input is smaller, 0 otherwise
*/
public static final int compare(final DrillBuf left, int lStart, int lEnd, final byte[] right, int rStart, final int rEnd) {
rangeCheck(left, lStart, lEnd);
return memcmp(left.memoryAddress(), lStart, lEnd, right, rStart, rEnd);
}
private static final int memcmp(final long laddr, int lStart, int lEnd, final byte[] right, int rStart, final int rEnd) {
int lLen = lEnd - lStart;
int rLen = rEnd - rStart;
int n = Math.min(rLen, lLen);
long lPos = laddr + lStart;
int rPos = rStart;
while (n-- != 0) {
byte leftByte = PlatformDependent.getByte(lPos);
byte rightByte = right[rPos];
if (leftByte != rightByte) {
return ((leftByte & 0xFF) - (rightByte & 0xFF)) > 0 ? 1 : -1;
}
lPos++;
rPos++;
}
if (lLen == rLen) {
return 0;
}
return lLen > rLen ? 1 : -1;
}
/*
* Following are helper functions to interact with sparse decimal represented in a byte array.
*/
// Get the integer ignore the sign
public static int getInteger(byte[] b, int index) {
return getInteger(b, index, true);
}
// Get the integer, ignore the sign
public static int getInteger(byte[] b, int index, boolean ignoreSign) {
int startIndex = index * DecimalUtility.INTEGER_SIZE;
if (index == 0 && ignoreSign == true) {
return (b[startIndex + 3] & 0xFF) |
(b[startIndex + 2] & 0xFF) << 8 |
(b[startIndex + 1] & 0xFF) << 16 |
(b[startIndex] & 0x7F) << 24;
}
return ((b[startIndex + 3] & 0xFF) |
(b[startIndex + 2] & 0xFF) << 8 |
(b[startIndex + 1] & 0xFF) << 16 |
(b[startIndex] & 0xFF) << 24);
}
// Set integer in the byte array
public static void setInteger(byte[] b, int index, int value) {
int startIndex = index * DecimalUtility.INTEGER_SIZE;
b[startIndex] = (byte) ((value >> 24) & 0xFF);
b[startIndex + 1] = (byte) ((value >> 16) & 0xFF);
b[startIndex + 2] = (byte) ((value >> 8) & 0xFF);
b[startIndex + 3] = (byte) ((value) & 0xFF);
}
// Set the sign in a sparse decimal representation
public static void setSign(byte[] b, boolean sign) {
int value = getInteger(b, 0);
if (sign == true) {
setInteger(b, 0, value | 0x80000000);
} else {
setInteger(b, 0, value & 0x7FFFFFFF);
}
}
// Get the sign
public static boolean getSign(byte[] b) {
return ((getInteger(b, 0, false) & 0x80000000) != 0);
}
}