com.aerospike.client.exp.BitExp Maven / Gradle / Ivy
/*
* Copyright 2012-2021 Aerospike, Inc.
*
* Portions may be licensed to Aerospike, Inc. under one or more contributor
* license agreements WHICH ARE COMPATIBLE WITH THE APACHE LICENSE, VERSION 2.0.
*
* Licensed 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 com.aerospike.client.exp;
import com.aerospike.client.operation.BitOverflowAction;
import com.aerospike.client.operation.BitPolicy;
import com.aerospike.client.operation.BitResizeFlags;
import com.aerospike.client.util.Pack;
import com.aerospike.client.util.Packer;
/**
* Bit expression generator. See {@link com.aerospike.client.exp.Exp}.
*
* The bin expression argument in these methods can be a reference to a bin or the
* result of another expression. Expressions that modify bin values are only used
* for temporary expression evaluation and are not permanently applied to the bin.
* Bit modify expressions return the blob bin's value.
*
* Offset orientation is left-to-right. Negative offsets are supported.
* If the offset is negative, the offset starts backwards from end of the bitmap.
* If an offset is out of bounds, a parameter error will be returned.
*/
public final class BitExp {
private static final int MODULE = 1;
private static final int RESIZE = 0;
private static final int INSERT = 1;
private static final int REMOVE = 2;
private static final int SET = 3;
private static final int OR = 4;
private static final int XOR = 5;
private static final int AND = 6;
private static final int NOT = 7;
private static final int LSHIFT = 8;
private static final int RSHIFT = 9;
private static final int ADD = 10;
private static final int SUBTRACT = 11;
private static final int SET_INT = 12;
private static final int GET = 50;
private static final int COUNT = 51;
private static final int LSCAN = 52;
private static final int RSCAN = 53;
private static final int GET_INT = 54;
private static final int INT_FLAGS_SIGNED = 1;
/**
* Create expression that resizes byte[] to byteSize according to resizeFlags (See {@link BitResizeFlags})
* and returns byte[].
*
* - bin = [0b00000001, 0b01000010]
* - byteSize = 4
* - resizeFlags = 0
* - returns [0b00000001, 0b01000010, 0b00000000, 0b00000000]
*
* {@code
* // Resize bin "a" and compare bit count
* Exp.eq(
* BitExp.count(Exp.val(0), Exp.val(3),
* BitExp.resize(BitPolicy.Default, Exp.val(4), 0, Exp.blobBin("a"))),
* Exp.val(2))
* }
*/
public static Exp resize(BitPolicy policy, Exp byteSize, int resizeFlags, Exp bin) {
byte[] bytes = Pack.pack(RESIZE, byteSize, policy.flags, resizeFlags);
return addWrite(bin, bytes);
}
/**
* Create expression that inserts value bytes into byte[] bin at byteOffset and returns byte[].
*
* - bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101]
* - byteOffset = 1
* - value = [0b11111111, 0b11000111]
* - bin result = [0b00000001, 0b11111111, 0b11000111, 0b01000010, 0b00000011, 0b00000100, 0b00000101]
*
* {@code
* // Insert bytes into bin "a" and compare bit count
* Exp.eq(
* BitExp.count(Exp.val(0), Exp.val(3),
* BitExp.insert(BitPolicy.Default, Exp.val(1), Exp.val(bytes), Exp.blobBin("a"))),
* Exp.val(2))
* }
*/
public static Exp insert(BitPolicy policy, Exp byteOffset, Exp value, Exp bin) {
byte[] bytes = Pack.pack(INSERT, byteOffset, value, policy.flags);
return addWrite(bin, bytes);
}
/**
* Create expression that removes bytes from byte[] bin at byteOffset for byteSize and returns byte[].
*
* - bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101]
* - byteOffset = 2
* - byteSize = 3
* - bin result = [0b00000001, 0b01000010]
*
* {@code
* // Remove bytes from bin "a" and compare bit count
* Exp.eq(
* BitExp.count(Exp.val(0), Exp.val(3),
* BitExp.remove(BitPolicy.Default, Exp.val(2), Exp.val(3), Exp.blobBin("a"))),
* Exp.val(2))
* }
*/
public static Exp remove(BitPolicy policy, Exp byteOffset, Exp byteSize, Exp bin) {
byte[] bytes = Pack.pack(REMOVE, byteOffset, byteSize, policy.flags);
return addWrite(bin, bytes);
}
/**
* Create expression that sets value on byte[] bin at bitOffset for bitSize and returns byte[].
*
* - bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101]
* - bitOffset = 13
* - bitSize = 3
* - value = [0b11100000]
* - bin result = [0b00000001, 0b01000111, 0b00000011, 0b00000100, 0b00000101]
*
* {@code
* // Set bytes in bin "a" and compare bit count
* Exp.eq(
* BitExp.count(Exp.val(0), Exp.val(3),
* BitExp.set(BitPolicy.Default, Exp.val(13), Exp.val(3), Exp.val(bytes), Exp.blobBin("a"))),
* Exp.val(2))
* }
*/
public static Exp set(BitPolicy policy, Exp bitOffset, Exp bitSize, Exp value, Exp bin) {
byte[] bytes = Pack.pack(SET, bitOffset, bitSize, value, policy.flags);
return addWrite(bin, bytes);
}
/**
* Create expression that performs bitwise "or" on value and byte[] bin at bitOffset for bitSize
* and returns byte[].
*
* - bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101]
* - bitOffset = 17
* - bitSize = 6
* - value = [0b10101000]
* - bin result = [0b00000001, 0b01000010, 0b01010111, 0b00000100, 0b00000101]
*
*/
public static Exp or(BitPolicy policy, Exp bitOffset, Exp bitSize, Exp value, Exp bin) {
byte[] bytes = Pack.pack(OR, bitOffset, bitSize, value, policy.flags);
return addWrite(bin, bytes);
}
/**
* Create expression that performs bitwise "xor" on value and byte[] bin at bitOffset for bitSize
* and returns byte[].
*
* - bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101]
* - bitOffset = 17
* - bitSize = 6
* - value = [0b10101100]
* - bin result = [0b00000001, 0b01000010, 0b01010101, 0b00000100, 0b00000101]
*
*/
public static Exp xor(BitPolicy policy, Exp bitOffset, Exp bitSize, Exp value, Exp bin) {
byte[] bytes = Pack.pack(XOR, bitOffset, bitSize, value, policy.flags);
return addWrite(bin, bytes);
}
/**
* Create expression that performs bitwise "and" on value and byte[] bin at bitOffset for bitSize
* and returns byte[].
*
* - bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101]
* - bitOffset = 23
* - bitSize = 9
* - value = [0b00111100, 0b10000000]
* - bin result = [0b00000001, 0b01000010, 0b00000010, 0b00000000, 0b00000101]
*
*/
public static Exp and(BitPolicy policy, Exp bitOffset, Exp bitSize, Exp value, Exp bin) {
byte[] bytes = Pack.pack(AND, bitOffset, bitSize, value, policy.flags);
return addWrite(bin, bytes);
}
/**
* Create expression that negates byte[] bin starting at bitOffset for bitSize and returns byte[].
*
* - bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101]
* - bitOffset = 25
* - bitSize = 6
* - bin result = [0b00000001, 0b01000010, 0b00000011, 0b01111010, 0b00000101]
*
*/
public static Exp not(BitPolicy policy, Exp bitOffset, Exp bitSize, Exp bin) {
byte[] bytes = Pack.pack(NOT, bitOffset, bitSize, policy.flags);
return addWrite(bin, bytes);
}
/**
* Create expression that shifts left byte[] bin starting at bitOffset for bitSize and returns byte[].
*
* - bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101]
* - bitOffset = 32
* - bitSize = 8
* - shift = 3
* - bin result = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00101000]
*
*/
public static Exp lshift(BitPolicy policy, Exp bitOffset, Exp bitSize, Exp shift, Exp bin) {
byte[] bytes = Pack.pack(LSHIFT, bitOffset, bitSize, shift, policy.flags);
return addWrite(bin, bytes);
}
/**
* Create expression that shifts right byte[] bin starting at bitOffset for bitSize and returns byte[].
*
* - bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101]
* - bitOffset = 0
* - bitSize = 9
* - shift = 1
* - bin result = [0b00000000, 0b11000010, 0b00000011, 0b00000100, 0b00000101]
*
*/
public static Exp rshift(BitPolicy policy, Exp bitOffset, Exp bitSize, Exp shift, Exp bin) {
byte[] bytes = Pack.pack(RSHIFT, bitOffset, bitSize, shift, policy.flags);
return addWrite(bin, bytes);
}
/**
* Create expression that adds value to byte[] bin starting at bitOffset for bitSize and returns byte[].
* BitSize must be <= 64. Signed indicates if bits should be treated as a signed number.
* If add overflows/underflows, {@link BitOverflowAction} is used.
*
* - bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101]
* - bitOffset = 24
* - bitSize = 16
* - value = 128
* - signed = false
* - bin result = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b10000101]
*
*/
public static Exp add(
BitPolicy policy,
Exp bitOffset,
Exp bitSize,
Exp value,
boolean signed,
BitOverflowAction action,
Exp bin
) {
byte[] bytes = packMath(ADD, policy, bitOffset, bitSize, value, signed, action);
return addWrite(bin, bytes);
}
/**
* Create expression that subtracts value from byte[] bin starting at bitOffset for bitSize and returns byte[].
* BitSize must be <= 64. Signed indicates if bits should be treated as a signed number.
* If add overflows/underflows, {@link BitOverflowAction} is used.
*
* - bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101]
* - bitOffset = 24
* - bitSize = 16
* - value = 128
* - signed = false
* - bin result = [0b00000001, 0b01000010, 0b00000011, 0b0000011, 0b10000101]
*
*/
public static Exp subtract(
BitPolicy policy,
Exp bitOffset,
Exp bitSize,
Exp value,
boolean signed,
BitOverflowAction action,
Exp bin
) {
byte[] bytes = packMath(SUBTRACT, policy, bitOffset, bitSize, value, signed, action);
return addWrite(bin, bytes);
}
/**
* Create expression that sets value to byte[] bin starting at bitOffset for bitSize and returns byte[].
* BitSize must be <= 64.
*
* - bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101]
* - bitOffset = 1
* - bitSize = 8
* - value = 127
* - bin result = [0b00111111, 0b11000010, 0b00000011, 0b0000100, 0b00000101]
*
*/
public static Exp setInt(BitPolicy policy, Exp bitOffset, Exp bitSize, Exp value, Exp bin) {
byte[] bytes = Pack.pack(SET_INT, bitOffset, bitSize, value, policy.flags);
return addWrite(bin, bytes);
}
/**
* Create expression that returns bits from byte[] bin starting at bitOffset for bitSize.
*
* - bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101]
* - bitOffset = 9
* - bitSize = 5
* - returns [0b10000000]
*
* {@code
* // Bin "a" bits = [0b10000000]
* Exp.eq(
* BitExp.get(Exp.val(9), Exp.val(5), Exp.blobBin("a")),
* Exp.val(new byte[] {(byte)0b10000000}))
* }
*/
public static Exp get(Exp bitOffset, Exp bitSize, Exp bin) {
byte[] bytes = Pack.pack(GET, bitOffset, bitSize);
return addRead(bin, bytes, Exp.Type.BLOB);
}
/**
* Create expression that returns integer count of set bits from byte[] bin starting at
* bitOffset for bitSize.
*
* - bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101]
* - bitOffset = 20
* - bitSize = 4
* - returns 2
*
* {@code
* // Bin "a" bit count <= 2
* Exp.le(BitExp.count(Exp.val(0), Exp.val(5), Exp.blobBin("a")), Exp.val(2))
* }
*/
public static Exp count(Exp bitOffset, Exp bitSize, Exp bin) {
byte[] bytes = Pack.pack(COUNT, bitOffset, bitSize);
return addRead(bin, bytes, Exp.Type.INT);
}
/**
* Create expression that returns integer bit offset of the first specified value bit in byte[] bin
* starting at bitOffset for bitSize.
*
* - bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101]
* - bitOffset = 24
* - bitSize = 8
* - value = true
* - returns 5
*
* {@code
* // lscan(a) == 5
* Exp.eq(BitExp.lscan(Exp.val(24), Exp.val(8), Exp.val(true), Exp.blobBin("a")), Exp.val(5))
* }
*
* @param bitOffset offset int expression
* @param bitSize size int expression
* @param value boolean expression
* @param bin bin or blob value expression
*/
public static Exp lscan(Exp bitOffset, Exp bitSize, Exp value, Exp bin) {
byte[] bytes = Pack.pack(LSCAN, bitOffset, bitSize, value);
return addRead(bin, bytes, Exp.Type.INT);
}
/**
* Create expression that returns integer bit offset of the last specified value bit in byte[] bin
* starting at bitOffset for bitSize.
* Example:
*
* - bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101]
* - bitOffset = 32
* - bitSize = 8
* - value = true
* - returns 7
*
* {@code
* // rscan(a) == 7
* Exp.eq(BitExp.rscan(Exp.val(32), Exp.val(8), Exp.val(true), Exp.blobBin("a")), Exp.val(7))
* }
*
* @param bitOffset offset int expression
* @param bitSize size int expression
* @param value boolean expression
* @param bin bin or blob value expression
*/
public static Exp rscan(Exp bitOffset, Exp bitSize, Exp value, Exp bin) {
byte[] bytes = Pack.pack(RSCAN, bitOffset, bitSize, value);
return addRead(bin, bytes, Exp.Type.INT);
}
/**
* Create expression that returns integer from byte[] bin starting at bitOffset for bitSize.
* Signed indicates if bits should be treated as a signed number.
*
* - bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101]
* - bitOffset = 8
* - bitSize = 16
* - signed = false
* - returns 16899
*
* {@code
* // getInt(a) == 16899
* Exp.eq(BitExp.getInt(Exp.val(8), Exp.val(16), false, Exp.blobBin("a")), Exp.val(16899))
* }
*/
public static Exp getInt(Exp bitOffset, Exp bitSize, boolean signed, Exp bin) {
byte[] bytes = packGetInt(bitOffset, bitSize, signed);
return addRead(bin, bytes, Exp.Type.INT);
}
private static byte[] packMath(
int command,
BitPolicy policy,
Exp bitOffset,
Exp bitSize,
Exp value,
boolean signed,
BitOverflowAction action
) {
Packer packer = new Packer();
// Pack.init() only required when CTX is used and server does not support CTX for bit operations.
// Pack.init(packer, ctx);
packer.packArrayBegin(6);
packer.packInt(command);
bitOffset.pack(packer);
bitSize.pack(packer);
value.pack(packer);
packer.packInt(policy.flags);
int flags = action.flags;
if (signed) {
flags |= INT_FLAGS_SIGNED;
}
packer.packInt(flags);
return packer.toByteArray();
}
private static byte[] packGetInt(Exp bitOffset, Exp bitSize, boolean signed) {
Packer packer = new Packer();
// Pack.init() only required when CTX is used and server does not support CTX for bit operations.
// Pack.init(packer, ctx);
packer.packArrayBegin(signed ? 4 : 3);
packer.packInt(GET_INT);
bitOffset.pack(packer);
bitSize.pack(packer);
if (signed) {
packer.packInt(INT_FLAGS_SIGNED);
}
return packer.toByteArray();
}
private static Exp addWrite(Exp bin, byte[] bytes) {
return new Exp.Module(bin, bytes, Exp.Type.BLOB.code, MODULE | Exp.MODIFY);
}
private static Exp addRead(Exp bin, byte[] bytes, Exp.Type retType) {
return new Exp.Module(bin, bytes, retType.code, MODULE);
}
}