| /* |
| * 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.datasketches.memory; |
| |
| import static org.apache.datasketches.memory.UnsafeUtil.checkBounds; |
| |
| import java.util.Random; |
| |
| /** |
| * @author Lee Rhodes |
| */ |
| public final class Util { |
| private Util() { } |
| |
| /** |
| * Searches a range of the specified array of longs for the specified value using the binary |
| * search algorithm. The range must be sorted method) prior to making this call. |
| * If it is not sorted, the results are undefined. If the range contains |
| * multiple elements with the specified value, there is no guarantee which one will be found. |
| * @param mem the Memory to be searched |
| * @param fromLongIndex the index of the first element (inclusive) to be searched |
| * @param toLongIndex the index of the last element (exclusive) to be searched |
| * @param key the value to be searched for |
| * @return index of the search key, if it is contained in the array within the specified range; |
| * otherwise, (-(insertion point) - 1). The insertion point is defined as the point at which |
| * the key would be inserted into the array: the index of the first element in the range greater |
| * than the key, or toIndex if all elements in the range are less than the specified key. |
| * Note that this guarantees that the return value will be ≥ 0 if and only if the key is found. |
| */ |
| public static long binarySearchLongs(final Memory mem, final long fromLongIndex, |
| final long toLongIndex, final long key) { |
| checkBounds(fromLongIndex << 3, (toLongIndex - fromLongIndex) << 3, mem.getCapacity()); |
| long low = fromLongIndex; |
| long high = toLongIndex - 1L; |
| |
| while (low <= high) { |
| final long mid = (low + high) >>> 1; |
| final long midVal = mem.getLong(mid << 3); |
| |
| if (midVal < key) { low = mid + 1; } |
| else if (midVal > key) { high = mid - 1; } |
| else { return mid; } // key found |
| } |
| return -(low + 1); // key not found. |
| } |
| |
| /** |
| * Prepend the given string with zeros. If the given string is equal or greater than the given |
| * field length, it will be returned without modification. |
| * @param s the given string |
| * @param fieldLength desired total field length including the given string |
| * @return the given string prepended with zeros. |
| */ |
| public static final String zeroPad(final String s, final int fieldLength) { |
| return characterPad(s, fieldLength, '0', false); |
| } |
| |
| /** |
| * Prepend or postpend the given string with the given character to fill the given field length. |
| * If the given string is equal or greater than the given field length, it will be returned |
| * without modification. |
| * @param s the given string |
| * @param fieldLength the desired field length |
| * @param padChar the desired pad character |
| * @param postpend if true append the pacCharacters to the end of the string. |
| * @return prepended or postpended given string with the given character to fill the given field |
| * length. |
| */ |
| public static final String characterPad(final String s, final int fieldLength, |
| final char padChar, final boolean postpend) { |
| final char[] chArr = s.toCharArray(); |
| final int sLen = chArr.length; |
| if (sLen < fieldLength) { |
| final char[] out = new char[fieldLength]; |
| final int blanks = fieldLength - sLen; |
| |
| if (postpend) { |
| for (int i = 0; i < sLen; i++) { |
| out[i] = chArr[i]; |
| } |
| for (int i = sLen; i < fieldLength; i++) { |
| out[i] = padChar; |
| } |
| } else { //prepend |
| for (int i = 0; i < blanks; i++) { |
| out[i] = padChar; |
| } |
| for (int i = blanks; i < fieldLength; i++) { |
| out[i] = chArr[i - blanks]; |
| } |
| } |
| |
| return String.valueOf(out); |
| } |
| return s; |
| } |
| |
| /** |
| * Return true if all the masked bits of value are zero |
| * @param value the value to be tested |
| * @param bitMask defines the bits of interest |
| * @return true if all the masked bits of value are zero |
| */ |
| public static final boolean isAllBitsClear(final long value, final long bitMask) { |
| return (~value & bitMask) == bitMask; |
| } |
| |
| /** |
| * Return true if all the masked bits of value are one |
| * @param value the value to be tested |
| * @param bitMask defines the bits of interest |
| * @return true if all the masked bits of value are one |
| */ |
| public static final boolean isAllBitsSet(final long value, final long bitMask) { |
| return (value & bitMask) == bitMask; |
| } |
| |
| /** |
| * Return true if any the masked bits of value are zero |
| * @param value the value to be tested |
| * @param bitMask defines the bits of interest |
| * @return true if any the masked bits of value are zero |
| */ |
| public static final boolean isAnyBitsClear(final long value, final long bitMask) { |
| return (~value & bitMask) != 0; |
| } |
| |
| /** |
| * Return true if any the masked bits of value are one |
| * @param value the value to be tested |
| * @param bitMask defines the bits of interest |
| * @return true if any the masked bits of value are one |
| */ |
| public static final boolean isAnyBitsSet(final long value, final long bitMask) { |
| return (value & bitMask) != 0; |
| } |
| |
| /** |
| * Creates random valid Character Code Points (as integers). By definition, valid CodePoints |
| * are integers in the range 0 to Character.MAX_CODE_POINT, and exclude the surrogate values. |
| * This is used in unit testing and characterization testing of the UTF8 class. Because the |
| * characterization tools are in a separate package, this must remain public. |
| * |
| * @author Lee Rhodes |
| */ |
| public static class RandomCodePoints { |
| private Random rand; // |
| private static final int ALL_CP = Character.MAX_CODE_POINT + 1; |
| private static final int MIN_SUR = Character.MIN_SURROGATE; |
| private static final int MAX_SUR = Character.MAX_SURROGATE; |
| |
| /** |
| * @param deterministic if true, configure java.util.Random with a fixed seed. |
| */ |
| public RandomCodePoints(final boolean deterministic) { |
| rand = deterministic ? new Random(0) : new Random(); |
| } |
| |
| /** |
| * Fills the given array with random valid Code Points from 0, inclusive, to |
| * <i>Character.MAX_CODE_POINT</i>, inclusive. |
| * The surrogate range, which is from <i>Character.MIN_SURROGATE</i>, inclusive, to |
| * <i>Character.MAX_SURROGATE</i>, inclusive, is always <u>excluded</u>. |
| * @param cpArr the array to fill |
| */ |
| public final void fillCodePointArray(final int[] cpArr) { |
| fillCodePointArray(cpArr, 0, ALL_CP); |
| } |
| |
| /** |
| * Fills the given array with random valid Code Points from <i>startCP</i>, inclusive, to |
| * <i>endCP</i>, exclusive. |
| * The surrogate range, which is from <i>Character.MIN_SURROGATE</i>, inclusive, to |
| * <i>Character.MAX_SURROGATE</i>, inclusive, is always <u>excluded</u>. |
| * @param cpArr the array to fill |
| * @param startCP the starting Code Point, included. |
| * @param endCP the ending Code Point, excluded. This value cannot exceed 0x110000. |
| */ |
| public final void fillCodePointArray(final int[] cpArr, final int startCP, final int endCP) { |
| final int arrLen = cpArr.length; |
| final int numCP = Math.min(endCP, 0X110000) - Math.min(0, startCP); |
| int idx = 0; |
| while (idx < arrLen) { |
| final int cp = startCP + rand.nextInt(numCP); |
| if ((cp >= MIN_SUR) && (cp <= MAX_SUR)) { |
| continue; |
| } |
| cpArr[idx++] = cp; |
| } |
| } |
| |
| /** |
| * Return a single valid random Code Point from 0, inclusive, to |
| * <i>Character.MAX_CODE_POINT</i>, inclusive. |
| * The surrogate range, which is from <i>Character.MIN_SURROGATE</i>, inclusive, to |
| * <i>Character.MAX_SURROGATE</i>, inclusive, is always <u>excluded</u>. |
| * @return a single valid random CodePoint. |
| */ |
| public final int getCodePoint() { |
| return getCodePoint(0, ALL_CP); |
| } |
| |
| /** |
| * Return a single valid random Code Point from <i>startCP</i>, inclusive, to |
| * <i>endCP</i>, exclusive. |
| * The surrogate range, which is from <i>Character.MIN_SURROGATE</i>, inclusive, to |
| * <i>Character.MAX_SURROGATE</i>, inclusive, is always <u>excluded</u>. |
| * @param startCP the starting Code Point, included. |
| * @param endCP the ending Code Point, excluded. This value cannot exceed 0x110000. |
| * @return a single valid random CodePoint. |
| */ |
| public final int getCodePoint(final int startCP, final int endCP) { |
| final int numCP = Math.min(endCP, 0X110000) - Math.min(0, startCP); |
| while (true) { |
| final int cp = startCP + rand.nextInt(numCP); |
| if ((cp < MIN_SUR) || (cp > MAX_SUR)) { |
| return cp; |
| } |
| } |
| } |
| } //End class RandomCodePoints |
| |
| static final void zeroCheck(final long value, final String arg) { |
| if (value <= 0) { |
| throw new IllegalArgumentException("The argument " + arg + " may not be negative or zero."); |
| } |
| } |
| |
| static final void negativeCheck(final long value, final String arg) { |
| if (value < 0) { |
| throw new IllegalArgumentException("The argument " + arg + " may not be negative."); |
| } |
| } |
| |
| static final void nullCheck(final Object obj, final String arg) { |
| if (obj == null) { |
| throw new IllegalArgumentException("The argument " + arg + " may not be null."); |
| } |
| } |
| |
| } |