Added some packages from JPUtil (https://github.com/OLEGSHA/JPUtil)

- ru.windcorp.common.util.ThrowingRunnable replaced with
ru.windcorp.jputil.functions.ThrowingRunnable
This commit is contained in:
OLEGSHA 2020-08-26 18:34:52 +03:00
parent a9896fa3e1
commit 65eaae68a8
47 changed files with 6015 additions and 47 deletions

View File

@ -0,0 +1,525 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil;
import java.lang.reflect.Array;
import java.math.BigInteger;
import java.util.Objects;
public class ArrayUtil {
private ArrayUtil() {}
public static int firstIndexOf(byte[] array, byte element) {
for (int i = 0; i < array.length; ++i) {
if (array[i] == element) {
return i;
}
}
return -1;
}
public static int lastIndexOf(byte[] array, byte element) {
for (int i = array.length - 1; i >= 0; --i) {
if (array[i] == element) {
return i;
}
}
return -1;
}
public static int occurences(byte[] array, byte element) {
int result = 0;
for (int i = 0; i < array.length; ++i) {
if (array[i] == element) {
++result;
}
}
return result;
}
public static int hasDuplicates(byte[] array) {
for (int i = 0; i < array.length; ++i) {
byte a = array[i];
for (int j = i + 1; j < array.length; ++j) {
if (array[j] == a) {
return i;
}
}
}
return -1;
}
public static int firstIndexOf(short[] array, short element) {
for (int i = 0; i < array.length; ++i) {
if (array[i] == element) {
return i;
}
}
return -1;
}
public static int lastIndexOf(short[] array, short element) {
for (int i = array.length - 1; i >= 0; --i) {
if (array[i] == element) {
return i;
}
}
return -1;
}
public static int occurences(short[] array, short element) {
int result = 0;
for (int i = 0; i < array.length; ++i) {
if (array[i] == element) {
++result;
}
}
return result;
}
public static int hasDuplicates(short[] array) {
for (int i = 0; i < array.length; ++i) {
short a = array[i];
for (int j = i + 1; j < array.length; ++j) {
if (array[j] == a) {
return i;
}
}
}
return -1;
}
public static int firstIndexOf(int[] array, int element) {
for (int i = 0; i < array.length; ++i) {
if (array[i] == element) {
return i;
}
}
return -1;
}
public static int lastIndexOf(int[] array, int element) {
for (int i = array.length - 1; i >= 0; --i) {
if (array[i] == element) {
return i;
}
}
return -1;
}
public static int occurences(int[] array, int element) {
int result = 0;
for (int i = 0; i < array.length; ++i) {
if (array[i] == element) {
++result;
}
}
return result;
}
public static int hasDuplicates(int[] array) {
for (int i = 0; i < array.length; ++i) {
int a = array[i];
for (int j = i + 1; j < array.length; ++j) {
if (array[j] == a) {
return i;
}
}
}
return -1;
}
public static int firstIndexOf(long[] array, long element) {
for (int i = 0; i < array.length; ++i) {
if (array[i] == element) {
return i;
}
}
return -1;
}
public static int lastIndexOf(long[] array, long element) {
for (int i = array.length - 1; i >= 0; --i) {
if (array[i] == element) {
return i;
}
}
return -1;
}
public static int occurences(long[] array, long element) {
int result = 0;
for (int i = 0; i < array.length; ++i) {
if (array[i] == element) {
++result;
}
}
return result;
}
public static int hasDuplicates(long[] array) {
for (int i = 0; i < array.length; ++i) {
long a = array[i];
for (int j = i + 1; j < array.length; ++j) {
if (array[j] == a) {
return i;
}
}
}
return -1;
}
public static int firstIndexOf(float[] array, float element) {
for (int i = 0; i < array.length; ++i) {
if (array[i] == element) {
return i;
}
}
return -1;
}
public static int lastIndexOf(float[] array, float element) {
for (int i = array.length - 1; i >= 0; --i) {
if (array[i] == element) {
return i;
}
}
return -1;
}
public static int occurences(float[] array, float element) {
int result = 0;
for (int i = 0; i < array.length; ++i) {
if (array[i] == element) {
++result;
}
}
return result;
}
public static int hasDuplicates(float[] array) {
for (int i = 0; i < array.length; ++i) {
float a = array[i];
for (int j = i + 1; j < array.length; ++j) {
if (array[j] == a) {
return i;
}
}
}
return -1;
}
public static int firstIndexOf(double[] array, double element) {
for (int i = 0; i < array.length; ++i) {
if (array[i] == element) {
return i;
}
}
return -1;
}
public static int lastIndexOf(double[] array, double element) {
for (int i = array.length - 1; i >= 0; --i) {
if (array[i] == element) {
return i;
}
}
return -1;
}
public static int occurences(double[] array, double element) {
int result = 0;
for (int i = 0; i < array.length; ++i) {
if (array[i] == element) {
++result;
}
}
return result;
}
public static int hasDuplicates(double[] array) {
for (int i = 0; i < array.length; ++i) {
double a = array[i];
for (int j = i + 1; j < array.length; ++j) {
if (array[j] == a) {
return i;
}
}
}
return -1;
}
public static int firstIndexOf(boolean[] array, boolean element) {
for (int i = 0; i < array.length; ++i) {
if (array[i] == element) {
return i;
}
}
return -1;
}
public static int lastIndexOf(boolean[] array, boolean element) {
for (int i = array.length - 1; i >= 0; --i) {
if (array[i] == element) {
return i;
}
}
return -1;
}
public static int occurences(boolean[] array, boolean element) {
int result = 0;
for (int i = 0; i < array.length; ++i) {
if (array[i] == element) {
++result;
}
}
return result;
}
public static int firstIndexOf(char[] array, char element) {
for (int i = 0; i < array.length; ++i) {
if (array[i] == element) {
return i;
}
}
return -1;
}
public static int lastIndexOf(char[] array, char element) {
for (int i = array.length - 1; i >= 0; --i) {
if (array[i] == element) {
return i;
}
}
return -1;
}
public static int occurences(char[] array, char element) {
int result = 0;
for (int i = 0; i < array.length; ++i) {
if (array[i] == element) {
++result;
}
}
return result;
}
public static int hasDuplicates(char[] array) {
for (int i = 0; i < array.length; ++i) {
char a = array[i];
for (int j = i + 1; j < array.length; ++j) {
if (array[j] == a) {
return i;
}
}
}
return -1;
}
public static int firstIndexOf(Object[] array, Object element) {
for (int i = 0; i < array.length; ++i) {
if (array[i] == element) {
return i;
}
}
return -1;
}
public static int lastIndexOf(Object[] array, Object element) {
for (int i = array.length - 1; i >= 0; --i) {
if (array[i] == element) {
return i;
}
}
return -1;
}
public static int occurences(Object[] array, Object element) {
int result = 0;
for (int i = 0; i < array.length; ++i) {
if (array[i] == element) {
++result;
}
}
return result;
}
public static int hasDuplicates(Object[] array) {
for (int i = 0; i < array.length; ++i) {
Object a = array[i];
for (int j = i + 1; j < array.length; ++j) {
if (array[j] == a) {
return i;
}
}
}
return -1;
}
public static int firstIndexOfEqual(Object[] array, Object element) {
for (int i = 0; i < array.length; ++i) {
if (Objects.equals(array[i], element)) {
return i;
}
}
return -1;
}
public static int lastIndexOfEqual(Object[] array, Object element) {
for (int i = array.length - 1; i >= 0; --i) {
if (Objects.equals(array[i], element)) {
return i;
}
}
return -1;
}
public static int occurencesOfEqual(Object[] array, Object element) {
int result = 0;
for (int i = 0; i < array.length; ++i) {
if (Objects.equals(array[i], element)) {
++result;
}
}
return result;
}
public static int hasEquals(Object[] array) {
for (int i = 0; i < array.length; ++i) {
Object a = array[i];
for (int j = i + 1; j < array.length; ++j) {
if (Objects.equals(array[j], a)) {
return i;
}
}
}
return -1;
}
public static long sum(byte[] array, int start, int length) {
long s = 0;
length += start;
for (int i = start; i < length; ++i) {
s += array[i];
}
return s;
}
public static long sum(short[] array, int start, int length) {
long s = 0;
length += start;
for (int i = start; i < length; ++i) {
s += array[i];
}
return s;
}
public static long sum(int[] array, int start, int length) {
long s = 0;
length += start;
for (int i = start; i < length; ++i) {
s += array[i];
}
return s;
}
public static long sum(long[] array, int start, int length) {
long s = 0;
length += start;
for (int i = start; i < length; ++i) {
s += array[i];
}
return s;
}
public static BigInteger longSum(long[] array, int start, int length) {
BigInteger s = BigInteger.ZERO;
length += start;
for (int i = start; i < length; ++i) {
s = s.add(BigInteger.valueOf(array[i]));
}
return s;
}
public static float sum(float[] array, int start, int length) {
float s = 0;
length += start;
for (int i = start; i < length; ++i) {
s += array[i];
}
return s;
}
public static double sum(double[] array, int start, int length) {
double s = 0;
length += start;
for (int i = start; i < length; ++i) {
s += array[i];
}
return s;
}
public static long sum(char[] array, int start, int length) {
long s = 0;
length += start;
for (int i = start; i < length; ++i) {
s += array[i];
}
return s;
}
public static int checkArrayOffsetLength(Object array, int offset, int length) {
int arrayLength = Array.getLength(array);
if (length < 0)
length = arrayLength;
int end = offset + length;
if (end > arrayLength || offset < 0)
throw new IllegalArgumentException("Array contains [0; " + arrayLength + "), requested [" + offset + "; " + end + ")");
return length;
}
public static int checkArrayStartEnd(Object array, int start, int end) {
int arrayLength = Array.getLength(array);
if (end < 0)
end = arrayLength;
if (start > end)
throw new IllegalArgumentException("Start > end: " + start + " > " + end);
if (end > arrayLength || start < 0)
throw new IllegalArgumentException("Array contains [0; " + arrayLength + "), requested [" + start + "; " + end + ")");
return end;
}
}

View File

@ -0,0 +1,104 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Writer;
public class CSVWriter {
private String columnSeparator = ";";
private String rowSeparator = "\n";
private boolean shouldAddSeparator = false;
private final PrintWriter parent;
public CSVWriter(PrintWriter output) {
this.parent = output;
}
public CSVWriter(Writer output) {
this(new PrintWriter(output));
}
public CSVWriter(OutputStream output) {
this(new PrintWriter(output));
}
public PrintWriter getParent() {
return parent;
}
public String getColumnSeparator() {
return columnSeparator;
}
public CSVWriter setColumnSeparator(String columnSeparator) {
this.columnSeparator = columnSeparator;
return this;
}
public String getRowSeparator() {
return rowSeparator;
}
public CSVWriter setRowSeparator(String rowSeparator) {
this.rowSeparator = rowSeparator;
return this;
}
public void print(Object object) {
skip();
getParent().print(String.valueOf(object));
}
public void skip() {
if (shouldAddSeparator) {
getParent().print(getColumnSeparator());
} else {
shouldAddSeparator = true;
}
}
public void skip(int amount) {
for (int i = 0; i < amount; ++i) {
skip();
}
}
public void endRow() {
getParent().print(getRowSeparator());
shouldAddSeparator = false;
}
public void endRow(Object object) {
print(object);
endRow();
}
public void flush() {
getParent().flush();
}
public void close() {
getParent().close();
}
}

View File

@ -0,0 +1,60 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil;
import java.util.HashMap;
import java.util.Map;
public class PrimitiveUtil {
private PrimitiveUtil() {}
private static final Map<Class<?>, Class<?>> PRIMITIVE_TO_BOXED = new HashMap<>();
private static final Map<Class<?>, Object> PRIMITIVE_TO_NULL = new HashMap<>();
static {
for (Class<?> boxed : new Class<?>[] {
Boolean.class, Byte.class, Short.class, Character.class,
Integer.class, Long.class, Float.class, Double.class
}) {
try {
PRIMITIVE_TO_BOXED.put((Class<?>) boxed.getField("TYPE").get(null), boxed);
} catch (Exception e) {
e.printStackTrace();
}
}
PRIMITIVE_TO_NULL.put(Boolean.TYPE, Boolean.FALSE);
PRIMITIVE_TO_NULL.put(Byte.TYPE, Byte.valueOf((byte) 0));
PRIMITIVE_TO_NULL.put(Short.TYPE, Short.valueOf((short) 0));
PRIMITIVE_TO_NULL.put(Integer.TYPE, Integer.valueOf(0));
PRIMITIVE_TO_NULL.put(Long.TYPE, Long.valueOf(0));
PRIMITIVE_TO_NULL.put(Float.TYPE, Float.valueOf(Float.NaN));
PRIMITIVE_TO_NULL.put(Double.TYPE, Double.valueOf(Double.NaN));
PRIMITIVE_TO_NULL.put(Character.TYPE, Character.valueOf('\u0000'));
}
public static Class<?> getBoxedClass(Class<?> primitiveClass) {
return PRIMITIVE_TO_BOXED.getOrDefault(primitiveClass, primitiveClass);
}
public static Object getPrimitiveNull(Class<?> primitiveClass) {
return PRIMITIVE_TO_NULL.get(primitiveClass);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,44 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil;
public class SyntaxException extends Exception {
private static final long serialVersionUID = -4052144233640072750L;
public SyntaxException() {
}
public SyntaxException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public SyntaxException(String message, Throwable cause) {
super(message, cause);
}
public SyntaxException(String message) {
super(message);
}
public SyntaxException(Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,128 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars;
import java.text.CharacterIterator;
public class CharArrayIterator implements CharacterIterator {
private final char[] array;
private int pos;
public CharArrayIterator(char[] array) {
this.array = array;
}
public CharArrayIterator(String src) {
this(src.toCharArray());
}
@Override
public char first() {
pos = 0;
if (array.length != 0) {
return array[pos];
}
return DONE;
}
@Override
public char last() {
pos = array.length;
if (array.length != 0) {
pos -= 1;
return array[pos];
}
return DONE;
}
@Override
public char current() {
if (array.length != 0 && pos < array.length) {
return array[pos];
}
return DONE;
}
@Override
public char next() {
pos += 1;
if (pos >= array.length) {
pos = array.length;
return DONE;
}
return current();
}
@Override
public char previous() {
if (pos == 0) {
return DONE;
}
pos -= 1;
return current();
}
@Override
public char setIndex(int position) {
if (position < 0 || position > array.length) {
throw new IllegalArgumentException("bad position: " + position);
}
pos = position;
if (pos != array.length && array.length != 0) {
return array[pos];
}
return DONE;
}
@Override
public int getBeginIndex() {
return 0;
}
@Override
public int getEndIndex() {
return array.length;
}
@Override
public int getIndex() {
return pos;
}
// @SuppressWarnings("all") Just STFU, this _is_ terrific
// SonarLint: "clone" should not be overridden (java:S2975)
// And I wouldn't have done that if only CharacterIterator had not required exception safety.
// SonarLint: "toString()" and "clone()" methods should not return null (java:S2225)
// The clause is unreachable: CharacterArrayIterator implements Cloneable and superclass is Object.
@SuppressWarnings({"squid:S2975", "squid:S2225"})
@Override
public CharArrayIterator clone() {
try {
return (CharArrayIterator) super.clone();
} catch (CloneNotSupportedException cnse) {
// Impossible
return null;
}
}
}

View File

@ -0,0 +1,42 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars;
import java.util.function.IntConsumer;
@FunctionalInterface
public interface CharConsumer {
void accept(char c);
public static CharConsumer andThen(CharConsumer first, CharConsumer second) {
return c -> {
first.accept(c);
second.accept(c);
};
}
public static IntConsumer toInt(CharConsumer consumer) {
return i -> consumer.accept((char) i);
}
public static CharConsumer toChar(IntConsumer consumer) {
return consumer::accept;
}
}

View File

@ -0,0 +1,69 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars;
import java.util.Objects;
import ru.windcorp.jputil.ArrayUtil;
/**
* @author Javapony
*
*/
public class CharConsumers {
private CharConsumers() {}
public static CharConsumer fillArray(char[] array, int offset, int length) {
return new ArrayFiller(array, offset, length);
}
public static CharConsumer fillArray(char[] array) {
return fillArray(array, 0, -1);
}
private static class ArrayFiller implements CharConsumer {
final char[] array;
int i;
final int end;
/**
* @param array
* @param offset
* @param length
*/
ArrayFiller(char[] array, int offset, int length) {
this.array = Objects.requireNonNull(array, "array");
this.end = ArrayUtil.checkArrayStartEnd(array, offset, offset + length);
this.i = offset;
}
/**
* @see ru.windcorp.jputil.chars.CharConsumer#accept(char)
*/
@Override
public void accept(char c) {
if (i == end)
throw new ArrayIndexOutOfBoundsException(end);
array[i++] = c;
}
}
}

View File

@ -0,0 +1,84 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars;
import java.util.Arrays;
import java.util.function.IntPredicate;
import ru.windcorp.jputil.ArrayUtil;
@FunctionalInterface
public interface CharPredicate {
boolean test(char c);
public static CharPredicate and(CharPredicate first, CharPredicate second) {
return c -> first.test(c) && second.test(c);
}
public static CharPredicate or(CharPredicate first, CharPredicate second) {
return c -> first.test(c) || second.test(c);
}
public static CharPredicate negate(CharPredicate predicate) {
return c -> !predicate.test(c);
}
public static IntPredicate toInt(CharPredicate predicate) {
return i -> predicate.test((char) i);
}
public static CharPredicate toChar(IntPredicate predicate) {
return predicate::test;
}
public static CharPredicate forArray(char... chars) {
if (chars.length == 0) {
return c -> false;
}
if (chars.length == 1) {
return forChar(chars[0]);
}
if (chars.length < 16) {
return c -> ArrayUtil.firstIndexOf(chars, c) >= 0;
} else {
final char[] sorted = Arrays.copyOf(chars, chars.length);
Arrays.sort(sorted);
return c -> Arrays.binarySearch(chars, c) >= 0;
}
}
public static CharPredicate forChar(final char c) {
return given -> given == c;
}
public static CharPredicate forRange(final char minInclusive, final char maxExclusive) {
if (minInclusive > maxExclusive) {
throw new IllegalArgumentException("min > max: " + minInclusive + " > " + maxExclusive);
}
if (minInclusive == maxExclusive) {
return c -> false;
}
return c -> c >= minInclusive && c < maxExclusive;
}
}

View File

@ -0,0 +1,35 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars;
import java.util.function.IntSupplier;
@FunctionalInterface
public interface CharSupplier {
char getAsChar();
public static IntSupplier toInt(CharSupplier consumer) {
return consumer::getAsChar;
}
public static CharSupplier toChar(IntSupplier consumer) {
return () -> (char) consumer.getAsInt();
}
}

View File

@ -0,0 +1,44 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars;
public class EscapeException extends Exception {
private static final long serialVersionUID = -3647188859290365053L;
public EscapeException() {
super();
}
public EscapeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public EscapeException(String message, Throwable cause) {
super(message, cause);
}
public EscapeException(String message) {
super(message);
}
public EscapeException(Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,474 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars;
import java.text.CharacterIterator;
import ru.windcorp.jputil.ArrayUtil;
import ru.windcorp.jputil.chars.reader.CharReader;
import ru.windcorp.jputil.chars.reader.CharReaders;
public class Escaper {
public static class EscaperBuilder {
private char escapeChar = '\\';
private char unicodeEscapeChar = 'u';
private char[] safes = null;
private char[] unsafes = null;
private boolean preferUnicode = false;
private boolean strict = true;
public EscaperBuilder withEscapeChar(char escapeChar) {
this.escapeChar = escapeChar;
return this;
}
public EscaperBuilder withUnicodeEscapeChar(char unicodeEscapeChar) {
this.unicodeEscapeChar = unicodeEscapeChar;
return this;
}
public EscaperBuilder withChars(char[] safes, char[] unsafes) {
this.safes = safes;
this.unsafes = unsafes;
return this;
}
public EscaperBuilder withChars(String safes, String unsafes) {
this.safes = safes.toCharArray();
this.unsafes = unsafes.toCharArray();
return this;
}
public EscaperBuilder withChars(char[] chars) {
this.safes = this.unsafes = chars;
return this;
}
public EscaperBuilder withChars(String chars) {
this.safes = this.unsafes = chars.toCharArray();
return this;
}
public EscaperBuilder withSafes(char[] safes) {
this.safes = safes;
return this;
}
public EscaperBuilder withSafes(String safes) {
this.safes = safes.toCharArray();
return this;
}
public EscaperBuilder withUnsafes(char[] unsafes) {
this.unsafes = unsafes;
return this;
}
public EscaperBuilder withUnsafes(String unsafes) {
this.unsafes = unsafes.toCharArray();
return this;
}
public EscaperBuilder preferUnicode(boolean preferUnicode) {
this.preferUnicode = preferUnicode;
return this;
}
public EscaperBuilder strict(boolean strict) {
this.strict = strict;
return this;
}
public Escaper build() {
return new Escaper(escapeChar, unicodeEscapeChar, safes, unsafes, preferUnicode, strict);
}
}
public static final Escaper JAVA = new Escaper('\\', 'u', "tbnrf'\"".toCharArray(), "\t\b\n\r\f\'\"".toCharArray(), true, true);
private final char escapeChar;
private final char unicodeEscapeChar;
private final char[] safes;
private final char[] unsafes;
private final boolean preferUnicode;
private final boolean strict;
protected Escaper(
char escapeChar, char unicodeEscapeChar,
char[] safes, char[] unsafes,
boolean preferUnicode, boolean strict) {
this.escapeChar = escapeChar;
this.unicodeEscapeChar = unicodeEscapeChar;
this.safes = safes;
this.unsafes = unsafes;
this.preferUnicode = preferUnicode;
this.strict = strict;
int duplicate;
if ((duplicate = ArrayUtil.hasDuplicates(safes)) != -1)
throw new IllegalArgumentException("Duplicate safe character '" + safes[duplicate] + "'");
if ((duplicate = ArrayUtil.hasDuplicates(unsafes)) != -1)
throw new IllegalArgumentException("Duplicate unsafe character '" + unsafes[duplicate] + "'");
for (char c : safes) {
if (c == escapeChar) throw new IllegalArgumentException("Safe characters contain escape chatacter");
if (c == unicodeEscapeChar) throw new IllegalArgumentException("Safe characters contain Unicode escape chatacter");
}
for (char c : unsafes) {
if (c == escapeChar) throw new IllegalArgumentException("Unsafe characters contain escape chatacter (escape character is escaped automatically)");
if (c == unicodeEscapeChar) throw new IllegalArgumentException("Unsafe characters contain Unicode escape chatacter");
}
}
public static EscaperBuilder create() {
return new EscaperBuilder();
}
/*
* Logic - escape
*/
public void escape(CharReader src, int length, CharPredicate until, CharConsumer output) {
int end;
if (length < 0) end = Integer.MAX_VALUE;
else end = src.getPosition() + length;
while (src.has() &&
src.getPosition() < end &&
(until == null || !until.test(src.current())))
escape(src.consume(), output);
}
public void escape(char c, CharConsumer output) {
if (c == escapeChar) {
output.accept(escapeChar);
output.accept(escapeChar);
return;
}
int index = ArrayUtil.firstIndexOf(unsafes, c);
if (index >= 0) {
output.accept(escapeChar);
output.accept(safes[index]);
} else {
if (preferUnicode && !isRegular(c)) {
escapeAsHex(c, output);
} else {
output.accept(c);
}
}
}
// SonarLint: Assignments should not be made from within sub-expressions (java:S1121)
// Seems self-evident enough
@SuppressWarnings("squid:S1121")
private void escapeAsHex(char c, CharConsumer output) {
output.accept(escapeChar);
output.accept(unicodeEscapeChar);
output.accept(StringUtil.hexDigit(c >>= (4 * 3)));
output.accept(StringUtil.hexDigit(c >>= (4 * 2)));
output.accept(StringUtil.hexDigit(c >>= (4 * 1)));
output.accept(StringUtil.hexDigit(c >> (4 * 0)));
}
public int getEscapedLength(CharReader src, int length, CharPredicate until) {
int end;
if (length < 0) end = Integer.MAX_VALUE;
else end = src.getPosition() + length;
int result = 0;
while (src.has() &&
src.getPosition() < end &&
(until == null || !until.test(src.current()))) {
result += getEscapedLength(src.consume());
}
return result;
}
public int getEscapedLength(char c) {
if (c == escapeChar || ArrayUtil.firstIndexOf(unsafes, c) >= 0)
return 2;
else {
if (preferUnicode && !isRegular(c))
return 6;
else
return 1;
}
}
/*
* Logic - unescape
*/
public void unescape(CharReader src, int length, CharPredicate until, CharConsumer output) throws EscapeException {
int end;
if (length < 0) end = Integer.MAX_VALUE;
else end = src.getPosition() + length;
while (src.has() &&
src.getPosition() < end &&
(until == null || !until.test(src.current()))) {
output.accept(unescapeOneSequence(src));
}
}
public char unescapeOneSequence(CharReader src) throws EscapeException {
int resetPos = src.getPosition();
try {
if (src.current() == escapeChar) {
src.next();
if (src.isEnd())
throw new EscapeException("Incomplete escape sequence at the end");
if (src.current() == escapeChar) {
src.next();
return escapeChar;
}
if (src.current() == unicodeEscapeChar) {
src.next();
return (char) (
hexValue(src.consume()) << (4 * 3) |
hexValue(src.consume()) << (4 * 2) |
hexValue(src.consume()) << (4 * 1) |
hexValue(src.consume()) << (4 * 0)
);
}
int index = ArrayUtil.firstIndexOf(safes, src.current());
if (index >= 0) {
src.next();
return unsafes[index];
}
if (strict)
throw new EscapeException("Unknown escape sequence \"" + escapeChar + src.current() + "\"");
else
return src.consume();
} else
return src.consume();
} catch (EscapeException | RuntimeException e) {
src.setPosition(resetPos);
throw e;
}
}
public int getUnescapedLength(CharReader src, int length, CharPredicate until) {
int end;
if (length < 0) end = Integer.MAX_VALUE;
else end = src.getPosition() + length;
int result = 0;
while (src.has() &&
src.getPosition() < end &&
(until == null || !until.test(src.current()))) {
skipOneSequence(src);
result++;
}
return result;
}
public void skipOneSequence(CharReader src) {
if (
src.current() == escapeChar
&&
src.next() == unicodeEscapeChar
) {
src.advance(4);
}
src.next();
}
/*
* Utility
*/
public void escape(CharReader src, int length, CharConsumer output) {
escape(src, length, null, output);
}
public void escape(CharReader src, CharPredicate until, CharConsumer output) {
escape(src, -1, until, output);
}
public void escape(CharReader src, CharConsumer output) {
escape(src, -1, null, output);
}
public int getEscapedLength(CharReader src, int length) {
return getEscapedLength(src, length, null);
}
public int getEscapedLength(CharReader src, CharPredicate until) {
return getEscapedLength(src, -1, until);
}
public int getEscapedLength(CharReader src) {
return getEscapedLength(src, -1, null);
}
public char[] escape(CharReader src, int length, CharPredicate until) {
src.mark();
char[] result = new char[getEscapedLength(src, length, until)];
src.reset();
escape(src, length, until, CharConsumers.fillArray(result));
return result;
}
public char[] escape(CharReader src, int length) {
return escape(src, length, (CharPredicate) null);
}
public char[] escape(CharReader src, CharPredicate until) {
return escape(src, -1, until);
}
public char[] escape(CharReader src) {
return escape(src, -1, (CharPredicate) null);
}
public void unescape(CharReader src, int length, CharConsumer output) throws EscapeException {
unescape(src, length, null, output);
}
public void unescape(CharReader src, CharPredicate until, CharConsumer output) throws EscapeException {
unescape(src, -1, until, output);
}
public void unescape(CharReader src, CharConsumer output) throws EscapeException {
unescape(src, -1, null, output);
}
public int getUnescapedLength(CharReader src, int length) {
return getUnescapedLength(src, length, null);
}
public int getUnescapedLength(CharReader src, CharPredicate until) {
return getUnescapedLength(src, -1, until);
}
public int getUnescapedLength(CharReader src) {
return getUnescapedLength(src, -1, null);
}
public char[] unescape(CharReader src, int length, CharPredicate until) throws EscapeException {
src.mark();
char[] result = new char[getUnescapedLength(src, length, until)];
src.reset();
unescape(src, length, until, CharConsumers.fillArray(result));
return result;
}
public char[] unescape(CharReader src, int length) throws EscapeException {
return unescape(src, length, (CharPredicate) null);
}
public char[] unescape(CharReader src, CharPredicate until) throws EscapeException {
return unescape(src, -1, until);
}
public char[] unescape(CharReader src) throws EscapeException {
return unescape(src, -1, (CharPredicate) null);
}
@Deprecated()
public char[] unescape(CharacterIterator src, char until) throws EscapeException {
int index = src.getIndex();
CharReader reader = CharReaders.wrap(src);
char[] result = unescape(reader, -1, CharPredicate.forChar(until));
src.setIndex(index + reader.getPosition());
return result;
}
public String escape(String src) {
StringBuilder result = new StringBuilder(src.length());
escape(CharReaders.wrap(src), (CharConsumer) result::append);
return result.toString();
}
public String unescape(String src) throws EscapeException {
StringBuilder result = new StringBuilder(src.length());
unescape(CharReaders.wrap(src), (CharConsumer) result::append);
return result.toString();
}
/*
* Misc
*/
private static int hexValue(char c) throws EscapeException {
if (c < '0') throw thisIsNotAHexDigit(c);
if (c <= '9') return c - '0';
if (c < 'A') throw thisIsNotAHexDigit(c);
if (c <= 'F') return c - 'A';
if (c < 'a') throw thisIsNotAHexDigit(c);
if (c <= 'f') return c - 'a';
if (c == CharReader.DONE) throw new EscapeException("Incomplete Unicode escape sequence at the end");
throw thisIsNotAHexDigit(c);
}
private static EscapeException thisIsNotAHexDigit(char c) {
return new EscapeException("Invalid hex digit '" + c + "', expected [0-9A-Fa-f]");
}
protected static boolean isRegular(char c) {
return c >= ' ' && c <= '~';
}
/*
* Getters / setters
*/
public char getEscapeChar() {
return escapeChar;
}
public char getUnicodeEscapeChar() {
return unicodeEscapeChar;
}
public char[] getSafes() {
return safes;
}
public char[] getUnsafes() {
return unsafes;
}
public boolean isPreferUnicode() {
return preferUnicode;
}
public boolean isStrict() {
return strict;
}
}

View File

@ -0,0 +1,102 @@
/*
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
package ru.windcorp.jputil.chars;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
public class FancyCharacterIterator implements CharacterIterator {
private final StringCharacterIterator obj;
private final String data;
public FancyCharacterIterator(String data) {
this.obj = new StringCharacterIterator(data);
this.data = data;
}
@Override
public char first() {
return obj.first();
}
@Override
public char last() {
return obj.last();
}
@Override
public char setIndex(int p) {
return obj.setIndex(p);
}
@Override
public char current() {
return obj.current();
}
@Override
public char next() {
return obj.next();
}
@Override
public char previous() {
return obj.previous();
}
@Override
public int getBeginIndex() {
return obj.getBeginIndex();
}
@Override
public int getEndIndex() {
return obj.getEndIndex();
}
@Override
public int getIndex() {
return obj.getIndex();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("\"");
sb.append(data);
sb.append("\"\n ");
for (int i = 0; i < obj.getIndex(); ++i) sb.append(' ');
sb.append("^ Here.");
return sb.toString();
}
// @SuppressWarnings("all") Just STFU, this _is_ terrific
// SonarLint: "clone" should not be overridden (java:S2975)
// And I wouldn't have done that if only CharacterIterator had not required exception safety.
// SonarLint: "toString()" and "clone()" methods should not return null (java:S2225)
// The clause is unreachable: CharacterArrayIterator implements Cloneable and superclass is Object.
@SuppressWarnings({"squid:S2975", "squid:S2225"})
@Override
public FancyCharacterIterator clone() {
try {
return (FancyCharacterIterator) super.clone();
} catch (CloneNotSupportedException cnse) {
// Impossible
return null;
}
}
}

View File

@ -0,0 +1,135 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars;
public class IndentedStringBuilder {
private final StringBuilder sb = new StringBuilder();
private int indentLevel = 0;
private boolean indentApplied = false;
private String[] indentCache = new String[16];
private String indent = "";
private final char[] indentFill;
public IndentedStringBuilder(char[] indentFill) {
this.indentFill = indentFill;
}
public IndentedStringBuilder(String indentFill) {
this(indentFill.toCharArray());
}
public IndentedStringBuilder(char indentChar, int length) {
this(StringUtil.sequence(indentChar, length));
}
public IndentedStringBuilder() {
this(new char[] {' '});
}
@Override
public String toString() {
return sb.toString();
}
public int getIndentLevel() {
return indentLevel;
}
public void setIndentLevel(int level) {
this.indentLevel = level;
updateIndent();
}
public char[] getIndentFill() {
return indentFill;
}
protected void updateIndent() {
if (indentLevel < indentCache.length) {
indent = indentCache[indentLevel];
if (indent != null) return;
}
char[] fill = getIndentFill();
char[] array = new char[fill.length * getIndentLevel()];
for (int i = 0; i < array.length; i += fill.length)
System.arraycopy(fill, 0, array, i, fill.length);
indent = new String(array);
if (indentLevel < indentCache.length) {
indentCache[indentLevel] = indent;
}
}
public IndentedStringBuilder indent() {
setIndentLevel(getIndentLevel() + 1);
return this;
}
public IndentedStringBuilder unindent() {
setIndentLevel(getIndentLevel() - 1);
return this;
}
public IndentedStringBuilder append(Object x) {
if (x == null) {
appendRaw("null");
return this;
}
String str = x.toString();
int newLines = StringUtil.count(str, '\n');
if (newLines == 0) {
appendRaw(str);
return this;
}
String[] lines = StringUtil.split(str, '\n', newLines + 1);
appendRaw(lines[0]);
for (int i = 1; i < lines.length; ++i) {
newLine();
appendRaw(lines[i]);
}
return this;
}
public IndentedStringBuilder appendRaw(String str) {
if (str.isEmpty()) return this; // Do not append indent
if (!indentApplied) {
sb.append(indent);
indentApplied = true;
}
sb.append(str);
return this;
}
public IndentedStringBuilder newLine() {
sb.append('\n');
indentApplied = false;
return this;
}
}

View File

@ -0,0 +1,778 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.function.IntFunction;
public class StringUtil {
private StringUtil() {}
private static final String NULL_PLACEHOLDER = "[null]";
private static final String EMPTY_PLACEHOLDER = "[empty]";
private static final String DEFAULT_SEPARATOR = "; ";
public static <T> String arrayToString(
T[] array,
String separator,
String empty,
String nullPlaceholder,
String nullArray
) {
if (separator == null) {
throw new IllegalArgumentException(new NullPointerException());
}
if (array == null) {
return nullArray;
}
if (array.length == 0) {
return empty;
}
StringBuilder sb = new StringBuilder(array[0] == null ? nullPlaceholder : array[0].toString());
for (int i = 1; i < array.length; ++i) {
sb.append(separator);
sb.append(array[i] == null ? nullPlaceholder : array[i].toString());
}
return sb.toString();
}
public static <T> String arrayToString(T[] array, String separator) {
return arrayToString(array, separator, EMPTY_PLACEHOLDER, NULL_PLACEHOLDER, "[null array]");
}
public static <T> String arrayToString(T[] array) {
return arrayToString(array, DEFAULT_SEPARATOR);
}
public static String iteratorToString(
Iterator<?> iterator,
String separator,
String empty,
String nullPlaceholder,
String nullIterator
) {
if (separator == null) {
throw new IllegalArgumentException(new NullPointerException());
}
if (iterator == null) {
return nullIterator;
}
if (!iterator.hasNext()) {
return empty;
}
Object obj = iterator.next();
StringBuilder sb = new StringBuilder(obj == null ? nullPlaceholder : obj.toString());
while (iterator.hasNext()) {
obj = iterator.next();
sb.append(separator);
sb.append(obj == null ? nullPlaceholder : obj.toString());
}
return sb.toString();
}
public static String iteratorToString(Iterator<?> iterator, String separator) {
return iteratorToString(iterator, separator, EMPTY_PLACEHOLDER, NULL_PLACEHOLDER, "[null iterator]");
}
public static String iteratorToString(Iterator<?> iterator) {
return iteratorToString(iterator, DEFAULT_SEPARATOR);
}
public static String iterableToString(
Iterable<?> iterable,
String separator,
String empty,
String nullPlaceholder,
String nullIterable
) {
if (separator == null) {
throw new IllegalArgumentException(new NullPointerException());
}
if (iterable == null) {
return nullIterable;
}
return iteratorToString(iterable.iterator(), separator, empty, nullPlaceholder, nullIterable);
}
public static String iterableToString(Iterable<?> iterable, String separator) {
return iterableToString(iterable, separator, EMPTY_PLACEHOLDER, NULL_PLACEHOLDER, "[null iterable]");
}
public static String iterableToString(Iterable<?> iterable) {
return iterableToString(iterable, DEFAULT_SEPARATOR);
}
public static <T> String supplierToString(
IntFunction<T> supplier,
int length,
String separator,
String empty,
String nullPlaceholder,
String nullSupplier
) {
if (separator == null) throw new IllegalArgumentException(new NullPointerException());
if (supplier == null) return nullSupplier;
if (length == 0) return empty;
if (length > 0) {
return supplierToStringExactly(
supplier,
length,
separator,
nullPlaceholder
);
} else {
return supplierToStringUntilNull(
supplier,
separator,
empty
);
}
}
private static <T> String supplierToStringExactly(
IntFunction<T> supplier,
int length,
String separator,
String nullPlaceholder
) {
T element = supplier.apply(0);
StringBuilder sb = new StringBuilder(element == null ? nullPlaceholder : element.toString());
for (int i = 1; i < length; ++i) {
sb.append(separator);
element = supplier.apply(i);
sb.append(element == null ? nullPlaceholder : element.toString());
}
return sb.toString();
}
private static <T> String supplierToStringUntilNull(
IntFunction<T> supplier,
String separator,
String empty
) {
T element = supplier.apply(0);
if (element == null) {
return empty;
}
StringBuilder sb = new StringBuilder(element.toString());
int i = 0;
while ((element = supplier.apply(i++)) != null) {
sb.append(separator);
sb.append(element);
}
return sb.toString();
}
public static String supplierToString(IntFunction<?> supplier, int length, String separator) {
return supplierToString(supplier, length, separator, EMPTY_PLACEHOLDER, NULL_PLACEHOLDER, "[null supplier]");
}
public static String supplierToString(IntFunction<?> supplier, String separator) {
return supplierToString(supplier, -1, separator, EMPTY_PLACEHOLDER, NULL_PLACEHOLDER, "[null supplier]");
}
public static String supplierToString(IntFunction<?> supplier, int length) {
return supplierToString(supplier, length, DEFAULT_SEPARATOR);
}
public static String supplierToString(IntFunction<?> supplier) {
return supplierToString(supplier, -1, DEFAULT_SEPARATOR);
}
public static byte[] toJavaByteArray(String str) {
char[] chars = str.toCharArray();
byte[] bytes = new byte[chars.length];
for (int i = 0; i < bytes.length; ++i) {
bytes[i] = (byte) chars[i];
}
return bytes;
}
public static int count(String src, char target) {
int i = 0;
for (char c : src.toCharArray()) {
if (c == target) {
++i;
}
}
return i;
}
public static String[] split(String src, char separator) {
return split(src, separator, count(src, separator) + 1);
}
public static String[] split(String src, char separator, int arrayLength) {
if (arrayLength < 0) throw illegalArrayLength(arrayLength);
else if (arrayLength == 0) return new String[0];
else if (arrayLength == 1) return new String[] { src };
String[] result = new String[arrayLength];
int resultIndex = 0;
StringBuilder sb = new StringBuilder();
for (char c : src.toCharArray()) {
if (c == separator && (resultIndex + 1) < arrayLength) {
result[resultIndex] = resetStringBuilder(sb);
++resultIndex;
} else {
sb.append(c);
}
}
result[resultIndex] = sb.toString();
return result;
}
public static int count(String src, char... target) {
int i = 0;
for (char c : src.toCharArray()) {
for (char t : target) {
if (c == t) {
++i;
break;
}
}
}
return i;
}
public static String[] split(String src, char... separator) {
return split(src, count(src, separator) + 1, separator);
}
public static String[] split(String src, int arrayLength, char... separator) {
if (arrayLength < 0) throw illegalArrayLength(arrayLength);
else if (arrayLength == 0) return new String[0];
else if (arrayLength == 1) return new String[] { src };
String[] result = new String[arrayLength];
int resultIndex = 0;
StringBuilder sb = new StringBuilder();
charLoop:
for (char c : src.toCharArray()) {
if ((resultIndex + 1) < arrayLength) {
for (char h : separator) {
if (c == h) {
result[resultIndex] = resetStringBuilder(sb);
++resultIndex;
continue charLoop;
}
}
}
sb.append(c);
}
result[resultIndex] = sb.toString();
return result;
}
public static int count(String src, CharPredicate test) {
int i = 0;
for (char c : src.toCharArray()) {
if (test.test(c)) i++;
}
return i;
}
public static String[] split(String src, CharPredicate test) {
return split(src, count(src, test) + 1, test);
}
public static String[] split(String src, int arrayLength, CharPredicate test) {
if (arrayLength < 0) throw illegalArrayLength(arrayLength);
else if (arrayLength == 0) return new String[0];
else if (arrayLength == 1) return new String[] { src };
String[] result = new String[arrayLength];
int resultIndex = 0;
StringBuilder sb = new StringBuilder();
charLoop:
for (char c : src.toCharArray()) {
if (
(resultIndex + 1) < arrayLength
&&
test.test(c)
) {
result[resultIndex] = resetStringBuilder(sb);
++resultIndex;
continue charLoop;
}
sb.append(c);
}
result[resultIndex] = sb.toString();
return result;
}
private static IllegalArgumentException illegalArrayLength(int length) {
return new IllegalArgumentException("arrayLength must be non-negative (" + length + ")");
}
public static String remove(String src, char... remove) {
char[] result = new char[src.length() - count(src, remove)];
char current;
int resultIndex = 0;
mainLoop:
for (int srcIndex = 0; srcIndex < src.length(); ++srcIndex) {
current = src.charAt(srcIndex);
for (char c : remove) {
if (current == c) {
continue mainLoop;
}
}
result[resultIndex++] = current;
}
return new String(result);
}
public static String resetStringBuilder(StringBuilder sb) {
String result = sb.toString();
sb.setLength(0);
sb.ensureCapacity(10);
return result;
}
public static String readToString(InputStream is, Charset encoding, int bufferSize) throws IOException {
char[] buffer = new char[bufferSize];
StringBuilder result = new StringBuilder();
Reader reader = new InputStreamReader(is, encoding);
while (true) {
int readChars = reader.read(buffer, 0, buffer.length);
if (readChars == -1) {
break;
}
result.append(buffer, 0, readChars);
}
return result.toString();
}
public static boolean equalsPart(char[] a, char[] b, int beginPos, int endPos) {
if (beginPos < 0) {
throw new IllegalArgumentException("beginPos must be non-negative (" + beginPos + ")");
}
if (endPos < beginPos) {
throw new IllegalArgumentException("endPos must be greater than or equal to beginPos (endPos="
+ endPos + ", beginPos=" + beginPos + ")");
}
if (endPos >= Math.min(a.length, b.length)) {
return false; // At least one of the arrays does not contain at least one of the required elements
}
for (int i = beginPos; i < endPos; ++i) {
if (a[i] != b[i]) {
return false;
}
}
return true;
}
// Java 8 is for pussies
public static char[] join(char[]... srcs) {
int tmp = 0;
for (int i = 0; i < srcs.length; ++i) {
tmp += srcs[i].length;
}
char[] result = new char[tmp];
tmp = 0;
for (int i = 0; i < srcs.length; ++i) {
System.arraycopy(srcs[i], 0, result, tmp, srcs[i].length);
tmp += srcs[i].length;
}
return result;
}
/**
* Finds and returns the index of the specified appearance of the specified character
* in the given array. The search starts at index 0.<p>
* Examples:<p>
* <table border="1">
* <tr>
* <th align="center"><code>src</code></th>
* <th align="center"><code>target</code></th>
* <th align="center"><code>skip</code></th>
* <th align="center">returns</th>
* </tr>
* <tr align="center"><td><code>a<u>.</u>b.c</code></td><td><code>'.'</code></td><td><code>0</code></td><td><code>1</code></td></tr>
* <tr align="center"><td><code>a.b<u>.</u>c</code></td><td><code>'.'</code></td><td><code>1</code></td><td><code>3</code></td></tr>
* <tr align="center"><td><code>a.b.c</code></td><td><code>'.'</code></td><td><code>2</code></td><td><code>-1</code></td></tr>
* <tr align="center"><td><code>a.b.c</code></td><td><code>'d'</code></td><td><i>any</i></td><td><code>-1</code></td></tr>
* </table>
* @param src - the array to search in.
* @param target - the character to search for.
* @param skip - the amount of <code>target</code> characters to be skipped.
* @return The index of the <code>skip+1</code>th <code>target</code> character or -1, if none found.
* @see StringUtil#indexFromEnd(char[], char, int)
*/
public static int indexFromBeginning(char[] src, char target, int skip) {
for (int i = 0; i < src.length; ++i) {
if (src[i] == target) {
if (skip == 0) {
return i;
}
--skip;
}
}
return -1;
}
/**
* Finds and returns the index of the specified appearance of the specified character
* in the given array. The search starts at index <code>src.length - 1</code>.<p>
* Examples:<p>
* <table border="1">
* <tr>
* <th align="center"><code>src</code></th>
* <th align="center"><code>target</code></th>
* <th align="center"><code>skip</code></th>
* <th align="center">returns</th>
* </tr>
* <tr align="center"><td><code>a.b<u>.</u>c</code></td><td><code>'.'</code></td><td><code>0</code></td><td><code>3</code></td></tr>
* <tr align="center"><td><code>a<u>.</u>b.c</code></td><td><code>'.'</code></td><td><code>1</code></td><td><code>1</code></td></tr>
* <tr align="center"><td><code>a.b.c</code></td><td><code>'.'</code></td><td><code>2</code></td><td><code>-1</code></td></tr>
* <tr align="center"><td><code>a.b.c</code></td><td><code>'d'</code></td><td><i>any</i></td><td><code>-1</code></td></tr>
* </table>
* @param src - the array to search in.
* @param target - the character to search for.
* @param skip - the amount of <code>target</code> characters to be skipped.
* @return The index of the <code>skip+1</code>th <code>target</code>character
* from the end of the array or -1, if none found.
* @see StringUtil#indexFromBeginning(char[], char, int)
*/
public static int indexFromEnd(char[] src, char target, int skip) {
for (int i = src.length - 1; i >= 0; --i) {
if (src[i] == target) {
if (skip == 0) {
return i;
}
--skip;
}
}
return -1;
}
public static String padToLeft(String src, int length, char c) {
if (length <= 0) {
throw new IllegalArgumentException("length must be positive (" + length + ")");
}
if (length <= src.length()) {
return src;
}
char[] result = new char[length];
int i = 0;
for (; i < src.length(); ++i) {
result[i] = src.charAt(i);
}
for (; i < length; ++i) {
result[i] = c;
}
return new String(result);
}
public static String padToLeft(String src, int length) {
return padToLeft(src, length, ' ');
}
public static String padToRight(String src, int length, char c) {
if (length <= 0) {
throw new IllegalArgumentException("length must be positive (" + length + ")");
}
if (length <= src.length()) {
return src;
}
char[] result = new char[length];
int i = 0;
int srcLength = src.length();
for (; i < length - srcLength; ++i) {
result[i] = c;
}
for (; i < length; ++i) {
result[i] = src.charAt(i - (length - srcLength));
}
return new String(result);
}
public static String padToRight(String src, int length) {
return padToRight(src, length, ' ');
}
public static int countWords(String src) {
int i = 0;
boolean isWord = false;
for (char c : src.toCharArray()) {
if (Character.isWhitespace(c)) {
if (isWord) {
isWord = false;
i++;
}
} else {
isWord = true;
}
}
if (isWord) {
i++;
}
return i;
}
public static String[] splitWords(String src) {
String[] result = new String[countWords(src)];
int i = 0;
StringBuilder sb = new StringBuilder();
for (char c : src.toCharArray()) {
if (Character.isWhitespace(c)) {
if (sb.length() != 0) {
result[i++] = resetStringBuilder(sb);
}
} else {
sb.append(c);
}
}
if (sb.length() != 0) {
result[i] = resetStringBuilder(sb);
}
return result;
}
public static char[] sequence(char c, int length) {
char[] result = new char[length];
Arrays.fill(result, c);
return result;
}
public static String stripPrefix(String string, String prefix) {
if (prefix != null && string.startsWith(prefix)) {
return string.substring(prefix.length());
}
return string;
}
public static String stripSuffix(String string, String suffix) {
if (suffix != null && string.endsWith(suffix)) {
return string.substring(suffix.length());
}
return string;
}
@SafeVarargs
public static Collection<String> allCombinations(Iterable<String>... parts) {
StringBuilder sb = new StringBuilder();
Collection<String> result = new ArrayList<>();
buildCombinations(sb, result, parts, 0);
return result;
}
private static void buildCombinations(StringBuilder sb, Collection<String> result, Iterable<String>[] parts,
int index) {
if (index >= parts.length) {
result.add(sb.toString());
} else {
int startLength = sb.length();
for (String part : parts[index]) {
sb.append(part);
buildCombinations(sb, result, parts, index + 1);
sb.setLength(startLength);
}
}
}
@SafeVarargs
public static String[] allCombinations(String[]... parts) {
StringBuilder sb = new StringBuilder();
int length = 1;
for (String[] array : parts) length *= array.length;
String[] result = new String[length];
buildCombinations(sb, result, new int[] {0}, parts, 0);
return result;
}
private static void buildCombinations(StringBuilder sb, String[] result, int[] resultIndex, String[][] parts,
int index) {
if (index >= parts.length) {
result[resultIndex[0]++] = sb.toString();
} else {
int startLength = sb.length();
for (String part : parts[index]) {
sb.append(part);
buildCombinations(sb, result, resultIndex, parts, index + 1);
sb.setLength(startLength);
}
}
}
public static String toUnsignedHexString(byte b) {
int unsigned = b;
if (b < 0) {
unsigned += 0x100;
}
char[] chars = new char[2];
chars[0] = Character.forDigit(unsigned >>> 4, 0x10);
chars[1] = Character.forDigit(unsigned & 0x0F, 0x10);
return new String(chars);
}
public static String toUnsignedHexString(byte[] bytes, String separator, int size) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; ++i) {
sb.append(toUnsignedHexString(bytes[i]));
if (i < bytes.length - 1 && ((i + 1) % size == 0)) {
sb.append(separator);
}
}
return sb.toString();
}
public static String toUnsignedHexString(byte[] bytes) {
return toUnsignedHexString(bytes, ", ", 1);
}
public static char[] toFullHex(byte x) {
return toFullHex(x, Byte.BYTES);
}
public static char[] toFullHex(short x) {
return toFullHex(x, Short.BYTES);
}
public static char[] toFullHex(int x) {
return toFullHex(x, Integer.BYTES);
}
public static char[] toFullHex(long x) {
return toFullHex(x, Long.BYTES);
}
private static char[] toFullHex(long x, int bytes) {
final int digits = bytes * 2;
char[] result = new char[digits + 2];
result[0] = '0';
result[1] = 'x';
for (int digit = 0; digit < digits; ++digit) {
result[(digits - digit - 1) + 2] =
hexDigit(x, digit);
}
return result;
}
private static char hexDigit(long value, int digit) {
return hexDigit(
(int) (value >>> (4 * digit))
& 0xF
);
}
public static char hexDigit(int value) {
if (value < 0xA) return (char) ('0' + value);
else return (char) ('A' - 0xA + value);
}
}

View File

@ -0,0 +1,37 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars;
public class UncheckedEscapeException extends RuntimeException {
private static final long serialVersionUID = 5392628641744570926L;
public UncheckedEscapeException(String message, EscapeException cause) {
super(message, cause);
}
public UncheckedEscapeException(EscapeException cause) {
super(cause);
}
@Override
public synchronized EscapeException getCause() {
return (EscapeException) super.getCause();
}
}

View File

@ -0,0 +1,139 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars;
import java.io.IOException;
import java.io.Reader;
import java.nio.CharBuffer;
import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class WordReader implements Iterator<String> {
private final Reader reader;
private char[] wordBuffer = new char[1024];
private final CharBuffer inputBuffer;
private String next = null;
private boolean isExhausted = false;
private IOException lastException = null;
public WordReader(Reader src, int bufferSize) {
this.reader = src;
this.inputBuffer = CharBuffer.allocate(bufferSize);
}
public WordReader(Reader src) {
this(src, 2048);
}
public WordReader(char[] array, int offset, int length) {
this.reader = null;
this.inputBuffer = CharBuffer.wrap(Arrays.copyOfRange(array, offset, length + offset));
}
public WordReader(char[] array) {
this.reader = null;
this.inputBuffer = CharBuffer.wrap(array);
}
public WordReader(String str) {
this(str.toCharArray());
}
@Override
public String next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
String result = next;
next = null;
return result;
}
@Override
public boolean hasNext() {
if (next != null) {
return true;
}
if (isExhausted) {
return false;
}
int length = 0;
char c;
while (true) {
c = nextChar();
if (isExhausted) break;
if (Character.isWhitespace(c)) {
if (length == 0) continue;
else break;
}
if (wordBuffer.length == length) {
char[] newBuf = new char[wordBuffer.length * 2];
System.arraycopy(wordBuffer, 0, newBuf, 0, wordBuffer.length);
wordBuffer = newBuf;
}
wordBuffer[length++] = c;
}
if (length == 0) {
return false;
}
next = new String(wordBuffer, 0, length);
return true;
}
private char nextChar() {
if (!inputBuffer.hasRemaining()) {
if (reader == null) {
isExhausted = true;
return 0;
}
inputBuffer.rewind();
try {
if (reader.read(inputBuffer) == -1) {
isExhausted = true;
}
} catch (IOException e) {
lastException = e;
isExhausted = true;
return 0;
}
}
return inputBuffer.get();
}
public IOException getLastException() {
return lastException;
}
}

View File

@ -0,0 +1,104 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars.reader;
/**
* @author Javapony
*
*/
public abstract class AbstractCharReader implements CharReader {
protected static final int DEFAULT_MARK_STACK_SIZE = 8;
/**
* Current position of this CharReader. The reader maps its input to positions starting from 0.
* Positions that are negative or lower than 0 are invalid. {@link #current()}
* will throw an exception if position is invalid.
*/
protected int position = 0;
private int[] marks = new int[DEFAULT_MARK_STACK_SIZE];
private int nextMark = 0;
protected static int closestGreaterPowerOf2(int x) {
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return x + 1;
}
/**
* @see ru.windcorp.jputil.chars.reader.CharReader#getPosition()
*/
@Override
public int getPosition() {
return position;
}
/**
* @see ru.windcorp.jputil.chars.reader.CharReader#setPosition(int)
*/
@Override
public int setPosition(int position) {
this.position = position;
return position;
}
/**
* @see ru.windcorp.jputil.chars.reader.CharReader#mark()
*/
@Override
public int mark() {
ensureMarksCapacity();
marks[nextMark++] = position;
return position;
}
/**
* @see ru.windcorp.jputil.chars.reader.CharReader#forget()
*/
@Override
public int forget() {
return marks[--nextMark];
}
private void ensureMarksCapacity() {
if (nextMark < marks.length) return;
int[] newMarks = new int[closestGreaterPowerOf2(nextMark)];
System.arraycopy(marks, 0, newMarks, 0, nextMark);
marks = newMarks;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("\"");
mark();
position = 0;
sb.append(getChars());
reset();
sb.append("\"\n ");
for (int i = 0; i < position; ++i) sb.append(' ');
sb.append("^ (pos " + position + ")");
return sb.toString();
}
}

View File

@ -0,0 +1,59 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars.reader;
import java.util.Objects;
import ru.windcorp.jputil.ArrayUtil;
/**
* @author Javapony
*
*/
public class ArrayCharReader extends AbstractCharReader {
private final char[] array;
private final int offset;
private final int length;
public ArrayCharReader(char[] array, int offset, int length) {
this.array = Objects.requireNonNull(array, "array");
this.length = ArrayUtil.checkArrayOffsetLength(array, offset, length);
this.offset = offset;
}
/**
* @see ru.windcorp.jputil.chars.reader.CharReader#current()
*/
@Override
public char current() {
if (position >= length) return DONE;
if (position < 0)
throw new IllegalStateException("Position " + position + " is invalid");
return array[position + offset];
}
/**
* @see ru.windcorp.jputil.chars.reader.CharReader#remaining()
*/
@Override
public int remaining() {
return length - position;
}
}

View File

@ -0,0 +1,122 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars.reader;
/**
* @author Javapony
*
*/
public abstract class BufferedCharReader extends AbstractCharReader {
protected static final int DEFAULT_BUFFER_SIZE = 256;
/**
* Buffer to store data acquired with {@link #pullChars(char[], int, int)}.
* Contains characters for positions <code>[0; bufferNextIndex)</code>.
*/
private char[] buffer = new char[DEFAULT_BUFFER_SIZE];
/**
* The index of the next character.
*/
private int bufferNextIndex = 0;
/**
* Whether this reader has been buffered completely.
*/
private boolean exhausted = false;
/**
* Acquires the next character.
* @return the character or {@link #DONE} if the end of the reader has been reached
*/
protected abstract char pullChar();
/**
* Acquires next characters and stores them in the array.
*
* @param buffer the output array
* @param offset index of the first character
* @param length maximum amount of characters to be pulled
* @return the amount of characters actually pulled
*/
protected int pullChars(char[] buffer, int offset, int length) {
for (int i = 0; i < length; ++i) {
if ((buffer[offset + i] = pullChar()) == DONE) {
return i;
}
}
return length;
}
private int pullChars(int offset, int length) {
if (exhausted || length == 0) return 0;
int pulled = pullChars(buffer, offset, length);
if (pulled != length) {
exhausted = true;
}
return pulled;
}
@Override
public char current() {
if (getPosition() < 0) {
throw new IllegalStateException("Position " + getPosition() + " is invalid");
}
if (getPosition() >= bufferNextIndex) {
if (exhausted) return DONE;
ensureBufferCapacity();
int needToPull = getPosition() - bufferNextIndex + 1;
assert needToPull <= buffer.length : "buffer size not ensured!";
int pulled = pullChars(bufferNextIndex, needToPull);
bufferNextIndex += pulled;
if (exhausted) return DONE;
}
// TODO test the shit out of current()
return buffer[getPosition()];
}
private void ensureBufferCapacity() {
if (getPosition() < buffer.length) return;
char[] newBuffer = new char[closestGreaterPowerOf2(getPosition())];
System.arraycopy(buffer, 0, newBuffer, 0, bufferNextIndex);
buffer = newBuffer;
}
/**
* @see ru.windcorp.jputil.chars.reader.CharReader#remaining()
*/
@Override
public int remaining() {
if (exhausted) {
return Math.max(bufferNextIndex - getPosition(), 0);
}
return super.remaining();
}
}

View File

@ -0,0 +1,270 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars.reader;
import java.io.IOException;
import java.util.Arrays;
import ru.windcorp.jputil.chars.CharPredicate;
import ru.windcorp.jputil.chars.EscapeException;
import ru.windcorp.jputil.chars.Escaper;
/**
* @author Javapony
*
*/
// SonarLint: Constants should not be defined in interfaces (java:S1214)
// DONE is an essential part of the interface
@SuppressWarnings("squid:S1214")
public interface CharReader {
char DONE = '\uFFFF';
char current();
int getPosition();
int setPosition(int position);
default char next() {
return advance(1);
}
default char previous() {
return rollBack(1);
}
default char consume() {
char c = current();
advance(1);
return c;
}
default char advance(int forward) {
setPosition(getPosition() + forward);
return current();
}
default char rollBack(int backward) {
return advance(-backward);
}
default boolean isEnd() {
return current() == DONE;
}
default boolean has() {
return current() != DONE;
}
default boolean is(char c) {
return current() == c;
}
default int getChars(char[] output, int offset, int length) {
for (int i = 0; i < length; ++i) {
if ((output[offset + i] = current()) == DONE) {
return i;
}
next();
}
return length;
}
default int getChars(char[] output) {
return getChars(output, 0, output.length);
}
default char[] getChars(int length) {
char[] result = new char[length];
int from = getChars(result);
if (from != length) Arrays.fill(result, from, length, DONE);
return result;
}
default char[] getChars() {
return getChars(remaining());
}
default String getString(int length) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length && !isEnd(); ++i) sb.append(consume());
return sb.toString();
}
default String getString() {
return getString(Integer.MAX_VALUE);
}
default boolean match(CharSequence seq) {
for (int i = 0; i < seq.length(); ++i) {
if (isEnd()) return false;
if (current() != seq.charAt(i)) return false;
next();
}
return true;
}
default boolean matchOrReset(CharSequence seq) {
mark();
if (match(seq)) {
forget();
return true;
} else {
reset();
return false;
}
}
default boolean match(char[] array) {
for (int i = 0; i < array.length; ++i) {
if (isEnd()) return false;
if (current() != array[i]) return false;
next();
}
return true;
}
default boolean matchOrReset(char[] array) {
mark();
if (match(array)) {
forget();
return true;
} else {
reset();
return false;
}
}
default int skip(CharPredicate condition) {
int i = 0;
while (has() && condition.test(current())) {
i++;
next();
}
return i;
}
default int skipWhitespace() {
return skip(Character::isWhitespace);
}
/**
* Skips to the end of the current line. Both <code>"\n"</code>, <code>"\r"</code>
* and <code>"\r\n"</code> are considered line separators.
* @return the amount of characters in the skipped line
*/
default int skipLine() {
int i = 0;
while (!isEnd()) {
if (current() == '\r') {
if (next() == '\n') {
next();
}
break;
} else if (current() == '\n') {
next();
break;
}
i++;
next();
}
return i;
}
default char[] readWhile(CharPredicate condition) {
return readUntil(CharPredicate.negate(condition));
}
default char[] readUntil(CharPredicate condition) {
mark();
int length = 0;
while (!isEnd() && !condition.test(current())) {
length++;
next();
}
reset();
char[] result = new char[length];
for (int i = 0; i < length; ++i) result[i] = consume();
return result;
}
default char[] readWord() {
skipWhitespace();
return readUntil(Character::isWhitespace);
}
default char[] readWord(Escaper escaper, char quotes) throws EscapeException {
skipWhitespace();
if (current() == quotes) {
return escaper.unescape(this, quotes);
} else {
return readWord();
}
}
default char[] readLine() {
mark();
int length = skipLine();
reset();
char[] result = new char[length];
for (int i = 0; i < result.length; ++i) result[i] = consume();
return result;
}
default int remaining() {
mark();
int result = 0;
while (consume() != DONE) result++;
reset();
return result;
}
int mark();
int forget();
default int reset() {
return setPosition(forget());
}
default IOException getLastException() {
return null;
}
default void resetLastException() {
// Do nothing
}
default boolean hasErrored() {
return getLastException() != null;
}
}

View File

@ -0,0 +1,112 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars.reader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.CharacterIterator;
import java.util.function.IntSupplier;
import ru.windcorp.jputil.chars.CharSupplier;
/**
* @author Javapony
*
*/
public class CharReaders {
private CharReaders() {}
public static CharReader wrap(char[] array, int offset, int length) {
return new ArrayCharReader(array, offset, length);
}
public static CharReader wrap(char[] array) {
return wrap(array, 0, array.length);
}
public static CharReader wrap(String str, int offset, int length) {
return new StringCharReader(str, offset, length);
}
public static CharReader wrap(String str) {
return wrap(str, 0, str.length());
}
public static CharReader wrap(CharSupplier supplier) {
return new BufferedCharReader() {
@Override
protected char pullChar() {
try {
return supplier.getAsChar();
} catch (Exception e) {
return DONE;
}
}
};
}
public static CharReader wrap(IntSupplier supplier) {
return new BufferedCharReader() {
@Override
protected char pullChar() {
try {
int i = supplier.getAsInt();
if (i < 0 || i > Character.MAX_VALUE) {
return DONE;
} else {
return (char) i;
}
} catch (Exception e) {
return DONE;
}
}
};
}
public static CharReader wrap(CharacterIterator it) {
return new BufferedCharReader() {
@Override
protected char pullChar() {
char result = it.current();
it.next();
return result;
}
};
}
public static CharReader wrap(Reader reader) {
return new ReaderCharReader(reader);
}
public static CharReader wrap(InputStream is, Charset charset) {
return wrap(new InputStreamReader(is, charset));
}
public static CharReader wrapDefaultCS(InputStream is) {
return wrap(new InputStreamReader(is));
}
public static CharReader wrapUTF8(InputStream is) {
return wrap(new InputStreamReader(is, StandardCharsets.UTF_8));
}
}

View File

@ -0,0 +1,70 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars.reader;
import java.io.IOException;
import java.io.Reader;
/**
* @author Javapony
*
*/
public class ReaderCharReader extends BufferedCharReader {
private final Reader src;
private IOException lastException = null;
public ReaderCharReader(Reader src) {
this.src = src;
}
/**
* @see ru.windcorp.jputil.chars.reader.BufferedCharReader#pullChar()
*/
@Override
protected char pullChar() {
try {
return (char) src.read(); // Handles DONE correctly
} catch (IOException e) {
lastException = e;
return DONE;
}
}
/**
* @see ru.windcorp.jputil.chars.reader.BufferedCharReader#pullChars(char[], int, int)
*/
@Override
protected int pullChars(char[] buffer, int offset, int length) {
try {
return src.read(buffer, offset, length);
} catch (IOException e) {
lastException = e;
return 0;
}
}
/**
* @return the exception
*/
@Override
public IOException getLastException() {
return lastException;
}
}

View File

@ -0,0 +1,65 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars.reader;
import java.util.Objects;
/**
* @author Javapony
*
*/
public class StringCharReader extends AbstractCharReader {
private final String str;
private final int offset;
private final int length;
public StringCharReader(String str, int offset, int length) {
this.str = Objects.requireNonNull(str, "str");
if (length < 0)
length = str.length();
int end = offset + length;
if (end > str.length() || offset < 0)
throw new IllegalArgumentException("String contains [0; " + str.length() + "), requested [" + offset + "; " + end + ")");
this.offset = offset;
this.length = length;
}
/**
* @see ru.windcorp.jputil.chars.reader.CharReader#current()
*/
@Override
public char current() {
if (position >= length) return DONE;
if (position < 0)
throw new IllegalStateException("Position " + position + " is invalid");
return str.charAt(position + offset);
}
/**
* @see ru.windcorp.jputil.chars.reader.CharReader#remaining()
*/
@Override
public int remaining() {
return length - position;
}
}

View File

@ -0,0 +1,72 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.functions;
import java.util.function.BiConsumer;
@FunctionalInterface
public interface ThrowingBiConsumer<T, U, E extends Exception> {
@FunctionalInterface
public static interface BiConsumerHandler<T, U, E extends Exception> {
void handle(T t, U u, E e);
}
void accept(T t, U u) throws E;
@SuppressWarnings("unchecked")
default BiConsumer<T, U> withHandler(BiConsumerHandler<? super T, ? super U, ? super E> handler) {
return (t, u) -> {
try {
accept(t, u);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
handler.handle(t, u, (E) e);
}
};
}
public static <T, U, E extends Exception> ThrowingBiConsumer<T, U, E> concat(
ThrowingBiConsumer<? super T, ? super U, ? extends E> first,
ThrowingBiConsumer<? super T, ? super U, ? extends E> second) {
return (t, u) -> {
first.accept(t, u);
second.accept(t, u);
};
}
public static <T, U, E extends Exception> ThrowingBiConsumer<T, U, E> concat(
BiConsumer<? super T, ? super U> first,
ThrowingBiConsumer<? super T, ? super U, E> second) {
return (t, u) -> {
first.accept(t, u);
second.accept(t, u);
};
}
public static <T, U, E extends Exception> ThrowingBiConsumer<T, U, E> concat(
ThrowingBiConsumer<? super T, ? super U, E> first,
BiConsumer<? super T, ? super U> second) {
return (t, u) -> {
first.accept(t, u);
second.accept(t, u);
};
}
}

View File

@ -0,0 +1,62 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.functions;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
@FunctionalInterface
public interface ThrowingConsumer<T, E extends Exception> {
void accept(T t) throws E;
@SuppressWarnings("unchecked")
default Consumer<T> withHandler(BiConsumer<? super T, ? super E> handler) {
return t -> {
try {
accept(t);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
handler.accept(t, (E) e);
}
};
}
public static <T, E extends Exception> ThrowingConsumer<T, E> concat(ThrowingConsumer<? super T, ? extends E> first, ThrowingConsumer<? super T, ? extends E> second) {
return t -> {
first.accept(t);
second.accept(t);
};
}
public static <T, E extends Exception> ThrowingConsumer<T, E> concat(Consumer<? super T> first, ThrowingConsumer<? super T, ? extends E> second) {
return t -> {
first.accept(t);
second.accept(t);
};
}
public static <T, E extends Exception> ThrowingConsumer<T, E> concat(ThrowingConsumer<? super T, ? extends E> first, Consumer<? super T> second) {
return t -> {
first.accept(t);
second.accept(t);
};
}
}

View File

@ -0,0 +1,73 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.functions;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;
@FunctionalInterface
public interface ThrowingFunction<T, R, E extends Exception> {
R apply(T t) throws E;
@SuppressWarnings("unchecked")
default Function<T, R> withHandler(BiConsumer<? super T, ? super E> handler, Function<? super T, ? extends R> value) {
return t -> {
try {
return apply(t);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
if (handler != null) handler.accept(t, (E) e);
return value == null ? null : value.apply(t);
}
};
}
default Function<T, R> withHandler(BiConsumer<? super T, ? super E> handler, Supplier<? extends R> value) {
return withHandler(handler, t -> value.get());
}
default Function<T, R> withHandler(BiConsumer<? super T, ? super E> handler, R value) {
return withHandler(handler, t -> value);
}
default Function<T, R> withHandler(BiConsumer<? super T, ? super E> handler) {
return withHandler(handler, (Function<T, R>) null);
}
public static <T, R, I, E extends Exception> ThrowingFunction<T, R, E> compose(
ThrowingFunction<? super T, I, ? extends E> first,
ThrowingFunction<? super I, ? extends R, ? extends E> second) {
return t -> second.apply(first.apply(t));
}
public static <T, R, I, E extends Exception> ThrowingFunction<T, R, E> compose(
Function<? super T, I> first,
ThrowingFunction<? super I, ? extends R, E> second) {
return t -> second.apply(first.apply(t));
}
public static <T, R, I, E extends Exception> ThrowingFunction<T, R, E> compose(
ThrowingFunction<? super T, I, E> first,
Function<? super I, ? extends R> second) {
return t -> second.apply(first.apply(t));
}
}

View File

@ -0,0 +1,64 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.functions;
import java.util.function.Consumer;
@FunctionalInterface
public interface ThrowingRunnable<E extends Exception> {
void run() throws E;
@SuppressWarnings("unchecked")
default Runnable withHandler(Consumer<? super E> handler) {
return () -> {
try {
run();
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
handler.accept((E) e);
}
};
}
public static <E extends Exception> ThrowingRunnable<E> concat(
ThrowingRunnable<? extends E> first,
ThrowingRunnable<? extends E> second
) {
return () -> {
first.run();
second.run();
};
}
public static <E extends Exception> ThrowingRunnable<E> concat(Runnable first, ThrowingRunnable<E> second) {
return () -> {
first.run();
second.run();
};
}
public static <E extends Exception> ThrowingRunnable<E> concat(ThrowingRunnable<E> first, Runnable second) {
return () -> {
first.run();
second.run();
};
}
}

View File

@ -1,6 +1,6 @@
/*******************************************************************************
* Progressia
* Copyright (C) 2020 Wind Corporation
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -15,49 +15,36 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.progressia.common.util;
package ru.windcorp.jputil.functions;
import java.util.function.Consumer;
import com.google.common.base.Throwables;
import java.util.function.Supplier;
@FunctionalInterface
public interface ThrowingRunnable<T extends Throwable> {
public interface ThrowingSupplier<T, E extends Exception> {
void run() throws T;
T get() throws E;
default Runnable withCatcher(
Consumer<T> catcher,
Class<T> throwableClass
) {
@SuppressWarnings("unchecked")
default Supplier<T> withHandler(Consumer<? super E> handler, Supplier<? extends T> value) {
return () -> {
try {
ThrowingRunnable.this.run();
} catch (Throwable t) {
if (t.getClass() == throwableClass) {
catcher.accept(throwableClass.cast(t));
return get();
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
if (handler != null) handler.accept((E) e);
return value == null ? null : value.get();
}
Throwables.throwIfUnchecked(t);
// This should never happen
throw new AssertionError("This should not have been thrown", t);
}
};
}
default Runnable withCatcher(
Consumer<Throwable> catcher
) {
return () -> {
try {
ThrowingRunnable.this.run();
} catch (Throwable t) {
catcher.accept(t);
default Supplier<T> withHandler(Consumer<? super E> handler, T value) {
return withHandler(handler, () -> value);
}
};
default Supplier<T> withHandler(Consumer<? super E> handler) {
return withHandler(handler, (Supplier<T>) null);
}
}

View File

@ -0,0 +1,47 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.iterators;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class ArrayIterator<E> implements Iterator<E> {
private final E[] array;
private int next;
@SafeVarargs
public ArrayIterator(E... array) {
this.array = array;
}
@Override
public boolean hasNext() {
return next < array.length;
}
@Override
public E next() {
try {
return array[next++];
} catch (ArrayIndexOutOfBoundsException e) {
throw new NoSuchElementException();
}
}
}

View File

@ -0,0 +1,61 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.iterators;
import java.util.Iterator;
import java.util.function.Function;
/**
* @author Javapony
*
*/
public class FunctionIterator<T, E> implements Iterator<E> {
private final Iterator<T> parent;
private final Function<T, E> function;
public FunctionIterator(Iterator<T> parent, Function<T, E> function) {
this.parent = parent;
this.function = function;
}
/**
* @see java.util.Iterator#hasNext()
*/
@Override
public boolean hasNext() {
return parent.hasNext();
}
/**
* @see java.util.Iterator#next()
*/
@Override
public E next() {
return function.apply(parent.next());
}
/**
* @see java.util.Iterator#remove()
*/
@Override
public void remove() {
parent.remove();
}
}

View File

@ -0,0 +1,60 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.iterators;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class PeekingIterator<E> implements Iterator<E> {
private final Iterator<? extends E> source;
private E next = null;
public PeekingIterator(Iterator<? extends E> source) {
this.source = source;
}
@Override
public boolean hasNext() {
return next != null || source.hasNext();
}
public E peek() {
if (next == null) {
if (source.hasNext()) {
next = source.next();
} else {
throw new NoSuchElementException();
}
}
return next;
}
// SonarLint: "Iterator.next()" methods should throw "NoSuchElementException" (java:S2272)
// peek() throws NoSuchElementException as expected
@SuppressWarnings("squid:S2272")
@Override
public E next() {
E element = peek();
next = null;
return element;
}
}

View File

@ -0,0 +1,67 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.iterators;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class RangeIterator<E> implements Iterator<E> {
private final Iterator<E> parent;
private final int from;
private final int amount;
private int nextIndex = 0;
public RangeIterator(Iterator<E> iterator, int from, int amount) {
this.parent = iterator;
this.from = from;
this.amount = amount < 0 ? Integer.MAX_VALUE : amount;
}
public RangeIterator(Iterator<E> iterator, int from) {
this(iterator, from, -1);
}
@Override
public boolean hasNext() {
update();
return nextIndex < from + amount && parent.hasNext();
}
@Override
public E next() {
update();
if (nextIndex >= from + amount) {
throw new NoSuchElementException("RangeIterator about to retrieve element " + nextIndex
+ " which exceeds upper boundary " + (from + amount));
}
E result = parent.next();
nextIndex++;
return result;
}
protected void update() {
while (nextIndex < from && parent.hasNext()) {
parent.next();
nextIndex++;
}
}
}

View File

@ -0,0 +1,70 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.iterators;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class Reiterator<E> implements Iterable<E> {
private class ReiteratorIterator implements Iterator<E> {
int index = 0;
@Override
public boolean hasNext() {
synchronized (source) {
if (index >= data.size()) {
if (!source.hasNext()) {
return false;
} else {
data.add(source.next());
}
}
return true;
}
}
@Override
public E next() {
E result;
synchronized (source) {
if (!hasNext()) throw new NoSuchElementException();
result = data.get(index);
}
index++;
return result;
}
}
private final Iterator<E> source;
private final ArrayList<E> data = new ArrayList<>();
public Reiterator(Iterator<E> source) {
this.source = source;
}
@Override
public Iterator<E> iterator() {
return new ReiteratorIterator();
}
}

View File

@ -0,0 +1,39 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.selectors;
public abstract class AbstractSelectorOperator implements SelectorOperator {
private final String[] names;
public AbstractSelectorOperator(String[] names) {
this.names = names;
}
@Override
public boolean matchesName(String name) {
for (String n : names) {
if (n.equals(name)) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,57 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.selectors;
import ru.windcorp.jputil.SyntaxException;
import ru.windcorp.jputil.chars.StringUtil;
public abstract class NamedParameterizedSelector<T> extends NamedSelector<T> {
private final char separator;
private String givenName;
public NamedParameterizedSelector(char separator, String... names) {
super(names);
this.separator = separator;
}
@Override
public Selector<T> derive(String name) throws SyntaxException {
String[] parts = StringUtil.split(name, separator, 2);
if (parts[1] == null) {
return null;
}
if (!matchesName(parts[0])) {
return null;
}
NamedParameterizedSelector<T> selector = deriveImpl(parts[1]);
selector.givenName = name;
return selector;
}
protected abstract NamedParameterizedSelector<T> deriveImpl(String param) throws SyntaxException;
@Override
public String toString() {
return givenName;
}
}

View File

@ -0,0 +1,50 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.selectors;
import ru.windcorp.jputil.SyntaxException;
public abstract class NamedSelector<T> implements Selector<T> {
private final String[] names;
public NamedSelector(String... names) {
this.names = names;
}
public boolean matchesName(String name) {
for (String n : names) {
if (n.equalsIgnoreCase(name)) {
return true;
}
}
return false;
}
@Override
public Selector<T> derive(String name) throws SyntaxException {
return matchesName(name) ? this : null;
}
@Override
public String toString() {
return names[0];
}
}

View File

@ -0,0 +1,36 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.selectors;
import java.util.Deque;
import java.util.function.Predicate;
public class OperatorAnd extends AbstractSelectorOperator {
public OperatorAnd(String... names) {
super(names);
}
@Override
public <T> void process(Deque<Predicate<T>> stack) {
Predicate<T> arg2 = stack.pop();
Predicate<T> arg1 = stack.pop();
stack.push(obj -> arg1.test(obj) && arg2.test(obj));
}
}

View File

@ -0,0 +1,36 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.selectors;
import java.util.Deque;
import java.util.function.Predicate;
public class OperatorExclude extends AbstractSelectorOperator {
public OperatorExclude(String... names) {
super(names);
}
@Override
public <T> void process(Deque<Predicate<T>> stack) {
Predicate<T> arg2 = stack.pop();
Predicate<T> arg1 = stack.pop();
stack.push(obj -> arg1.test(obj) && !arg2.test(obj));
}
}

View File

@ -0,0 +1,34 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.selectors;
import java.util.Deque;
import java.util.function.Predicate;
public class OperatorNot extends AbstractSelectorOperator {
public OperatorNot(String... names) {
super(names);
}
@Override
public <T> void process(Deque<Predicate<T>> stack) {
stack.push(stack.pop().negate());
}
}

View File

@ -0,0 +1,36 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.selectors;
import java.util.Deque;
import java.util.function.Predicate;
public class OperatorOr extends AbstractSelectorOperator {
public OperatorOr(String... names) {
super(names);
}
@Override
public <T> void process(Deque<Predicate<T>> stack) {
Predicate<T> arg2 = stack.pop();
Predicate<T> arg1 = stack.pop();
stack.push(obj -> arg1.test(obj) || arg2.test(obj));
}
}

View File

@ -0,0 +1,36 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.selectors;
import java.util.Deque;
import java.util.function.Predicate;
public class OperatorXor extends AbstractSelectorOperator {
public OperatorXor(String... names) {
super(names);
}
@Override
public <T> void process(Deque<Predicate<T>> stack) {
Predicate<T> arg2 = stack.pop();
Predicate<T> arg1 = stack.pop();
stack.push(obj -> arg1.test(obj) != arg2.test(obj));
}
}

View File

@ -0,0 +1,36 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.selectors;
import java.util.function.Predicate;
public class PredicateWrapper<T> extends NamedSelector<T> {
private final Predicate<? super T> predicate;
public PredicateWrapper(String name, Predicate<? super T> predicate) {
super(name);
this.predicate = predicate;
}
@Override
public boolean test(T obj) {
return predicate.test(obj);
}
}

View File

@ -0,0 +1,28 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.selectors;
import java.util.function.Predicate;
import ru.windcorp.jputil.SyntaxException;
public interface Selector<T> extends Predicate<T> {
public Selector<T> derive(String name) throws SyntaxException;
}

View File

@ -0,0 +1,29 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.selectors;
import java.util.Deque;
import java.util.function.Predicate;
public interface SelectorOperator {
public <T> void process(Deque<Predicate<T>> stack);
public boolean matchesName(String name);
}

View File

@ -0,0 +1,176 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.selectors;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.function.Predicate;
import ru.windcorp.jputil.SyntaxException;
import ru.windcorp.jputil.iterators.PeekingIterator;
public class SelectorSystem<T> {
public static final char EXPRESSION_OPEN = '(';
public static final char EXPRESSION_CLOSE = ')';
private final Collection<Selector<T>> selectors =
Collections.synchronizedCollection(new ArrayList<Selector<T>>());
private final Collection<SelectorOperator> operators =
Collections.synchronizedCollection(new ArrayList<SelectorOperator>());
private String stackPrefix = null;
public Collection<Selector<T>> getSelectors() {
return this.selectors;
}
public Collection<SelectorOperator> getSelectorOperators() {
return this.operators;
}
public String getStackPrefix() {
return stackPrefix;
}
public SelectorSystem<T> setStackPrefix(String stackPrefix) {
this.stackPrefix = stackPrefix;
return this;
}
public SelectorSystem<T> add(Selector<T> selector) {
getSelectors().add(selector);
return this;
}
public SelectorSystem<T> add(SelectorOperator operator) {
getSelectorOperators().add(operator);
return this;
}
public Predicate<T> parse(Iterator<String> tokens) throws SyntaxException {
PeekingIterator<String> peeker = new PeekingIterator<>(tokens);
if (getStackPrefix() != null && peeker.hasNext() && getStackPrefix().equals(peeker.peek())) {
peeker.next();
return parseStack(peeker);
}
Deque<Predicate<T>> stack = new LinkedList<>();
synchronized (getSelectorOperators()) {
synchronized (getSelectors()) {
while (peeker.hasNext()) {
parseToken(stack, peeker);
}
}
}
return compress(stack);
}
private void parseToken(Deque<Predicate<T>> stack, Iterator<String> tokens) throws SyntaxException {
if (!tokens.hasNext()) {
throw new SyntaxException("Not enough tokens");
}
String token = tokens.next();
for (SelectorOperator operator : getSelectorOperators()) {
if (operator.matchesName(token.toLowerCase())) {
parseToken(stack, tokens);
operator.process(stack);
return;
}
}
Selector<T> tmp;
for (Selector<T> selector : getSelectors()) {
if ((tmp = selector.derive(token)) != null) {
stack.push(tmp);
return;
}
}
throw new SyntaxException("Unknown token \"" + token + "\"");
}
public Predicate<T> parseStack(Iterator<String> tokens) throws SyntaxException {
Deque<Predicate<T>> stack = new LinkedList<>();
String token;
synchronized (getSelectorOperators()) {
synchronized (getSelectors()) {
tokenCycle:
while (tokens.hasNext()) {
token = tokens.next();
for (SelectorOperator operator : getSelectorOperators()) {
if (operator.matchesName(token.toLowerCase())) {
operator.process(stack);
continue tokenCycle;
}
}
for (Selector<T> selector : getSelectors()) {
Selector<T> tmp;
if ((tmp = selector.derive(token)) != null) {
stack.push(tmp);
continue tokenCycle;
}
}
throw new SyntaxException("Unknown token \"" + token + "\"");
}
}
}
return compress(stack);
}
private Predicate<T> compress(Deque<Predicate<T>> stack) throws SyntaxException {
if (stack.isEmpty()) {
throw new SyntaxException("Stack is empty");
}
if (stack.size() == 1) {
return stack.pop();
}
return obj -> {
for (Predicate<? super T> predicate : stack) {
if (predicate.test(obj)) {
return true;
}
}
return false;
};
}
}

View File

@ -23,7 +23,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import ru.windcorp.progressia.common.util.ThrowingRunnable;
import ru.windcorp.jputil.functions.ThrowingRunnable;
public class RenderTaskQueue {
@ -46,9 +46,9 @@ public class RenderTaskQueue {
private static final Object WAIT_AND_INVOKE_MONITOR = new Object();
@SuppressWarnings("unchecked")
public static <T extends Throwable> void waitAndInvoke(
ThrowingRunnable<T> task
) throws InterruptedException, T {
public static <E extends Exception> void waitAndInvoke(
ThrowingRunnable<E> task
) throws InterruptedException, E {
if (GraphicsInterface.isRenderThread()) {
task.run();
@ -91,7 +91,7 @@ public class RenderTaskQueue {
throw (Error) thrown;
}
throw (T) thrown; // Guaranteed
throw (E) thrown; // Guaranteed
}
}