package io.blobkeeper.common.util;
/*
* Copyright (C) 2015 by Denis M. Gabaydulin
*
* 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.
*/
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.Range;
import org.jetbrains.annotations.NotNull;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.SortedMap;
import java.util.function.BinaryOperator;
public class Utils {
private Utils() {
}
/**
* @return The bitwise XOR of the inputs. The output will be the same length as the
* longer input, but if either input is null, the output will be null.
*/
public static byte[] xor(byte[] left, byte[] right) {
if (left == null || right == null) {
return null;
}
if (left.length > right.length) {
byte[] swap = left;
left = right;
right = swap;
}
// left.length is now <= right.length
byte[] out = Arrays.copyOf(right, right.length);
for (int i = 0; i < left.length; i++) {
out[i] = (byte) ((left[i] & 0xFF) ^ (right[i] & 0xFF));
}
return out;
}
public static long midPoint(long left, long right) {
// using BigInteger to avoid long overflow in intermediate operations
BigInteger l = BigInteger.valueOf(left);
BigInteger r = BigInteger.valueOf(right);
BigInteger midPoint;
if (l.compareTo(r) < 0) {
BigInteger sum = l.add(r);
midPoint = sum.shiftRight(1);
} else { // wrapping case
BigInteger max = BigInteger.valueOf(Long.MAX_VALUE);
BigInteger min = BigInteger.valueOf(Long.MIN_VALUE);
// length of range we're bisecting is (R - min) + (max - L)
// so we add that to L giving
// L + ((R - min) + (max - L) / 2) = (L + R + max - min) / 2
midPoint = (max.subtract(min).add(l).add(r)).shiftRight(1);
if (midPoint.compareTo(max) > 0)
midPoint = min.add(midPoint.subtract(max));
}
return midPoint.longValue();
}
public static <T> BinaryOperator<T> throwingMerger() {
return (u, v) -> {
throw new IllegalStateException(String.format("Duplicate key %s", u));
};
}
public static MerkleTree createEmptyTree(@NotNull Range<Long> range, int depth) {
MerkleTree tree = new MerkleTree(range, depth);
MerkleTree.fillTree(tree, ImmutableSortedMap.of());
tree.calculate();
return tree;
}
public static MerkleTree createTree(@NotNull Range<Long> range, int depth, @NotNull SortedMap<Long, Block> blocks) {
MerkleTree tree = new MerkleTree(range, depth);
MerkleTree.fillTree(tree, blocks);
tree.calculate();
return tree;
}
}