/*
* 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.cassandra.utils;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Random;
import org.junit.Test;
public class FastByteOperationsTest
{
private static final FastByteOperations.PureJavaOperations PJO = new FastByteOperations.PureJavaOperations();
private static final FastByteOperations.UnsafeOperations UO = new FastByteOperations.UnsafeOperations();
private static final Random rand = new Random(0);
private static final ByteBuffer dbuf1 = ByteBuffer.allocateDirect(150);
private static final ByteBuffer dbuf2 = ByteBuffer.allocateDirect(150);
private static final ByteBuffer hbuf1 = ByteBuffer.allocate(150);
private static final ByteBuffer hbuf2 = ByteBuffer.allocate(150);
@Test
public void testFastByteCopy()
{
byte[] bytes1 = new byte[128];
byte[] empty = new byte[128];
rand.nextBytes(bytes1);
testCopy(bytes1, wrap1(bytes1, true), wrap2(empty, true), PJO);
testCopy(bytes1, wrap1(bytes1, true), wrap2(empty, false), PJO);
testCopy(bytes1, wrap1(bytes1, false), wrap2(empty, true), PJO);
testCopy(bytes1, wrap1(bytes1, false), wrap2(empty, false), PJO);
testCopy(bytes1, wrap1(bytes1, true), wrap2(empty, true), UO);
testCopy(bytes1, wrap1(bytes1, true), wrap2(empty, false), UO);
testCopy(bytes1, wrap1(bytes1, false), wrap2(empty, true), UO);
testCopy(bytes1, wrap1(bytes1, false), wrap2(empty, false), UO);
}
private void testCopy(byte[] canon, ByteBuffer src, ByteBuffer trg, FastByteOperations.ByteOperations ops)
{
byte[] result = new byte[src.remaining()];
ops.copy(src, src.position(), trg, trg.position(), src.remaining());
ops.copy(trg, trg.position(), result, 0, trg.remaining());
assert firstdiff(canon, result) < 0;
}
private static int firstdiff(byte[] canon, byte[] test)
{
for (int i = 0 ; i < canon.length ; i++)
if (canon[i] != test[i])
return i;
return -1;
}
@Test
public void testFastByteComparisons()
{
byte[] bytes1 = new byte[128];
for (int i = 0 ; i < 1000 ; i++)
{
rand.nextBytes(bytes1);
for (int j = 0 ; j < 16 ; j++)
{
byte[] bytes2 = Arrays.copyOf(bytes1, bytes1.length - j);
testTwiddleOneByteComparisons(bytes1, bytes2, 16, true, 1);
testTwiddleOneByteComparisons(bytes1, bytes2, 16, true, -1);
testTwiddleOneByteComparisons(bytes1, bytes2, 16, false, 1);
testTwiddleOneByteComparisons(bytes1, bytes2, 16, false, -1);
testTwiddleOneByteComparisons(bytes1, bytes2, 16, true, 128);
testTwiddleOneByteComparisons(bytes1, bytes2, 16, false, 128);
}
}
}
private void testTwiddleOneByteComparisons(byte[] bytes1, byte[] bytes2, int count, boolean start, int inc)
{
for (int j = 0 ; j < count ; j++)
{
int index = start ? j : bytes2.length - (j + 1);
bytes2[index] += inc;
testComparisons(bytes1, bytes2);
bytes2[index] -= inc;
}
}
private static ByteBuffer wrap1(byte[] bytes, boolean direct)
{
return slice(bytes, direct ? dbuf1 : hbuf1);
}
private static ByteBuffer wrap2(byte[] bytes, boolean direct)
{
return slice(bytes, direct ? dbuf2 : hbuf2);
}
private static ByteBuffer slice(byte[] bytes, ByteBuffer buf)
{
buf = buf.duplicate();
buf.position((buf.limit() - bytes.length) / 2);
buf.limit(buf.position() + bytes.length);
buf.duplicate().put(bytes);
return buf;
}
private void testComparisons(byte[] bytes1, byte[] bytes2)
{
testComparison(bytes1, bytes2);
testComparison(bytes2, bytes1);
testComparison(wrap1(bytes1, false), bytes2);
testComparison(wrap2(bytes2, false), bytes1);
testComparison(wrap1(bytes1, false), wrap2(bytes2, false));
testComparison(wrap2(bytes2, false), wrap1(bytes1, false));
testComparison(wrap1(bytes1, true), bytes2);
testComparison(wrap2(bytes2, true), bytes1);
testComparison(wrap1(bytes1, true), wrap2(bytes2, true));
testComparison(wrap2(bytes2, true), wrap1(bytes1, true));
testComparison(wrap1(bytes1, true), wrap2(bytes2, false));
testComparison(wrap1(bytes1, false), wrap2(bytes2, true));
testComparison(wrap2(bytes2, true), wrap1(bytes1, false));
testComparison(wrap2(bytes2, false), wrap1(bytes1, true));
}
private void testComparison(byte[] bytes1, byte[] bytes2)
{
assert sameComparisonResult(PJO.compare(bytes1, 0, bytes1.length, bytes2, 0, bytes2.length), UO.compare(bytes1, 0, bytes1.length, bytes2, 0, bytes2.length));
assert sameComparisonResult(PJO.compare(bytes1, 10, bytes1.length - 10, bytes2, 10, bytes2.length - 10), UO.compare(bytes1, 10, bytes1.length - 10, bytes2, 10, bytes2.length - 10));
}
private void testComparison(ByteBuffer bytes1, byte[] bytes2)
{
assert sameComparisonResult(PJO.compare(bytes1, bytes2, 0, bytes2.length), UO.compare(bytes1, bytes2, 0, bytes2.length));
assert sameComparisonResult(PJO.compare(bytes1, bytes2, 10, bytes2.length - 10), UO.compare(bytes1, bytes2, 10, bytes2.length - 10));
}
private void testComparison(ByteBuffer bytes1, ByteBuffer bytes2)
{
assert sameComparisonResult(PJO.compare(bytes1, bytes2), UO.compare(bytes1, bytes2));
}
static boolean sameComparisonResult(int exp, int act)
{
if (exp < 0)
return act < 0;
if (exp > 0)
return act > 0;
return act == 0;
}
}