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:
parent
a9896fa3e1
commit
65eaae68a8
525
src/main/java/ru/windcorp/jputil/ArrayUtil.java
Normal file
525
src/main/java/ru/windcorp/jputil/ArrayUtil.java
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
104
src/main/java/ru/windcorp/jputil/CSVWriter.java
Normal file
104
src/main/java/ru/windcorp/jputil/CSVWriter.java
Normal 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
60
src/main/java/ru/windcorp/jputil/PrimitiveUtil.java
Normal file
60
src/main/java/ru/windcorp/jputil/PrimitiveUtil.java
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
1210
src/main/java/ru/windcorp/jputil/SyncStreams.java
Normal file
1210
src/main/java/ru/windcorp/jputil/SyncStreams.java
Normal file
File diff suppressed because it is too large
Load Diff
44
src/main/java/ru/windcorp/jputil/SyntaxException.java
Normal file
44
src/main/java/ru/windcorp/jputil/SyntaxException.java
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
128
src/main/java/ru/windcorp/jputil/chars/CharArrayIterator.java
Normal file
128
src/main/java/ru/windcorp/jputil/chars/CharArrayIterator.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
42
src/main/java/ru/windcorp/jputil/chars/CharConsumer.java
Normal file
42
src/main/java/ru/windcorp/jputil/chars/CharConsumer.java
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
69
src/main/java/ru/windcorp/jputil/chars/CharConsumers.java
Normal file
69
src/main/java/ru/windcorp/jputil/chars/CharConsumers.java
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
84
src/main/java/ru/windcorp/jputil/chars/CharPredicate.java
Normal file
84
src/main/java/ru/windcorp/jputil/chars/CharPredicate.java
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
35
src/main/java/ru/windcorp/jputil/chars/CharSupplier.java
Normal file
35
src/main/java/ru/windcorp/jputil/chars/CharSupplier.java
Normal 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
44
src/main/java/ru/windcorp/jputil/chars/EscapeException.java
Normal file
44
src/main/java/ru/windcorp/jputil/chars/EscapeException.java
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
474
src/main/java/ru/windcorp/jputil/chars/Escaper.java
Normal file
474
src/main/java/ru/windcorp/jputil/chars/Escaper.java
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
778
src/main/java/ru/windcorp/jputil/chars/StringUtil.java
Normal file
778
src/main/java/ru/windcorp/jputil/chars/StringUtil.java
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
139
src/main/java/ru/windcorp/jputil/chars/WordReader.java
Normal file
139
src/main/java/ru/windcorp/jputil/chars/WordReader.java
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
270
src/main/java/ru/windcorp/jputil/chars/reader/CharReader.java
Normal file
270
src/main/java/ru/windcorp/jputil/chars/reader/CharReader.java
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
112
src/main/java/ru/windcorp/jputil/chars/reader/CharReaders.java
Normal file
112
src/main/java/ru/windcorp/jputil/chars/reader/CharReaders.java
Normal 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Progressia
|
* JPUtil
|
||||||
* Copyright (C) 2020 Wind Corporation
|
* Copyright (C) 2019 Javapony/OLEGSHA
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* 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
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* 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 java.util.function.Consumer;
|
||||||
|
import java.util.function.Supplier;
|
||||||
import com.google.common.base.Throwables;
|
|
||||||
|
|
||||||
@FunctionalInterface
|
@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(
|
@SuppressWarnings("unchecked")
|
||||||
Consumer<T> catcher,
|
default Supplier<T> withHandler(Consumer<? super E> handler, Supplier<? extends T> value) {
|
||||||
Class<T> throwableClass
|
|
||||||
) {
|
|
||||||
return () -> {
|
return () -> {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ThrowingRunnable.this.run();
|
return get();
|
||||||
} catch (Throwable t) {
|
} catch (RuntimeException e) {
|
||||||
if (t.getClass() == throwableClass) {
|
throw e;
|
||||||
catcher.accept(throwableClass.cast(t));
|
} 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(
|
default Supplier<T> withHandler(Consumer<? super E> handler, T value) {
|
||||||
Consumer<Throwable> catcher
|
return withHandler(handler, () -> value);
|
||||||
) {
|
|
||||||
return () -> {
|
|
||||||
try {
|
|
||||||
ThrowingRunnable.this.run();
|
|
||||||
} catch (Throwable t) {
|
|
||||||
catcher.accept(t);
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
default Supplier<T> withHandler(Consumer<? super E> handler) {
|
||||||
|
return withHandler(handler, (Supplier<T>) null);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
70
src/main/java/ru/windcorp/jputil/iterators/Reiterator.java
Normal file
70
src/main/java/ru/windcorp/jputil/iterators/Reiterator.java
Normal 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
36
src/main/java/ru/windcorp/jputil/selectors/OperatorAnd.java
Normal file
36
src/main/java/ru/windcorp/jputil/selectors/OperatorAnd.java
Normal 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
34
src/main/java/ru/windcorp/jputil/selectors/OperatorNot.java
Normal file
34
src/main/java/ru/windcorp/jputil/selectors/OperatorNot.java
Normal 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
36
src/main/java/ru/windcorp/jputil/selectors/OperatorOr.java
Normal file
36
src/main/java/ru/windcorp/jputil/selectors/OperatorOr.java
Normal 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
36
src/main/java/ru/windcorp/jputil/selectors/OperatorXor.java
Normal file
36
src/main/java/ru/windcorp/jputil/selectors/OperatorXor.java
Normal 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
28
src/main/java/ru/windcorp/jputil/selectors/Selector.java
Normal file
28
src/main/java/ru/windcorp/jputil/selectors/Selector.java
Normal 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;
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
|
||||||
|
}
|
176
src/main/java/ru/windcorp/jputil/selectors/SelectorSystem.java
Normal file
176
src/main/java/ru/windcorp/jputil/selectors/SelectorSystem.java
Normal 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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -23,7 +23,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
|||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import ru.windcorp.progressia.common.util.ThrowingRunnable;
|
import ru.windcorp.jputil.functions.ThrowingRunnable;
|
||||||
|
|
||||||
public class RenderTaskQueue {
|
public class RenderTaskQueue {
|
||||||
|
|
||||||
@ -46,9 +46,9 @@ public class RenderTaskQueue {
|
|||||||
private static final Object WAIT_AND_INVOKE_MONITOR = new Object();
|
private static final Object WAIT_AND_INVOKE_MONITOR = new Object();
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static <T extends Throwable> void waitAndInvoke(
|
public static <E extends Exception> void waitAndInvoke(
|
||||||
ThrowingRunnable<T> task
|
ThrowingRunnable<E> task
|
||||||
) throws InterruptedException, T {
|
) throws InterruptedException, E {
|
||||||
|
|
||||||
if (GraphicsInterface.isRenderThread()) {
|
if (GraphicsInterface.isRenderThread()) {
|
||||||
task.run();
|
task.run();
|
||||||
@ -91,7 +91,7 @@ public class RenderTaskQueue {
|
|||||||
throw (Error) thrown;
|
throw (Error) thrown;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw (T) thrown; // Guaranteed
|
throw (E) thrown; // Guaranteed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user