First commit

This commit is contained in:
Andrea Cavalli 2023-05-10 17:05:09 +02:00
parent 4c94431ed6
commit 0ec246fe32
61 changed files with 1068 additions and 5425 deletions

79
.github/workflows/maven-publish.yml vendored Normal file
View File

@ -0,0 +1,79 @@
# This workflow will build a package using Maven and then publish it to GitHub packages when a release is created
# For more information see: https://github.com/actions/setup-java#apache-maven-with-a-settings-path
name: Maven Package
on:
push:
jobs:
build:
strategy:
matrix:
include:
- { os: ubuntu-20.04, arch: "linux/amd64" }
runs-on: ${{ matrix.os }}
steps:
- name: Branch name
id: branch_name
run: |
set -xeo pipefail
echo "SOURCE_NAME=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
echo "SOURCE_BRANCH=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV
echo "SOURCE_TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
echo "SOURCE_TAG_VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
cat $GITHUB_ENV > github.env
- uses: actions/checkout@v3
with:
submodules: "recursive"
- name: Setup variables
shell: bash
run: |
set -xeo pipefail
# ====== Variables
export REVISION=${{ steps.branch_name.outputs.SOURCE_TAG_VERSION }}
echo "REVISION=$REVISION" >> $GITHUB_ENV
- name: Set up JDK 17 (Snapshot)
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
uses: actions/setup-java@v3
with:
java-version: 17
distribution: temurin
cache: 'maven'
server-id: mchv-snapshot-distribution
server-username: MAVEN_USERNAME
server-password: MAVEN_PASSWORD
- name: Build and deploy to Maven (Snapshot)
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
shell: bash
run: |
set -xeo pipefail
mvn -B clean deploy
echo "Done."
env:
MAVEN_USERNAME: ${{ secrets.MCHV_USERNAME }}
MAVEN_PASSWORD: ${{ secrets.MCHV_TOKEN }}
- name: Set up JDK 17 (Release)
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
uses: actions/setup-java@v3
with:
java-version: 17
distribution: temurin
cache: 'maven'
server-id: mchv-release-distribution
server-username: MAVEN_USERNAME
server-password: MAVEN_PASSWORD
- name: Build and deploy to Maven (Release)
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
shell: bash
run: |
set -xeo pipefail
echo "REVISION: $REVISION"
mvn -B clean -Drevision="${REVISION}" deploy
echo "Done."
env:
MAVEN_USERNAME: ${{ secrets.MCHV_USERNAME }}
MAVEN_PASSWORD: ${{ secrets.MCHV_TOKEN }}

98
pom.xml
View File

@ -5,11 +5,12 @@
<packaging>jar</packaging> <packaging>jar</packaging>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>common-utils</artifactId> <groupId>it.tdlight</groupId>
<groupId>org.warp</groupId> <artifactId>common-util</artifactId>
<version>1.1.8</version> <version>${revision}</version>
<properties> <properties>
<revision>1.0.0-SNAPSHOT</revision>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> </properties>
@ -35,6 +36,11 @@
</distributionManagement> </distributionManagement>
<dependencies> <dependencies>
<dependency>
<groupId>org.jctools</groupId>
<artifactId>jctools-core</artifactId>
<version>4.0.1</version>
</dependency>
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId> <artifactId>junit-jupiter-api</artifactId>
@ -47,65 +53,6 @@
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<dependency>
<groupId>it.unimi.dsi</groupId>
<artifactId>fastutil</artifactId>
<version>8.5.8</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>23.0.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.1-jre</version>
</dependency>
<dependency>
<groupId>com.squareup.moshi</groupId>
<artifactId>moshi</artifactId>
<version>1.13.0</version>
<exclusions>
<exclusion>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
</exclusion>
<exclusion>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-common</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>dev.zacsweers.moshix</groupId>
<artifactId>moshi-records-reflect</artifactId>
<version>0.14.1</version>
<exclusions>
<exclusion>
<groupId>com.squareup.moshi</groupId>
<artifactId>moshi</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<!--suppress KotlinMavenPluginPhase -->
<artifactId>kotlin-stdlib</artifactId>
<version>1.6.0</version>
<exclusions>
<exclusion>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies> </dependencies>
<build> <build>
<plugins> <plugins>
@ -115,7 +62,7 @@
<version>3.8.1</version> <version>3.8.1</version>
<configuration> <configuration>
<encoding>UTF-8</encoding> <encoding>UTF-8</encoding>
<release>11</release> <release>8</release>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
@ -136,6 +83,31 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<version>1.1.0</version>
<configuration>
<updatePomFile>true</updatePomFile>
<flattenMode>oss</flattenMode>
</configuration>
<executions>
<execution>
<id>flatten</id>
<phase>process-resources</phase>
<goals>
<goal>flatten</goal>
</goals>
</execution>
<execution>
<id>flatten.clean</id>
<phase>clean</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins> </plugins>
</build> </build>
</project> </project>

View File

@ -1,229 +0,0 @@
/*BEGIN_COPYRIGHT_BLOCK
*
* Copyright (c) 2001-2010, JavaPLT group at Rice University (drjava@rice.edu)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software is Open Source Initiative approved Open Source Software.
* Open Source Initative Approved is a trademark of the Open Source Initiative.
*
* This file is part of DrJava. Download the current version of this project
* from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
*
* END_COPYRIGHT_BLOCK*/
package edu.rice.cs.util;
import java.util.List;
import java.util.LinkedList;
/**
* Utility class which can tokenize a String into a list of String arguments,
* with behavior similar to parsing command line arguments to a program.
* Quoted Strings are treated as single arguments, and escaped characters
* are translated so that the tokenized arguments have the same meaning.
* Since all methods are static, the class is declared abstract to prevent
* instantiation.
* @version $Id$
*/
public abstract class ArgumentTokenizer {
private static final int NO_TOKEN_STATE = 0;
private static final int NORMAL_TOKEN_STATE = 1;
private static final int SINGLE_QUOTE_STATE = 2;
private static final int DOUBLE_QUOTE_STATE = 3;
/** Tokenizes the given String into String tokens
* @param arguments A String containing one or more command-line style arguments to be tokenized.
* @return A list of parsed and properly escaped arguments.
*/
public static List<String> tokenize(String arguments) {
return tokenize(arguments, false);
}
/** Tokenizes the given String into String tokens.
* @param arguments A String containing one or more command-line style arguments to be tokenized.
* @param stringify whether or not to include escape special characters
* @return A list of parsed and properly escaped arguments.
*/
public static List<String> tokenize(String arguments, boolean stringify) {
LinkedList<String> argList = new LinkedList<String>();
StringBuilder currArg = new StringBuilder();
boolean escaped = false;
int state = NO_TOKEN_STATE; // start in the NO_TOKEN_STATE
int len = arguments.length();
// Loop over each character in the string
for (int i = 0; i < len; i++) {
char c = arguments.charAt(i);
if (escaped) {
// Escaped state: just append the next character to the current arg.
escaped = false;
currArg.append(c);
}
else {
switch(state) {
case SINGLE_QUOTE_STATE:
if (c == '\'') {
// Seen the close quote; continue this arg until whitespace is seen
state = NORMAL_TOKEN_STATE;
}
else {
currArg.append(c);
}
break;
case DOUBLE_QUOTE_STATE:
if (c == '"') {
// Seen the close quote; continue this arg until whitespace is seen
state = NORMAL_TOKEN_STATE;
}
else if (c == '\\') {
// Look ahead, and only escape quotes or backslashes
i++;
char next = arguments.charAt(i);
if (next == '"' || next == '\\') {
currArg.append(next);
}
else {
currArg.append(c);
currArg.append(next);
}
}
else {
currArg.append(c);
}
break;
// case NORMAL_TOKEN_STATE:
// if (Character.isWhitespace(c)) {
// // Whitespace ends the token; start a new one
// argList.add(currArg.toString());
// currArg = new StringBuffer();
// state = NO_TOKEN_STATE;
// }
// else if (c == '\\') {
// // Backslash in a normal token: escape the next character
// escaped = true;
// }
// else if (c == '\'') {
// state = SINGLE_QUOTE_STATE;
// }
// else if (c == '"') {
// state = DOUBLE_QUOTE_STATE;
// }
// else {
// currArg.append(c);
// }
// break;
case NO_TOKEN_STATE:
case NORMAL_TOKEN_STATE:
switch(c) {
case '\\':
escaped = true;
state = NORMAL_TOKEN_STATE;
break;
case '\'':
state = SINGLE_QUOTE_STATE;
break;
case '"':
state = DOUBLE_QUOTE_STATE;
break;
default:
if (!Character.isWhitespace(c)) {
currArg.append(c);
state = NORMAL_TOKEN_STATE;
}
else if (state == NORMAL_TOKEN_STATE) {
// Whitespace ends the token; start a new one
argList.add(currArg.toString());
currArg = new StringBuilder();
state = NO_TOKEN_STATE;
}
}
break;
default:
throw new IllegalStateException("ArgumentTokenizer state " + state + " is invalid!");
}
}
}
// If we're still escaped, put in the backslash
if (escaped) {
currArg.append('\\');
argList.add(currArg.toString());
}
// Close the last argument if we haven't yet
else if (state != NO_TOKEN_STATE) {
argList.add(currArg.toString());
}
// Format each argument if we've been told to stringify them
if (stringify) {
for (int i = 0; i < argList.size(); i++) {
argList.set(i, "\"" + _escapeQuotesAndBackslashes(argList.get(i)) + "\"");
}
}
return argList;
}
/** Inserts backslashes before any occurrences of a backslash or
* quote in the given string. Also converts any special characters
* appropriately.
*/
protected static String _escapeQuotesAndBackslashes(String s) {
final StringBuilder buf = new StringBuilder(s);
// Walk backwards, looking for quotes or backslashes.
// If we see any, insert an extra backslash into the buffer at
// the same index. (By walking backwards, the index into the buffer
// will remain correct as we change the buffer.)
for (int i = s.length()-1; i >= 0; i--) {
char c = s.charAt(i);
if ((c == '\\') || (c == '"')) {
buf.insert(i, '\\');
}
// Replace any special characters with escaped versions
else if (c == '\n') {
buf.deleteCharAt(i);
buf.insert(i, "\\n");
}
else if (c == '\t') {
buf.deleteCharAt(i);
buf.insert(i, "\\t");
}
else if (c == '\r') {
buf.deleteCharAt(i);
buf.insert(i, "\\r");
}
else if (c == '\b') {
buf.deleteCharAt(i);
buf.insert(i, "\\b");
}
else if (c == '\f') {
buf.deleteCharAt(i);
buf.insert(i, "\\f");
}
}
return buf.toString();
}
}

View File

@ -0,0 +1,25 @@
package it.tdlight.commonutil;
/**
* An iterator optimized for primitive collections which avoids auto-boxing on {@link #next()}.
*/
public interface IntIterator {
/**
* Identical to {@link java.util.Iterator#next()} but avoids auto-boxing.
*
* @return The next int in the collection.
*/
int next();
/**
* Identical to {@link java.util.Iterator#hasNext()}.
*
* @return True if the iterator has more elements.
*/
boolean hasNext();
/**
* Identical to {@link java.util.Iterator#remove()}.
*/
void remove();
}

View File

@ -0,0 +1,16 @@
package it.tdlight.commonutil;
import java.util.Iterator;
/**
* An extension of the standard {@link Iterator} interface which provides the {@link #nextLong()} method to avoid
* auto-boxing of results as they are returned.
* */
public interface LongIterator extends Iterator<Long> {
/**
* Returns the next long value without auto-boxing. Using this is preferred to {@link #next()}.
*
* @return The next long value.
*/
long nextLong();
}

View File

@ -0,0 +1,188 @@
package it.tdlight.commonutil;
import java.io.Serializable;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import org.jctools.maps.NonBlockingHashMapLong;
/**
* A simple wrapper around {@link NonBlockingHashMapLong} making it implement the
* {@link Set} interface. All operations are Non-Blocking and multi-thread safe.
*/
public class NonBlockingHashSetLong extends AbstractSet<Long> implements Serializable {
private static final Object V = "";
private final NonBlockingHashMapLong<Object> _map;
/** Make a new empty {@link NonBlockingHashSetLong}. */
public NonBlockingHashSetLong() {
super();
_map = new NonBlockingHashMapLong<Object>();
}
@Override
public boolean addAll(Collection<? extends Long> c) {
if (!NonBlockingHashSetLong.class.equals(c.getClass())) {
return super.addAll(c);
}
boolean modified = false;
for (final LongIterator it = ((NonBlockingHashSetLong)c).longIterator(); it.hasNext(); ) {
modified |= add(it.nextLong());
}
return modified;
}
@Override
public boolean removeAll(Collection<?> c) {
if (!NonBlockingHashSetLong.class.equals(c.getClass())) {
return super.removeAll(c);
}
boolean modified = false;
for (final LongIterator it = ((NonBlockingHashSetLong)c).longIterator(); it.hasNext(); ) {
modified |= remove(it.nextLong());
}
return modified;
}
@Override
public boolean containsAll(Collection<?> c) {
if (!NonBlockingHashSetLong.class.equals(c.getClass())) {
return super.containsAll(c);
}
for (final LongIterator it = ((NonBlockingHashSetLong)c).longIterator(); it.hasNext(); ) {
if (!contains(it.nextLong())) {
return false;
}
}
return true;
}
@Override
public boolean retainAll(Collection<?> c) {
if (!NonBlockingHashSetLong.class.equals(c.getClass())) {
return super.retainAll(c);
}
boolean modified = false;
final NonBlockingHashSetLong nonBlockingHashSetLong = (NonBlockingHashSetLong) c;
for (final LongIterator it = longIterator(); it.hasNext(); ) {
if (!nonBlockingHashSetLong.contains(it.nextLong())) {
it.remove();
modified = true;
}
}
return modified;
}
@Override
public int hashCode() {
int hashCode = 0;
for (final LongIterator it = longIterator(); it.hasNext(); ) {
final long value = it.nextLong();
hashCode += (int)(value ^ (value >>> 32));
}
return hashCode;
}
/** Add {@code o} to the set.
* @return <tt>true</tt> if {@code o} was added to the set, <tt>false</tt>
* if {@code o} was already in the set.
*/
public boolean add(final long o) {
return _map.putIfAbsent(o,V) != V;
}
/**
* To support AbstractCollection.addAll
*/
@Override
public boolean add(final Long o) {
return _map.putIfAbsent(o.longValue(),V) != V;
}
/**
* @return <tt>true</tt> if {@code o} is in the set.
*/
public boolean contains(final long o) { return _map.containsKey(o); }
@Override
public boolean contains(Object o) {
return o instanceof Long && contains(((Long) o).longValue());
}
/** Remove {@code o} from the set.
* @return <tt>true</tt> if {@code o} was removed to the set, <tt>false</tt>
* if {@code o} was not in the set.
*/
public boolean remove(final long o) { return _map.remove(o) == V; }
@Override
public boolean remove(final Object o) { return o instanceof Long && remove(((Long) o).longValue()); }
/**
* Current count of elements in the set. Due to concurrent racing updates,
* the size is only ever approximate. Updates due to the calling thread are
* immediately visible to calling thread.
* @return count of elements.
*/
@Override
public int size() { return _map.size(); }
/** Empty the set. */
@Override
public void clear() { _map.clear(); }
@Override
public String toString() {
// Overloaded to avoid auto-boxing
final LongIterator it = longIterator();
if (!it.hasNext()) {
return "[]";
}
final StringBuilder sb = new StringBuilder().append('[');
for (;;) {
sb.append(it.next());
if (!it.hasNext()) {
return sb.append(']').toString();
}
sb.append(", ");
}
}
@Override
public Iterator<Long>iterator() { return _map.keySet().iterator(); }
public LongIterator longIterator() {
return (LongIterator) _map.keySet().iterator();
}
// ---
/**
* Atomically make the set immutable. Future calls to mutate will throw an
* IllegalStateException. Existing mutator calls in other threads racing
* with this thread and will either throw IllegalStateException or their
* update will be visible to this thread. This implies that a simple flag
* cannot make the Set immutable, because a late-arriving update in another
* thread might see immutable flag not set yet, then mutate the Set after
* the {@link #readOnly} call returns. This call can be called concurrently
* (and indeed until the operation completes, all calls on the Set from any
* thread either complete normally or end up calling {@link #readOnly}
* internally).
*
* <p> This call is useful in debugging multi-threaded programs where the
* Set is constructed in parallel, but construction completes after some
* time; and after construction the Set is only read. Making the Set
* read-only will cause updates arriving after construction is supposedly
* complete to throw an {@link IllegalStateException}.
*/
// (1) call _map's immutable() call
// (2) get snapshot
// (3) CAS down a local map, power-of-2 larger than _map.size()+1/8th
// (4) start @ random, visit all snapshot, insert live keys
// (5) CAS _map to null, needs happens-after (4)
// (6) if Set call sees _map is null, needs happens-after (4) for readers
public void readOnly() {
throw new RuntimeException("Unimplemented");
}
}

View File

@ -0,0 +1,725 @@
/*
* Written by Cliff Click and released to the public domain, as explained at
* http://creativecommons.org/licenses/publicdomain
*/
package it.tdlight.commonutil;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.concurrent.atomic.AtomicInteger;
import org.jctools.maps.ConcurrentAutoTable;
import org.jctools.util.UnsafeAccess;
import sun.misc.Unsafe;
/**
* A multi-threaded bit-vector set, implemented as an array of primitive
* {@code longs}. All operations are non-blocking and multi-threaded safe.
* {@link #contains(int)} calls are roughly the same speed as a {load, mask}
* sequence. {@link #add(int)} and {@link #remove(int)} calls are a tad more
* expensive than a {load, mask, store} sequence because they must use a CAS.
* The bit-vector is auto-sizing.
*
* <p><em>General note of caution:</em> The Set API allows the use of {@link Integer}
* with silent autoboxing - which can be very expensive if many calls are
* being made. Since autoboxing is silent you may not be aware that this is
* going on. The built-in API takes lower-case {@code ints} and is much more
* efficient.
*
* <p>Space: space is used in proportion to the largest element, as opposed to
* the number of elements (as is the case with hash-table based Set
* implementations). Space is approximately (largest_element/8 + 64) bytes.
*
* The implementation is a simple bit-vector using CAS for update.
*
* @since 1.5
* @author Cliff Click
*/
public class NonBlockingSetInt extends AbstractSet<Integer> implements Serializable {
private static final long serialVersionUID = 1234123412341234123L;
private static final Unsafe _unsafe = UnsafeAccess.UNSAFE;
// --- Bits to allow atomic update of the NBSI
private static final long _nbsi_offset;
static { // <clinit>
Field f = null;
try {
f = NonBlockingSetInt.class.getDeclaredField("_nbsi");
} catch( NoSuchFieldException e ) {
}
_nbsi_offset = _unsafe.objectFieldOffset(f);
}
private final boolean CAS_nbsi( NBSI old, NBSI nnn ) {
return _unsafe.compareAndSwapObject(this, _nbsi_offset, old, nnn );
}
// The actual Set of Joy, which changes during a resize event. The
// Only Field for this class, so I can atomically change the entire
// set implementation with a single CAS.
private transient NBSI _nbsi;
/** Create a new empty bit-vector */
public NonBlockingSetInt( ) {
_nbsi = new NBSI(63, new ConcurrentAutoTable(), this); // The initial 1-word set
}
private NonBlockingSetInt(NonBlockingSetInt a, NonBlockingSetInt b) {
_nbsi = new NBSI(a._nbsi,b._nbsi,new ConcurrentAutoTable(),this);
}
/**
* Overridden to avoid auto-boxing for NonBlockingSetInt.
*
* @param c The collection to add to this set.
* @return True if the set was modified.
*/
@Override
public boolean addAll(Collection<? extends Integer> c) {
if (!NonBlockingSetInt.class.equals(c.getClass())) {
return super.addAll(c);
}
boolean modified = false;
for (final IntIterator it = ((NonBlockingSetInt)c).intIterator(); it.hasNext(); ) {
modified |= add(it.next());
}
return modified;
}
/**
* Overridden to avoid auto-boxing for NonBlockingSetInt.
*
* @param c The collection to remove from this set.
* @return True if the set was modified.
*/
@Override
public boolean removeAll(Collection<?> c) {
if (!NonBlockingSetInt.class.equals(c.getClass())) {
return super.removeAll(c);
}
boolean modified = false;
for (final IntIterator it = ((NonBlockingSetInt)c).intIterator(); it.hasNext(); ) {
modified |= remove(it.next());
}
return modified;
}
@Override
public boolean containsAll(Collection<?> c) {
if (!NonBlockingSetInt.class.equals(c.getClass())) {
return super.containsAll(c);
}
for (final IntIterator it = ((NonBlockingSetInt)c).intIterator(); it.hasNext(); ) {
if (!contains(it.next())) {
return false;
}
}
return true;
}
@Override
public boolean retainAll(Collection<?> c) {
if (!NonBlockingSetInt.class.equals(c.getClass())) {
return super.retainAll(c);
}
boolean modified = false;
final NonBlockingSetInt nonBlockingSetInt = (NonBlockingSetInt) c;
for (final IntIterator it = intIterator(); it.hasNext(); ) {
if (!nonBlockingSetInt.contains(it.next())) {
it.remove();
modified = true;
}
}
return modified;
}
@Override
public int hashCode() {
int hashCode = 0;
for (final IntIterator it = intIterator(); it.hasNext(); ) {
hashCode += it.next();
}
return hashCode;
}
/**
* Add {@code i} to the set. Uppercase {@link Integer} version of add,
* requires auto-unboxing. When possible use the {@code int} version of
* {@link #add(int)} for efficiency.
* @throws IllegalArgumentException if i is negative.
* @return <tt>true</tt> if i was added to the set.
*/
@Override
public boolean add ( final Integer i ) {
return add(i.intValue());
}
/**
* Test if {@code o} is in the set. This is the uppercase {@link Integer}
* version of contains, requires a type-check and auto-unboxing. When
* possible use the {@code int} version of {@link #contains(int)} for
* efficiency.
* @return <tt>true</tt> if i was in the set.
*/
@Override
public boolean contains( final Object o ) {
return o instanceof Integer && contains(((Integer) o).intValue());
}
/**
* Remove {@code o} from the set. This is the uppercase {@link Integer}
* version of remove, requires a type-check and auto-unboxing. When
* possible use the {@code int} version of {@link #remove(int)} for
* efficiency.
* @return <tt>true</tt> if i was removed to the set.
*/
@Override
public boolean remove( final Object o ) {
return o instanceof Integer && remove(((Integer) o).intValue());
}
/**
* Add {@code i} to the set. This is the lower-case '{@code int}' version
* of {@link #add} - no autoboxing. Negative values throw
* IllegalArgumentException.
* @throws IllegalArgumentException if i is negative.
* @return <tt>true</tt> if i was added to the set.
*/
public boolean add( final int i ) {
if( i < 0 ) throw new IllegalArgumentException(""+i);
return _nbsi.add(i);
}
/**
* Test if {@code i} is in the set. This is the lower-case '{@code int}'
* version of {@link #contains} - no autoboxing.
* @return <tt>true</tt> if i was int the set.
*/
public boolean contains( final int i ) { return i >= 0 && _nbsi.contains(i); }
/**
* Remove {@code i} from the set. This is the fast lower-case '{@code int}'
* version of {@link #remove} - no autoboxing.
* @return <tt>true</tt> if i was added to the set.
*/
public boolean remove ( final int i ) { return i >= 0 && _nbsi.remove(i); }
/**
* Current count of elements in the set. Due to concurrent racing updates,
* the size is only ever approximate. Updates due to the calling thread are
* immediately visible to calling thread.
* @return count of elements.
*/
@Override
public int size ( ) { return _nbsi.size( ); }
/** Empty the bitvector. */
@Override
public void clear ( ) {
NBSI cleared = new NBSI(63, new ConcurrentAutoTable(), this); // An empty initial NBSI
while( !CAS_nbsi( _nbsi, cleared ) ) // Spin until clear works
;
}
@Override
public String toString() {
// Overloaded to avoid auto-boxing
final IntIterator it = intIterator();
if (!it.hasNext()) {
return "[]";
}
final StringBuilder sb = new StringBuilder().append('[');
for (;;) {
sb.append(it.next());
if (!it.hasNext()) {
return sb.append(']').toString();
}
sb.append(", ");
}
}
public int sizeInBytes() { return _nbsi.sizeInBytes(); }
/*****************************************************************
*
* bitwise comparisons optimised for NBSI
*
*****************************************************************/
public NonBlockingSetInt intersect(final NonBlockingSetInt op) {
NonBlockingSetInt res = new NonBlockingSetInt(this,op);
res._nbsi.intersect(res._nbsi, this._nbsi, op._nbsi);
return res;
}
public NonBlockingSetInt union(final NonBlockingSetInt op) {
NonBlockingSetInt res = new NonBlockingSetInt(this,op);
res._nbsi.union(res._nbsi, this._nbsi, op._nbsi);
return res;
}
// public NonBlockingSetInt not(final NonBlockingSetInt op) {
//
// }
/** Verbose printout of internal structure for debugging. */
public void print() { _nbsi.print(0); }
/**
* Standard Java {@link Iterator}. Not very efficient because it
* auto-boxes the returned values.
*/
@Override
public Iterator<Integer> iterator( ) { return new iter(); }
public IntIterator intIterator() { return new NBSIIntIterator(); }
private class NBSIIntIterator implements IntIterator {
NBSI nbsi;
int index = -1;
int prev = -1;
NBSIIntIterator() {
nbsi = _nbsi;
advance();
}
private void advance() {
while( true ) {
index++; // Next index
while( (index>>6) >= nbsi._bits.length ) { // Index out of range?
if( nbsi._new == null ) { // New table?
index = -2; // No, so must be all done
return; //
}
nbsi = nbsi._new; // Carry on, in the new table
}
if( nbsi.contains(index) ) return;
}
}
@Override
public int next() {
if( index == -1 ) throw new NoSuchElementException();
prev = index;
advance();
return prev;
}
@Override
public boolean hasNext() {
return index != -2;
}
@Override
public void remove() {
if( prev == -1 ) throw new IllegalStateException();
nbsi.remove(prev);
prev = -1;
}
}
private class iter implements Iterator<Integer> {
NBSIIntIterator intIterator;
iter() { intIterator = new NBSIIntIterator(); }
@Override
public boolean hasNext() { return intIterator.hasNext(); }
@Override
public Integer next() { return intIterator.next(); }
@Override
public void remove() { intIterator.remove(); }
}
// --- writeObject -------------------------------------------------------
// Write a NBSI to a stream
private void writeObject(java.io.ObjectOutputStream s) throws IOException {
s.defaultWriteObject(); // Nothing to write
final NBSI nbsi = _nbsi; // The One Field is transient
final int len = _nbsi._bits.length<<6;
s.writeInt(len); // Write max element
for( int i=0; i<len; i++ )
s.writeBoolean( _nbsi.contains(i) );
}
// --- readObject --------------------------------------------------------
// Read a CHM from a stream
private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {
s.defaultReadObject(); // Read nothing
final int len = s.readInt(); // Read max element
_nbsi = new NBSI(len, new ConcurrentAutoTable(), this);
for( int i=0; i<len; i++ ) // Read all bits
if( s.readBoolean() )
_nbsi.add(i);
}
// --- NBSI ----------------------------------------------------------------
private static final class NBSI {
// Back pointer to the parent wrapper; sorta like make the class non-static
private transient final NonBlockingSetInt _non_blocking_set_int;
// Used to count elements: a high-performance counter.
private transient final ConcurrentAutoTable _size;
// The Bits
private final long _bits[];
// --- Bits to allow Unsafe access to arrays
private static final int _Lbase = _unsafe.arrayBaseOffset(long[].class);
private static final int _Lscale = _unsafe.arrayIndexScale(long[].class);
private static long rawIndex(final long[] ary, final int idx) {
assert idx >= 0 && idx < ary.length;
return _Lbase + idx * _Lscale;
}
private final boolean CAS( int idx, long old, long nnn ) {
return _unsafe.compareAndSwapLong( _bits, rawIndex(_bits, idx), old, nnn );
}
// --- Resize
// The New Table, only set once to non-zero during a resize.
// Must be atomically set.
private NBSI _new;
private static final long _new_offset;
static { // <clinit>
Field f = null;
try {
f = NBSI.class.getDeclaredField("_new");
} catch( NoSuchFieldException e ) {
}
_new_offset = _unsafe.objectFieldOffset(f);
}
private final boolean CAS_new( NBSI nnn ) {
return _unsafe.compareAndSwapObject(this, _new_offset, null, nnn );
}
private transient final AtomicInteger _copyIdx; // Used to count bits started copying
private transient final AtomicInteger _copyDone; // Used to count words copied in a resize operation
private transient final int _sum_bits_length; // Sum of all nested _bits.lengths
private static final long mask( int i ) { return 1L<<(i&63); }
// I need 1 free bit out of 64 to allow for resize. I do this by stealing
// the high order bit - but then I need to do something with adding element
// number 63 (and friends). I could use a mod63 function but it's more
// efficient to handle the mod-64 case as an exception.
//
// Every 64th bit is put in it's own recursive bitvector. If the low 6 bits
// are all set, we shift them off and recursively operate on the _nbsi64 set.
private final NBSI _nbsi64;
private NBSI(int max_elem, ConcurrentAutoTable ctr, NonBlockingSetInt nonb ) {
super();
_non_blocking_set_int = nonb;
_size = ctr;
_copyIdx = ctr == null ? null : new AtomicInteger();
_copyDone = ctr == null ? null : new AtomicInteger();
// The main array of bits
_bits = new long[(int)(((long)max_elem+63)>>>6)];
// Every 64th bit is moved off to it's own subarray, so that the
// sign-bit is free for other purposes
_nbsi64 = ((max_elem+1)>>>6) == 0 ? null : new NBSI((max_elem+1)>>>6, null, null);
_sum_bits_length = _bits.length + (_nbsi64==null ? 0 : _nbsi64._sum_bits_length);
}
/** built a new NBSI with buffers large enough to hold bitwise operations on the operands **/
private NBSI(NBSI a, NBSI b, ConcurrentAutoTable ctr, NonBlockingSetInt nonb) {
super();
_non_blocking_set_int = nonb;
_size = ctr;
_copyIdx = ctr == null ? null : new AtomicInteger();
_copyDone = ctr == null ? null : new AtomicInteger();
if(!has_bits(a) && !has_bits(b)) {
_bits = null;
_nbsi64 = null;
_sum_bits_length = 0;
return;
}
// todo - clean this nastiness up
// essentially just safely creates new empty buffers for each of the recursive bitsets
if(!has_bits(a)) {
_bits = new long[b._bits.length];
_nbsi64 = new NBSI(null,b._nbsi64,null,null);
} else if(!has_bits(b)) {
_bits = new long[a._bits.length];
_nbsi64 = new NBSI(null,a._nbsi64,null,null);
} else {
int bit_length = a._bits.length > b._bits.length ? a._bits.length : b._bits.length;
_bits = new long[bit_length];
_nbsi64 = new NBSI(a._nbsi64,b._nbsi64,null,null);
}
_sum_bits_length = _bits.length + _nbsi64._sum_bits_length;
}
private static boolean has_bits(NBSI n) {
return n != null && n._bits != null;
}
// Lower-case 'int' versions - no autoboxing, very fast.
// 'i' is known positive.
public boolean add( final int i ) {
// Check for out-of-range for the current size bit vector.
// If so we need to grow the bit vector.
if( (i>>6) >= _bits.length )
return install_larger_new_bits(i). // Install larger pile-o-bits (duh)
help_copy().add(i); // Finally, add to the new table
// Handle every 64th bit via using a nested array
NBSI nbsi = this; // The bit array being added into
int j = i; // The bit index being added
while( (j&63) == 63 ) { // Bit 64? (low 6 bits are all set)
nbsi = nbsi._nbsi64; // Recurse
j = j>>6; // Strip off low 6 bits (all set)
}
final long mask = mask(j);
long old;
do {
old = nbsi._bits[j>>6]; // Read old bits
if( old < 0 ) // Not mutable?
// Not mutable: finish copy of word, and retry on copied word
return help_copy_impl(i).help_copy().add(i);
if( (old & mask) != 0 ) return false; // Bit is already set?
} while( !nbsi.CAS( j>>6, old, old | mask ) );
_size.add(1);
return true;
}
public boolean remove( final int i ) {
if( (i>>6) >= _bits.length ) // Out of bounds? Not in this array!
return _new==null ? false : help_copy().remove(i);
// Handle every 64th bit via using a nested array
NBSI nbsi = this; // The bit array being added into
int j = i; // The bit index being added
while( (j&63) == 63 ) { // Bit 64? (low 6 bits are all set)
nbsi = nbsi._nbsi64; // Recurse
j = j>>6; // Strip off low 6 bits (all set)
}
final long mask = mask(j);
long old;
do {
old = nbsi._bits[j>>6]; // Read old bits
if( old < 0 ) // Not mutable?
// Not mutable: finish copy of word, and retry on copied word
return help_copy_impl(i).help_copy().remove(i);
if( (old & mask) == 0 ) return false; // Bit is already clear?
} while( !nbsi.CAS( j>>6, old, old & ~mask ) );
_size.add(-1);
return true;
}
public boolean contains( final int i ) {
if( (i>>6) >= _bits.length ) // Out of bounds? Not in this array!
return _new==null ? false : help_copy().contains(i);
// Handle every 64th bit via using a nested array
NBSI nbsi = this; // The bit array being added into
int j = i; // The bit index being added
while( (j&63) == 63 ) { // Bit 64? (low 6 bits are all set)
nbsi = nbsi._nbsi64; // Recurse
j = j>>6; // Strip off low 6 bits (all set)
}
final long mask = mask(j);
long old = nbsi._bits[j>>6]; // Read old bits
if( old < 0 ) // Not mutable?
// Not mutable: finish copy of word, and retry on copied word
return help_copy_impl(i).help_copy().contains(i);
// Yes mutable: test & return bit
return (old & mask) != 0;
}
/**
* Bitwise operations which store the result in this instance.
* Assumes that this instance contains ample buffer space to store the largest
* buffer from each NBSI in the recursive bitmap.
*
* Also assumes that this method is called during the construction process of
* the bitset before the instance could be leaked to multiple threads.
***/
public boolean intersect(NBSI dest, NBSI a, NBSI b) {
// terminate recursion if one bitset is missing data
// since that word should be left as 0L anyway
if(!has_bits(a) || !has_bits(b))
return true;
for(int i = 0; i < dest._bits.length; i++) {
long left = a.safe_read_word(i,0L);
long right = b.safe_read_word(i,0L);
dest._bits[i] = (left & right) & Long.MAX_VALUE; // mask sign bit
}
// todo - recompute size
return intersect(dest._nbsi64, a._nbsi64, b._nbsi64);
}
public boolean union(NBSI dest, NBSI a, NBSI b) {
// terminate recursion if neiter bitset has data
if(!has_bits(a) && !has_bits(b))
return true;
if(has_bits(a) || has_bits(b)) {
for(int i = 0; i < dest._bits.length; i++) {
long left = a == null ? 0L : a.safe_read_word(i,0);
long right = b == null ? 0L : b.safe_read_word(i,0);
dest._bits[i] = (left | right) & Long.MAX_VALUE;
}
}
return union(dest._nbsi64, a == null ? null : a._nbsi64, b == null ? null : b._nbsi64);
}
/**************************************************************************/
private long safe_read_word(int i, long default_word) {
if(i >= _bits.length) {
// allow reading past the end of the buffer filling in a default word
return default_word;
}
long word = _bits[i];
if(word < 0) {
NBSI nb = help_copy_impl(i);
if(nb._non_blocking_set_int == null) {
return default_word;
}
word = nb.help_copy()._bits[i];
}
return word;
}
public int sizeInBytes() { return (int)_bits.length; }
public int size() { return (int)_size.get(); }
// Must grow the current array to hold an element of size i
private NBSI install_larger_new_bits( final int i ) {
if( _new == null ) {
// Grow by powers of 2, to avoid minor grow-by-1's.
// Note: must grow by exact powers-of-2 or the by-64-bit trick doesn't work right
int sz = (_bits.length<<6)<<1;
// CAS to install a new larger size. Did it work? Did it fail? We
// don't know and don't care. Only One can be installed, so if
// another thread installed a too-small size, we can't help it - we
// must simply install our new larger size as a nested-resize table.
CAS_new(new NBSI(sz, _size, _non_blocking_set_int));
}
// Return self for 'fluid' programming style
return this;
}
// Help any top-level NBSI to copy until completed.
// Always return the _new version of *this* NBSI, in case we're nested.
private NBSI help_copy() {
// Pick some words to help with - but only help copy the top-level NBSI.
// Nested NBSI waits until the top is done before we start helping.
NBSI top_nbsi = _non_blocking_set_int._nbsi;
final int HELP = 8; // Tuning number: how much copy pain are we willing to inflict?
// We "help" by forcing individual bit indices to copy. However, bits
// come in lumps of 64 per word, so we just advance the bit counter by 64's.
int idx = top_nbsi._copyIdx.getAndAdd(64*HELP);
for( int i=0; i<HELP; i++ ) {
int j = idx+i*64;
j %= (top_nbsi._bits.length<<6); // Limit, wrap to array size; means we retry indices
top_nbsi.help_copy_impl(j );
top_nbsi.help_copy_impl(j+63); // Also force the nested-by-64 bit
}
// Top level guy ready to promote?
// Note: WE may not be the top-level guy!
if( top_nbsi._copyDone.get() == top_nbsi._sum_bits_length )
// One shot CAS to promote - it may fail since we are racing; others
// may promote as well
if( _non_blocking_set_int.CAS_nbsi( top_nbsi, top_nbsi._new ) ) {
//System.out.println("Promote at top level to size "+(_non_blocking_set_int._nbsi._bits.length<<6));
}
// Return the new bitvector for 'fluid' programming style
return _new;
}
// Help copy this one word. State Machine.
// (1) If not "made immutable" in the old array, set the sign bit to make
// it immutable.
// (2) If non-zero in old array & zero in new, CAS new from 0 to copy-of-old
// (3) If non-zero in old array & non-zero in new, CAS old to zero
// (4) Zero in old, new is valid
// At this point, old should be immutable-zero & new has a copy of bits
private NBSI help_copy_impl( int i ) {
// Handle every 64th bit via using a nested array
NBSI old = this; // The bit array being copied from
NBSI nnn = _new; // The bit array being copied to
if( nnn == null ) return this; // Promoted already
int j = i; // The bit index being added
while( (j&63) == 63 ) { // Bit 64? (low 6 bits are all set)
old = old._nbsi64; // Recurse
nnn = nnn._nbsi64; // Recurse
j = j>>6; // Strip off low 6 bits (all set)
}
// Transit from state 1: word is not immutable yet
// Immutable is in bit 63, the sign bit.
long bits = old._bits[j>>6];
while( bits >= 0 ) { // Still in state (1)?
long oldbits = bits;
bits |= mask(63); // Target state of bits: sign-bit means immutable
if( old.CAS( j>>6, oldbits, bits ) ) {
if( oldbits == 0 ) _copyDone.addAndGet(1);
break; // Success - old array word is now immutable
}
bits = old._bits[j>>6]; // Retry if CAS failed
}
// Transit from state 2: non-zero in old and zero in new
if( bits != mask(63) ) { // Non-zero in old?
long new_bits = nnn._bits[j>>6];
if( new_bits == 0 ) { // New array is still zero
new_bits = bits & ~mask(63); // Desired new value: a mutable copy of bits
// One-shot CAS attempt, no loop, from 0 to non-zero.
// If it fails, somebody else did the copy for us
if( !nnn.CAS( j>>6, 0, new_bits ) )
new_bits = nnn._bits[j>>6]; // Since it failed, get the new value
assert new_bits != 0;
}
// Transit from state 3: non-zero in old and non-zero in new
// One-shot CAS attempt, no loop, from non-zero to 0 (but immutable)
if( old.CAS( j>>6, bits, mask(63) ) )
_copyDone.addAndGet(1); // One more word finished copying
}
// Now in state 4: zero (and immutable) in old
// Return the self bitvector for 'fluid' programming style
return this;
}
private void print( int d, String msg ) {
for( int i=0; i<d; i++ )
System.out.print(" ");
System.out.println(msg);
}
private void print(int d) {
StringBuilder buf = new StringBuilder();
buf.append("NBSI - _bits.len=");
NBSI x = this;
while( x != null ) {
buf.append(" "+x._bits.length);
x = x._nbsi64;
}
print(d,buf.toString());
x = this;
while( x != null ) {
for( int i=0; i<x._bits.length; i++ )
System.out.print(Long.toHexString(x._bits[i])+" ");
x = x._nbsi64;
System.out.println();
}
if( _copyIdx.get() != 0 || _copyDone.get() != 0 )
print(d,"_copyIdx="+_copyIdx.get()+" _copyDone="+_copyDone.get()+" _words_to_cpy="+_sum_bits_length);
if( _new != null ) {
print(d,"__has_new - ");
_new.print(d+1);
}
}
}
}

View File

@ -1,16 +0,0 @@
module common.utils {
exports org.warp.commonutils.moshi;
exports org.warp.commonutils.type;
exports org.warp.commonutils.range;
exports org.warp.commonutils.error;
exports org.warp.commonutils.random;
exports org.warp.commonutils.functional;
exports edu.rice.cs.util;
exports org.warp.commonutils.locks;
requires org.jetbrains.annotations;
requires it.unimi.dsi.fastutil;
requires moshi;
requires moshi.records.reflect;
requires org.apache.commons.lang3;
requires okio;
}

View File

@ -1,19 +0,0 @@
package org.warp.commonutils.error;
public class IndexOutOfBoundsException extends RuntimeException {
public IndexOutOfBoundsException() {
}
public IndexOutOfBoundsException(String s) {
super(s);
}
public IndexOutOfBoundsException(long index) {
super("Index out of range: " + index);
}
public IndexOutOfBoundsException(long index, long min, long max) {
super("Index " + index + " out of range (from " + min + " to " + max + ")");
}
}

View File

@ -1,8 +0,0 @@
package org.warp.commonutils.functional;
import java.io.IOException;
public interface IOBiConsumer<T, U> {
void consume(T t, U u) throws IOException;
}

View File

@ -1,8 +0,0 @@
package org.warp.commonutils.functional;
import java.io.IOException;
public interface IOBooleanSupplier {
boolean get() throws IOException;
}

View File

@ -1,8 +0,0 @@
package org.warp.commonutils.functional;
import java.io.IOException;
import java.util.concurrent.CompletableFuture;
public interface IOCompletableFunction<T, U> {
CompletableFuture<U> apply(T value) throws IOException;
}

View File

@ -1,8 +0,0 @@
package org.warp.commonutils.functional;
import java.io.IOException;
public interface IOConsumer<T> {
void consume(T value) throws IOException;
}

View File

@ -1,8 +0,0 @@
package org.warp.commonutils.functional;
import java.io.IOException;
public interface IOFunction<T, U> {
U apply(T data) throws IOException;
}

View File

@ -1,8 +0,0 @@
package org.warp.commonutils.functional;
import java.io.IOException;
public interface IOIntegerSupplier {
int get() throws IOException;
}

View File

@ -1,8 +0,0 @@
package org.warp.commonutils.functional;
import java.io.IOException;
public interface IOLongSupplier {
long get() throws IOException;
}

View File

@ -1,8 +0,0 @@
package org.warp.commonutils.functional;
import java.io.IOException;
public interface IORunnable {
void run() throws IOException;
}

View File

@ -1,8 +0,0 @@
package org.warp.commonutils.functional;
import java.io.IOException;
public interface IOSupplier<T> {
T get() throws IOException;
}

View File

@ -1,55 +0,0 @@
package org.warp.commonutils.functional;
import java.io.IOException;
import java.util.Objects;
import java.util.function.Consumer;
/**
* Represents an operation that accepts three input arguments and returns no
* result. This is the three-arity specialization of {@link Consumer}.
* Unlike most other functional interfaces, {@code TriConsumer} is expected
* to operate via side-effects.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #accept(Object, Object, Object)}.
*
* @param <T> the type of the first argument to the operation
* @param <U> the type of the second argument to the operation
* @param <U> the type of the thord argument to the operation
*
* @see Consumer
* @since 1.8
*/
@FunctionalInterface
public interface IOTriConsumer<T, U, V> {
/**
* Performs this operation on the given arguments.
*
* @param t the first input argument
* @param u the second input argument
* @param v the third input argument
*/
void accept(T t, U u, V v) throws IOException;
/**
* Returns a composed {@code TriConsumer} that performs, in sequence, this
* operation followed by the {@code after} operation. If performing either
* operation throws an exception, it is relayed to the caller of the
* composed operation. If performing this operation throws an exception,
* the {@code after} operation will not be performed.
*
* @param after the operation to perform after this operation
* @return a composed {@code TriConsumer} that performs in sequence this
* operation followed by the {@code after} operation
* @throws NullPointerException if {@code after} is null
*/
default IOTriConsumer<T, U, V> andThen(IOTriConsumer<? super T, ? super U, ? super V> after) {
Objects.requireNonNull(after);
return (l, r, u) -> {
accept(l, r, u);
after.accept(l, r, u);
};
}
}

View File

@ -1,54 +0,0 @@
package org.warp.commonutils.functional;
import java.util.Objects;
import java.util.function.Consumer;
/**
* Represents an operation that accepts three input arguments and returns no
* result. This is the three-arity specialization of {@link Consumer}.
* Unlike most other functional interfaces, {@code TriConsumer} is expected
* to operate via side-effects.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #accept(Object, Object, Object)}.
*
* @param <T> the type of the first argument to the operation
* @param <U> the type of the second argument to the operation
* @param <U> the type of the thord argument to the operation
*
* @see Consumer
* @since 1.8
*/
@FunctionalInterface
public interface TriConsumer<T, U, V> {
/**
* Performs this operation on the given arguments.
*
* @param t the first input argument
* @param u the second input argument
* @param v the third input argument
*/
void accept(T t, U u, V v);
/**
* Returns a composed {@code TriConsumer} that performs, in sequence, this
* operation followed by the {@code after} operation. If performing either
* operation throws an exception, it is relayed to the caller of the
* composed operation. If performing this operation throws an exception,
* the {@code after} operation will not be performed.
*
* @param after the operation to perform after this operation
* @return a composed {@code TriConsumer} that performs in sequence this
* operation followed by the {@code after} operation
* @throws NullPointerException if {@code after} is null
*/
default org.warp.commonutils.functional.TriConsumer<T, U, V> andThen(org.warp.commonutils.functional.TriConsumer<? super T, ? super U, ? super V> after) {
Objects.requireNonNull(after);
return (l, r, u) -> {
accept(l, r, u);
after.accept(l, r, u);
};
}
}

View File

@ -1,51 +0,0 @@
package org.warp.commonutils.functional;
import java.util.Objects;
import java.util.function.Function;
/**
* Represents a function that accepts three arguments and produces a result.
* This is the three-arity specialization of {@link Function}.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #apply(Object, Object, Object)}.
*
* @param <T> the type of the first argument to the function
* @param <U> the type of the second argument to the function
* @param <X> the type of the third argument to the function
* @param <R> the type of the result of the function
*
* @see Function
* @since 1.8
*/
@FunctionalInterface
public interface TriFunction<T, U, X, R> {
/**
* Applies this function to the given arguments.
*
* @param t the first function argument
* @param u the second function argument
* @param x the third function argument
* @return the function result
*/
R apply(T t, U u, X x);
/**
* Returns a composed function that first applies this function to
* its input, and then applies the {@code after} function to the result.
* If evaluation of either function throws an exception, it is relayed to
* the caller of the composed function.
*
* @param <V> the type of output of the {@code after} function, and of the
* composed function
* @param after the function to apply after this function is applied
* @return a composed function that first applies this function and then
* applies the {@code after} function
* @throws NullPointerException if after is null
*/
default <V> org.warp.commonutils.functional.TriFunction<T, U, X, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t, U u, X x) -> after.apply(apply(t, u, x));
}
}

View File

@ -1,193 +0,0 @@
package org.warp.commonutils.locks;
import java.io.IOException;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.StampedLock;
import java.util.function.Supplier;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.warp.commonutils.functional.IORunnable;
import org.warp.commonutils.functional.IOSupplier;
public class LockUtils {
public static void lock(@Nullable Lock lock, @NotNull Runnable r) {
if (lock != null) {
lock.lock();
}
try {
r.run();
} finally {
if (lock != null) {
lock.unlock();
}
}
}
public static void readLock(@Nullable StampedLock lock, @NotNull Runnable r) {
long lockValue;
if (lock != null) {
lockValue = lock.readLock();
} else {
lockValue = 0;
}
try {
r.run();
} finally {
if (lock != null) {
lock.unlockRead(lockValue);
}
}
}
public static void writeLock(@Nullable StampedLock lock, @NotNull Runnable r) {
long lockValue;
if (lock != null) {
lockValue = lock.writeLock();
} else {
lockValue = 0;
}
try {
r.run();
} finally {
if (lock != null) {
lock.unlockWrite(lockValue);
}
}
}
public static void lockIO(@Nullable Lock lock, @NotNull IORunnable r) throws IOException {
if (lock != null) {
lock.lock();
}
try {
r.run();
} finally {
if (lock != null) {
lock.unlock();
}
}
}
public static void readLockIO(@Nullable StampedLock lock, @NotNull IORunnable r) throws IOException {
long lockValue;
if (lock != null) {
lockValue = lock.readLock();
} else {
lockValue = 0;
}
try {
r.run();
} finally {
if (lock != null) {
lock.unlockRead(lockValue);
}
}
}
public static void writeLockIO(@Nullable StampedLock lock, @NotNull IORunnable r) throws IOException {
long lockValue;
if (lock != null) {
lockValue = lock.writeLock();
} else {
lockValue = 0;
}
try {
r.run();
} finally {
if (lock != null) {
lock.unlockWrite(lockValue);
}
}
}
public static <T> T lock(@Nullable Lock lock, @NotNull Supplier<T> r) {
if (lock != null) {
lock.lock();
}
try {
return r.get();
} finally {
if (lock != null) {
lock.unlock();
}
}
}
public static <T> T readLock(@Nullable StampedLock lock, @NotNull Supplier<T> r) {
long lockValue;
if (lock != null) {
lockValue = lock.readLock();
} else {
lockValue = 0;
}
try {
return r.get();
} finally {
if (lock != null) {
lock.unlockRead(lockValue);
}
}
}
public static <T> T writeLock(@Nullable StampedLock lock, @NotNull Supplier<T> r) {
long lockValue;
if (lock != null) {
lockValue = lock.writeLock();
} else {
lockValue = 0;
}
try {
return r.get();
} finally {
if (lock != null) {
lock.unlockWrite(lockValue);
}
}
}
public static <T> T lockIO(@Nullable Lock lock, @NotNull IOSupplier<T> r) throws IOException {
if (lock != null) {
lock.lock();
}
try {
return r.get();
} finally {
if (lock != null) {
lock.unlock();
}
}
}
public static <T> T readLockIO(@Nullable StampedLock lock, @NotNull IOSupplier<T> r) throws IOException {
long lockValue;
if (lock != null) {
lockValue = lock.readLock();
} else {
lockValue = 0;
}
try {
return r.get();
} finally {
if (lock != null) {
lock.unlockRead(lockValue);
}
}
}
public static <T> T writeLockIO(@Nullable StampedLock lock, @NotNull IOSupplier<T> r) throws IOException {
long lockValue;
if (lock != null) {
lockValue = lock.writeLock();
} else {
lockValue = 0;
}
try {
return r.get();
} finally {
if (lock != null) {
lock.unlockWrite(lockValue);
}
}
}
}

View File

@ -1,40 +0,0 @@
package org.warp.commonutils.moshi;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.JsonReader;
import com.squareup.moshi.JsonWriter;
import it.unimi.dsi.fastutil.booleans.BooleanArrayList;
import it.unimi.dsi.fastutil.booleans.BooleanList;
import it.unimi.dsi.fastutil.booleans.BooleanLists;
import it.unimi.dsi.fastutil.bytes.ByteArrayList;
import java.io.IOException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class BooleanListJsonAdapter extends JsonAdapter<BooleanList> {
@Override
public @NotNull BooleanList fromJson(@NotNull JsonReader reader) throws IOException {
reader.beginArray();
BooleanArrayList modifiableOutput = new BooleanArrayList();
while (reader.hasNext()) {
modifiableOutput.add(reader.nextBoolean());
}
reader.endArray();
return BooleanLists.unmodifiable(modifiableOutput);
}
@Override
public void toJson(@NotNull JsonWriter writer, @Nullable BooleanList value) throws IOException {
if (value == null) {
writer.nullValue();
return;
}
writer.beginArray();
for (int i = 0; i < value.size(); i++) {
writer.value(value.getBoolean(i));
}
writer.endArray();
}
}

View File

@ -1,39 +0,0 @@
package org.warp.commonutils.moshi;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.JsonReader;
import com.squareup.moshi.JsonWriter;
import it.unimi.dsi.fastutil.bytes.ByteArrayList;
import it.unimi.dsi.fastutil.bytes.ByteList;
import it.unimi.dsi.fastutil.bytes.ByteLists;
import java.io.IOException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class ByteListJsonAdapter extends JsonAdapter<ByteList> {
@Override
public @NotNull ByteList fromJson(@NotNull JsonReader reader) throws IOException {
reader.beginArray();
ByteArrayList modifiableOutput = new ByteArrayList();
while (reader.hasNext()) {
modifiableOutput.add((byte) reader.nextInt());
}
reader.endArray();
return ByteLists.unmodifiable(modifiableOutput);
}
@Override
public void toJson(@NotNull JsonWriter writer, @Nullable ByteList value) throws IOException {
if (value == null) {
writer.nullValue();
return;
}
writer.beginArray();
for (int i = 0; i < value.size(); i++) {
writer.value((long) value.getByte(i));
}
writer.endArray();
}
}

View File

@ -1,39 +0,0 @@
package org.warp.commonutils.moshi;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.JsonReader;
import com.squareup.moshi.JsonWriter;
import it.unimi.dsi.fastutil.chars.CharArrayList;
import it.unimi.dsi.fastutil.chars.CharList;
import it.unimi.dsi.fastutil.chars.CharLists;
import java.io.IOException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class CharListJsonAdapter extends JsonAdapter<CharList> {
@Override
public @NotNull CharList fromJson(@NotNull JsonReader reader) throws IOException {
reader.beginArray();
CharArrayList modifiableOutput = new CharArrayList();
while (reader.hasNext()) {
modifiableOutput.add((char) reader.nextInt());
}
reader.endArray();
return CharLists.unmodifiable(modifiableOutput);
}
@Override
public void toJson(@NotNull JsonWriter writer, @Nullable CharList value) throws IOException {
if (value == null) {
writer.nullValue();
return;
}
writer.beginArray();
for (int i = 0; i < value.size(); i++) {
writer.value((long) value.getChar(i));
}
writer.endArray();
}
}

View File

@ -1,39 +0,0 @@
package org.warp.commonutils.moshi;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.JsonReader;
import com.squareup.moshi.JsonWriter;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import it.unimi.dsi.fastutil.ints.IntLists;
import java.io.IOException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class IntListJsonAdapter extends JsonAdapter<IntList> {
@Override
public @NotNull IntList fromJson(@NotNull JsonReader reader) throws IOException {
reader.beginArray();
IntArrayList modifiableOutput = new IntArrayList();
while (reader.hasNext()) {
modifiableOutput.add(reader.nextInt());
}
reader.endArray();
return IntLists.unmodifiable(modifiableOutput);
}
@Override
public void toJson(@NotNull JsonWriter writer, @Nullable IntList value) throws IOException {
if (value == null) {
writer.nullValue();
return;
}
writer.beginArray();
for (int i = 0; i < value.size(); i++) {
writer.value((long) value.getInt(i));
}
writer.endArray();
}
}

View File

@ -1,39 +0,0 @@
package org.warp.commonutils.moshi;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.JsonReader;
import com.squareup.moshi.JsonWriter;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.longs.LongList;
import it.unimi.dsi.fastutil.longs.LongLists;
import java.io.IOException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class LongListJsonAdapter extends JsonAdapter<LongList> {
@Override
public @NotNull LongList fromJson(@NotNull JsonReader reader) throws IOException {
reader.beginArray();
LongArrayList modifiableOutput = new LongArrayList();
while (reader.hasNext()) {
modifiableOutput.add(reader.nextLong());
}
reader.endArray();
return LongLists.unmodifiable(modifiableOutput);
}
@Override
public void toJson(@NotNull JsonWriter writer, @Nullable LongList value) throws IOException {
if (value == null) {
writer.nullValue();
return;
}
writer.beginArray();
for (int i = 0; i < value.size(); i++) {
writer.value(value.getLong(i));
}
writer.endArray();
}
}

View File

@ -1,373 +0,0 @@
package org.warp.commonutils.moshi;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.JsonDataException;
import com.squareup.moshi.JsonReader;
import com.squareup.moshi.JsonReader.Options;
import com.squareup.moshi.JsonWriter;
import com.squareup.moshi.Moshi;
import com.squareup.moshi.Types;
import dev.zacsweers.moshix.records.RecordsJsonAdapterFactory;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.warp.commonutils.serialization.UTFUtils;
public abstract class MoshiPolymorphic<OBJ> {
public enum GetterStyle {
FIELDS,
RECORDS_GETTERS,
STANDARD_GETTERS
}
private final boolean instantiateUsingStaticOf;
private final GetterStyle getterStyle;
private boolean initialized = false;
private Moshi abstractMoshi;
private final Map<Type, JsonAdapter<OBJ>> abstractClassesSerializers = new ConcurrentHashMap<>();
private final Map<Type, JsonAdapter<List<OBJ>>> abstractListClassesSerializers = new ConcurrentHashMap<>();
private final Map<Type, JsonAdapter<OBJ>> concreteClassesSerializers = new ConcurrentHashMap<>();
private final Map<Type, JsonAdapter<List<OBJ>>> concreteListClassesSerializers = new ConcurrentHashMap<>();
private final Map<Type, JsonAdapter<?>> extraClassesSerializers = new ConcurrentHashMap<>();
private final Map<String, JsonAdapter<OBJ>> customAdapters = new ConcurrentHashMap<>();
public MoshiPolymorphic() {
this(false, GetterStyle.FIELDS);
}
public MoshiPolymorphic(boolean instantiateUsingStaticOf, GetterStyle getterStyle) {
this.instantiateUsingStaticOf = instantiateUsingStaticOf;
this.getterStyle = getterStyle;
}
private synchronized void initialize() {
if (!this.initialized) {
this.initialized = true;
var abstractMoshiBuilder = new Moshi.Builder();
var abstractClasses = getAbstractClasses();
var concreteClasses = getConcreteClasses();
var extraAdapters = getExtraAdapters();
extraAdapters.forEach((extraClass, jsonAdapter) -> {
extraClassesSerializers.put(extraClass, jsonAdapter);
abstractMoshiBuilder.add(extraClass, jsonAdapter);
});
for (Class<?> declaredClass : abstractClasses) {
var name = fixType(declaredClass.getSimpleName());
JsonAdapter<OBJ> adapter = new PolymorphicAdapter<>(name);
if (!extraClassesSerializers.containsKey(declaredClass)) {
abstractMoshiBuilder.add(declaredClass, adapter);
abstractClassesSerializers.put(declaredClass, adapter);
abstractListClassesSerializers.put(Types.newParameterizedType(List.class, declaredClass),
new ListValueAdapter<>(adapter)
);
}
customAdapters.put(name, adapter);
}
for (Class<?> declaredClass : concreteClasses) {
var name = fixType(declaredClass.getSimpleName());
JsonAdapter<OBJ> adapter = new NormalValueAdapter<>(name, declaredClass);
if (!extraClassesSerializers.containsKey(declaredClass)
&& !abstractClassesSerializers.containsKey(declaredClass)) {
concreteClassesSerializers.put(declaredClass, adapter);
concreteListClassesSerializers.put(Types.newParameterizedType(List.class, declaredClass),
new ListValueAdapter<>(adapter)
);
abstractMoshiBuilder.add(declaredClass, adapter);
}
customAdapters.put(name, adapter);
}
abstractMoshiBuilder.addLast(new RecordsJsonAdapterFactory());
abstractMoshi = abstractMoshiBuilder.build();
}
}
protected abstract Set<Class<OBJ>> getAbstractClasses();
protected abstract Set<Class<OBJ>> getConcreteClasses();
protected Map<Class<?>, JsonAdapter<?>> getExtraAdapters() {
return Map.of();
}
protected abstract boolean shouldIgnoreField(String fieldName);
public Moshi.Builder registerAdapters(Moshi.Builder moshiBuilder) {
initialize();
extraClassesSerializers.forEach(moshiBuilder::add);
abstractClassesSerializers.forEach(moshiBuilder::add);
abstractListClassesSerializers.forEach(moshiBuilder::add);
concreteClassesSerializers.forEach(moshiBuilder::add);
concreteListClassesSerializers.forEach(moshiBuilder::add);
return moshiBuilder;
}
private class PolymorphicAdapter<T> extends JsonAdapter<T> {
private final String adapterName;
private PolymorphicAdapter(String adapterName) {
this.adapterName = adapterName;
}
private final Options NAMES = Options.of("type", "properties");
@Nullable
@Override
public T fromJson(@NotNull JsonReader jsonReader) throws IOException {
String type = null;
jsonReader.beginObject();
iterate: while (jsonReader.hasNext()) {
switch (jsonReader.selectName(NAMES)) {
case 0:
type = fixType(jsonReader.nextString());
break;
case 1:
if (type == null) {
throw new JsonDataException("Type must be defined before properties");
}
break iterate;
default:
String name = jsonReader.nextName();
throw new JsonDataException("Key \"" + name + "\" is invalid");
}
}
JsonAdapter<? extends OBJ> propertiesAdapter = customAdapters.get(type);
if (propertiesAdapter == null) {
throw new JsonDataException("Type \"" + type + "\" is unknown");
}
//noinspection unchecked
var result = (T) propertiesAdapter.fromJson(jsonReader);
jsonReader.endObject();
return result;
}
@Override
public void toJson(@NotNull JsonWriter jsonWriter, @Nullable T t) throws IOException {
if (t == null) {
jsonWriter.nullValue();
} else {
String type = fixType(t.getClass().getSimpleName());
JsonAdapter<OBJ> propertiesAdapter = customAdapters.get(type);
if (propertiesAdapter == null) {
abstractMoshi.adapter(java.lang.Object.class).toJson(jsonWriter, t);
} else {
jsonWriter.beginObject();
jsonWriter.name("type").value(type);
jsonWriter.name("properties");
//noinspection unchecked
propertiesAdapter.toJson(jsonWriter, (OBJ) t);
jsonWriter.endObject();
}
}
}
}
private class NormalValueAdapter<T> extends JsonAdapter<T> {
private final String adapterName;
private final Options names;
private final Class<?> declaredClass;
private final List<Field> declaredFields;
private final Function<T, Object>[] fieldGetters;
private NormalValueAdapter(String adapterName, Class<?> declaredClass) {
try {
this.adapterName = adapterName;
this.declaredClass = declaredClass;
this.declaredFields = Arrays
.stream(declaredClass.getDeclaredFields())
.filter(field -> {
var modifiers = field.getModifiers();
return !Modifier.isStatic(modifiers)
&& !Modifier.isTransient(modifiers)
&& !shouldIgnoreField(field.getName());
})
.collect(Collectors.toList());
String[] fieldNames = new String[this.declaredFields.size()];
//noinspection unchecked
this.fieldGetters = new Function[this.declaredFields.size()];
int i = 0;
for (Field declaredField : this.declaredFields) {
fieldNames[i] = declaredField.getName();
switch (getterStyle) {
case STANDARD_GETTERS:
var getterMethod = declaredField
.getDeclaringClass()
.getMethod("get" + StringUtils.capitalize(declaredField.getName()));
fieldGetters[i] = obj -> {
try {
return getterMethod.invoke(obj);
} catch (InvocationTargetException | IllegalAccessException e) {
throw new RuntimeException(e);
}
};
break;
case RECORDS_GETTERS:
var getterMethod2 = declaredField
.getDeclaringClass()
.getMethod(declaredField.getName());
fieldGetters[i] = obj -> {
try {
return getterMethod2.invoke(obj);
} catch (InvocationTargetException | IllegalAccessException e) {
throw new RuntimeException(e);
}
};
break;
case FIELDS:
fieldGetters[i] = t -> {
try {
return declaredField.get(t);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
};
break;
}
i++;
} this.names = Options.of(fieldNames);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
@Nullable
@Override
public T fromJson(@NotNull JsonReader jsonReader) throws IOException {
try {
Object instance;
Object[] fields;
if (instantiateUsingStaticOf) {
fields = new Object[declaredFields.size()];
instance = null;
} else {
fields = null;
instance = declaredClass.getConstructor().newInstance();
}
jsonReader.beginObject();
while (jsonReader.hasNext()) {
var nameId = jsonReader.selectName(names);
if (nameId >= 0 && nameId < this.declaredFields.size()) {
var fieldValue = abstractMoshi.adapter(declaredFields.get(nameId).getGenericType()).fromJson(jsonReader);
if (instantiateUsingStaticOf) {
fields[nameId] = fieldValue;
} else {
declaredFields.get(nameId).set(instance, fieldValue);
}
} else {
String keyName = jsonReader.nextName();
throw new JsonDataException("Key \"" + keyName + "\" is invalid");
}
}
jsonReader.endObject();
if (instantiateUsingStaticOf) {
Class[] params = new Class[declaredFields.size()];
for (int i = 0; i < declaredFields.size(); i++) {
params[i] = declaredFields.get(i).getType();
}
instance = declaredClass.getMethod("of", params).invoke(null, fields);
}
//noinspection unchecked
return (T) instance;
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
throw new JsonDataException(e);
}
}
@Override
public void toJson(@NotNull JsonWriter jsonWriter, @Nullable T t) throws IOException {
if (t == null) {
jsonWriter.nullValue();
} else {
jsonWriter.beginObject();
int i = 0;
for (Field declaredField : declaredFields) {
jsonWriter.name(declaredField.getName());
Class<?> fieldType = declaredField.getType();
if (abstractClassesSerializers.containsKey(fieldType)) {
//noinspection unchecked
abstractClassesSerializers.<OBJ>get(fieldType).toJson(jsonWriter, (OBJ) fieldGetters[i].apply(t));
} else if (concreteClassesSerializers.containsKey(fieldType)) {
//noinspection unchecked
concreteClassesSerializers.<OBJ>get(fieldType).toJson(jsonWriter, (OBJ) fieldGetters[i].apply(t));
} else {
abstractMoshi.<Object>adapter(fieldType).toJson(jsonWriter, fieldGetters[i].apply(t));
}
i++;
}
jsonWriter.endObject();
}
}
}
private static class ListValueAdapter<T> extends JsonAdapter<List<T>> {
private final JsonAdapter<T> valueAdapter;
public ListValueAdapter(JsonAdapter<T> valueAdapter) {
this.valueAdapter = valueAdapter;
}
@Nullable
@Override
public List<T> fromJson(@NotNull JsonReader jsonReader) throws IOException {
jsonReader.beginArray();
var result = new ArrayList<T>();
while (jsonReader.hasNext()) {
result.add(valueAdapter.fromJson(jsonReader));
}
jsonReader.endArray();
return Collections.unmodifiableList(result);
}
@Override
public void toJson(@NotNull JsonWriter jsonWriter, @Nullable List<T> ts) throws IOException {
if (ts == null) {
jsonWriter.nullValue();
} else {
jsonWriter.beginArray();
for (T value : ts) {
valueAdapter.toJson(jsonWriter.valueSink(), value);
}
jsonWriter.endArray();
}
}
}
private static String fixType(String nextString) {
if (nextString.length() > 512) {
throw new IllegalArgumentException("Input too long: " + nextString.length());
}
return UTFUtils.keepOnlyASCII(nextString);
}
}

View File

@ -1,39 +0,0 @@
package org.warp.commonutils.moshi;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.JsonReader;
import com.squareup.moshi.JsonWriter;
import it.unimi.dsi.fastutil.shorts.ShortArrayList;
import it.unimi.dsi.fastutil.shorts.ShortList;
import it.unimi.dsi.fastutil.shorts.ShortLists;
import java.io.IOException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class ShortListJsonAdapter extends JsonAdapter<ShortList> {
@Override
public @NotNull ShortList fromJson(@NotNull JsonReader reader) throws IOException {
reader.beginArray();
ShortArrayList modifiableOutput = new ShortArrayList();
while (reader.hasNext()) {
modifiableOutput.add((short) reader.nextInt());
}
reader.endArray();
return ShortLists.unmodifiable(modifiableOutput);
}
@Override
public void toJson(@NotNull JsonWriter writer, @Nullable ShortList value) throws IOException {
if (value == null) {
writer.nullValue();
return;
}
writer.beginArray();
for (int i = 0; i < value.size(); i++) {
writer.value((long) value.getShort(i));
}
writer.endArray();
}
}

View File

@ -1,137 +0,0 @@
package org.warp.commonutils.random;
import java.math.BigInteger;
import java.util.Iterator;
import java.util.Random;
import org.jetbrains.annotations.NotNull;
/**
* Linear feedback shift register
* <p>
* Taps can be found at: See http://www.xilinx.com/support/documentation/application_notes/xapp052.pdf See
* http://mathoverflow.net/questions/46961/how-are-taps-proven-to-work-for-lfsrs/46983#46983 See
* http://www.newwaveinstruments.com/resources/articles/m_sequence_linear_feedback_shift_register_lfsr.htm See
* http://www.yikes.com/~ptolemy/lfsr_web/index.htm See http://seanerikoconnor.freeservers.com/Mathematics/AbstractAlgebra/PrimitivePolynomials/overview.html
*
* @author OldCurmudgeon
*/
public class LFSR implements Iterable<BigInteger> {
private static final Random random = new Random();
// Bit pattern for taps.
private final BigInteger taps;
// Where to start (and end).
private final BigInteger start;
public static LFSR randomInt() {
return random(32, random.nextInt());
}
public static LFSR randomLong() {
return random(64, random.nextLong());
}
public static LFSR randomPositiveLong() {
return random(50, Math.abs(random.nextInt()));
}
public static BigInteger randomPrimitive(int bitsSize) {
// Build the BigInteger.
BigInteger primitive = BigInteger.ZERO;
for (int bitNumber = 0; bitNumber <= bitsSize; bitNumber++) {
if (random.nextBoolean() || bitNumber == 0 || bitNumber == bitsSize) {
primitive = primitive.or(BigInteger.ONE.shiftLeft(bitNumber));
}
}
return primitive;
}
public static LFSR random(int bitsSize, long startNumber) {
return new LFSR(randomPrimitive(bitsSize), BigInteger.valueOf(startNumber));
}
// The poly must be primitive to span the full sequence.
public LFSR(BigInteger primitivePoly, BigInteger start) {
// Where to start from (and stop).
this.start = start.equals(BigInteger.ZERO) ? BigInteger.ONE : start;
// Knock off the 2^0 coefficient of the polynomial for the TAP.
this.taps = primitivePoly.shiftRight(1);
}
@NotNull
@Override
public LFSRIterator iterator() {
return new LFSRIterator(start);
}
public class LFSRIterator implements Iterator<BigInteger> {
// The last one we returned.
private BigInteger last = null;
// The next one to return.
private BigInteger next = null;
public LFSRIterator(BigInteger start) {
// Do not return the seed.
last = start;
}
@Override
public boolean hasNext() {
if (next == null) {
/*
* Uses the Galois form.
*
* Shift last right one.
*
* If the bit shifted out was a 1 - xor with the tap mask.
*/
boolean shiftedOutA1 = last.testBit(0);
// Shift right.
next = last.shiftRight(1);
if (shiftedOutA1) {
// Tap!
next = next.xor(taps);
}
// Never give them `start` again.
if (next.equals(start)) {
// Could set a finished flag here too.
next = null;
}
}
return next != null;
}
@Override
public BigInteger next() {
// Remember this one.
last = hasNext() ? next : null;
// Don't deliver it again.
next = null;
return last;
}
public BigInteger next(BigInteger last) {
this.last = last;
next = null;
return next();
}
@Override
public void remove() {
throw new UnsupportedOperationException("Not supported.");
}
@Override
public String toString() {
return LFSR.this.toString() + "[" + (last != null ? last.toString(16) : "") + "-" + (next != null ? next
.toString(16) : "") + "]";
}
}
@Override
public String toString() {
return "(" + taps.toString(32) + ")-" + start.toString(32);
}
}

View File

@ -1,121 +0,0 @@
package org.warp.commonutils.range;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectMaps;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectRBTreeMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectSortedMap;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import java.util.Comparator;
import java.util.function.Function;
public class MappedRanges<T> {
private final Object2ObjectMap<Range, T> ranges;
public MappedRanges(int start, int end, T value) {
if (start > end) {
throw new IndexOutOfBoundsException();
}
this.ranges = new Object2ObjectOpenHashMap<>();
ranges.put(new Range(start, end), value);
}
public void deleteRange(final int start, final int end, Function<T, T> replaceWhenSplitting, Function<T, T> cloneWhenSplitting) {
if (start > end) {
throw new IndexOutOfBoundsException();
}
Object2ObjectOpenHashMap<Range, T> rangesToAdd = new Object2ObjectOpenHashMap<>();
ObjectOpenHashSet<Range> rangesToDelete = new ObjectOpenHashSet<>();
ranges.forEach((range, value) -> {
if (range.start <= end && range.end >= start) {
if (range.start >= start && range.end <= end) {
// delete the range
rangesToDelete.add(range);
} else if (range.start <= start && range.end >= end) {
// cut the hole
rangesToDelete.add(range);
rangesToAdd.put(new Range(range.start, start), value);
rangesToAdd.put(new Range(end, range.end), cloneWhenSplitting.apply(value));
} else if (range.start <= start && range.end <= end && range.end > start) {
// shrink the right border
rangesToDelete.add(range);
rangesToAdd.put(new Range(range.start, start), value);
} else if (range.start >= start && range.end >= end && range.start < end) {
// shrink the left border
rangesToDelete.add(range);
rangesToAdd.put(new Range(end, range.end), value);
}
}
});
for (Range range : rangesToDelete) {
ranges.remove(range);
}
rangesToAdd.forEach((range, value) -> {
if (canAddRange(range)) {
ranges.put(range, replaceWhenSplitting.apply(value));
}
});
}
public void transformRange(int start, int end, Function<T, T> replaceWhenOverlapping, Function<T, T> cloneWhenSplitting) {
if (start > end) {
throw new IndexOutOfBoundsException();
}
Object2ObjectOpenHashMap<Range, T> rangesToTransform = new Object2ObjectOpenHashMap<>();
Object2ObjectOpenHashMap<Range, T> rangesToAdd = new Object2ObjectOpenHashMap<>();
ObjectOpenHashSet<Range> rangesToRemove = new ObjectOpenHashSet<>();
ranges.forEach((range, value) -> {
if (range.start <= end && range.end >= start) {
if (range.start >= start && range.end <= end) {
// transform the range
rangesToTransform.put(range, replaceWhenOverlapping.apply(value));
} else if (range.start <= start && range.end >= end) {
// transform the middle
rangesToRemove.add(range);
rangesToAdd.put(new Range(range.start, start), value);
rangesToTransform.put(new Range(start, end), replaceWhenOverlapping.apply(cloneWhenSplitting.apply(value)));
rangesToAdd.put(new Range(end, range.end), cloneWhenSplitting.apply(value));
} else if (range.start <= start && range.end <= end && range.end > start) {
// transform the right
rangesToRemove.add(range);
rangesToAdd.put(new Range(range.start, start), value);
rangesToTransform.put(new Range(start, range.end), replaceWhenOverlapping.apply(cloneWhenSplitting.apply(value)));
} else if (range.start >= start && range.end >= end && range.start < end) {
// transform the left
rangesToRemove.add(range);
rangesToTransform.put(new Range(range.start, end), replaceWhenOverlapping.apply(cloneWhenSplitting.apply(value)));
rangesToAdd.put(new Range(end, range.end), value);
} else {
// do not transform
}
}
});
rangesToRemove.forEach((range) -> {
ranges.remove(range);
});
rangesToAdd.forEach((range, value) -> {
if (canAddRange(range)) {
ranges.put(range, value);
}
});
rangesToTransform.forEach((range, value) -> {
ranges.put(range, value);
});
}
private boolean canAddRange(UnmodifiableRange range) {
return range.getStart() != range.getEnd();
}
private boolean canAddRange(Range range) {
return range.getStart() != range.getEnd();
}
public Object2ObjectMap<UnmodifiableRange, T> getRanges() {
Object2ObjectSortedMap<UnmodifiableRange, T> a = new Object2ObjectRBTreeMap<>(Comparator.comparingLong(UnmodifiableRange::getStart));
ranges.forEach((range, value) -> a.put(range.unmodifiableClone(), value));
return Object2ObjectMaps.unmodifiable(a);
}
}

View File

@ -1,60 +0,0 @@
package org.warp.commonutils.range;
import java.util.Objects;
import java.util.StringJoiner;
import org.warp.commonutils.error.IndexOutOfBoundsException;
public class Range {
public long start;
public long end;
public Range(long start, long end) {
if (start > end) {
throw new IndexOutOfBoundsException(start, 0, end);
}
this.start = start;
this.end = end;
}
public long getStart() {
return start;
}
public long getEnd() {
return end;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Range range = (Range) o;
return start == range.start && end == range.end;
}
@Override
public int hashCode() {
return Objects.hash(start, end);
}
@Override
public String toString() {
return new StringJoiner(", ", Range.class.getSimpleName() + "[", "]").add("start=" + start).add("end=" + end)
.toString();
}
@SuppressWarnings("MethodDoesntCallSuperMethod")
@Override
public Range clone() {
return new Range(start, end);
}
public UnmodifiableRange unmodifiableClone() {
return new UnmodifiableRange(start, end);
}
}

View File

@ -1,104 +0,0 @@
package org.warp.commonutils.range;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectRBTreeSet;
import it.unimi.dsi.fastutil.objects.ObjectSortedSet;
import it.unimi.dsi.fastutil.objects.ObjectSortedSets;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import org.warp.commonutils.error.IndexOutOfBoundsException;
public class Ranges {
private final ObjectArrayList<Range> ranges;
public Ranges(long start, long end) {
if (start > end) {
throw new IndexOutOfBoundsException(start, 0, end);
}
this.ranges = new ObjectArrayList<>();
ranges.add(new Range(start, end));
}
public void addRange(Range range) {
addRange(range.start, range.end);
}
public void addRange(long start, long end) {
if (start > end) {
throw new IndexOutOfBoundsException(start, 0, end);
}
long rangeStart = start;
long rangeEnd = end;
var it = ranges.iterator();
while (it.hasNext()) {
Range range = it.next();
if (range.start <= end && range.end >= start) {
boolean remove = false;
if (range.start < rangeStart && range.end >= rangeStart) {
rangeStart = range.start;
remove = true;
}
if (range.end > rangeEnd && range.start <= rangeEnd) {
rangeEnd = range.end;
remove = true;
}
if (remove) {
it.remove();
}
}
}
addRangeIfNotZero(new Range(rangeStart, rangeEnd));
}
public void deleteRange(final long start, final long end) {
if (start > end) {
throw new IndexOutOfBoundsException(start);
}
List<Range> rangesToAdd = new ArrayList<>(ranges.size());
var it = ranges.iterator();
while (it.hasNext()) {
Range range = it.next();
if (range.start <= end && range.end >= start) {
if (range.start >= start && range.end <= end) {
// delete the range
it.remove();
} else if (range.start <= start && range.end >= end) {
// cut the hole
it.remove();
rangesToAdd.add(new Range(range.start, start));
rangesToAdd.add(new Range(end, range.end));
} else if (range.start <= start && range.end <= end && range.end > start) {
// shrink the right border
it.remove();
rangesToAdd.add(new Range(range.start, start));
} else if (range.start >= start && range.end >= end && range.start < end) {
// shrink the left border
it.remove();
rangesToAdd.add(new Range(end, range.end));
}
}
}
for (Range rangeToAdd : rangesToAdd) {
addRangeIfNotZero(rangeToAdd);
}
}
/**
* This methods does not check overlapping ranges! It's used only internally to skip empty ranges
*
* @param range
*/
private void addRangeIfNotZero(Range range) {
if (range.start != range.end) {
ranges.add(range);
}
}
public ObjectSortedSet<UnmodifiableRange> getRanges() {
ObjectSortedSet<UnmodifiableRange> a = new ObjectRBTreeSet<>(Comparator.comparingLong(UnmodifiableRange::getStart));
ranges.forEach((range) -> a.add(range.unmodifiableClone()));
return ObjectSortedSets.unmodifiable(a);
}
}

View File

@ -1,54 +0,0 @@
package org.warp.commonutils.range;
import java.util.Objects;
import java.util.StringJoiner;
import org.warp.commonutils.error.IndexOutOfBoundsException;
public class UnmodifiableRange {
private final long start;
private final long end;
public UnmodifiableRange(long start, long end) {
if (start > end) {
throw new IndexOutOfBoundsException(start, 0, end);
}
this.start = start;
this.end = end;
}
public long getStart() {
return start;
}
public long getEnd() {
return end;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
UnmodifiableRange that = (UnmodifiableRange) o;
return start == that.start && end == that.end;
}
@Override
public int hashCode() {
return Objects.hash(start, end);
}
@Override
public String toString() {
return new StringJoiner(", ", UnmodifiableRange.class.getSimpleName() + "[", "]").add("start=" + start)
.add("end=" + end).toString();
}
public Range toRange() {
return new Range(start, end);
}
}

View File

@ -1,42 +0,0 @@
package org.warp.commonutils.serialization;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
public class UTFUtils {
public static void writeUTF(DataOutput out, String utf) throws IOException {
byte[] bytes = utf.getBytes(StandardCharsets.UTF_8);
out.writeInt(bytes.length);
out.write(bytes);
}
public static String readUTF(DataInput in) throws IOException {
int len = in.readInt();
byte[] data = new byte[len];
in.readFully(data, 0, len);
return new String(data, StandardCharsets.UTF_8);
}
/**
* Keep only ascii alphanumeric letters
*/
public static String keepOnlyASCII(String nextString) {
char[] chars = nextString.toCharArray();
//noinspection UnusedAssignment
nextString = null;
int writeIndex = 0;
char c;
for (int checkIndex = 0; checkIndex < chars.length; checkIndex++) {
c = chars[checkIndex];
if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
if (writeIndex != checkIndex) {
chars[writeIndex] = c;
}
writeIndex++;
}
}
return new String(chars, 0, writeIndex);
}
}

View File

@ -1,29 +0,0 @@
package org.warp.commonutils.stream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import org.jetbrains.annotations.NotNull;
/**
* Simple {@link InputStream} implementation that exposes currently
* available content of a {@link ByteBuffer}.
*/
public class ByteBufferBackedInputStream extends InputStream {
protected final ByteBuffer _b;
public ByteBufferBackedInputStream(ByteBuffer buf) { _b = buf; }
@Override public int available() { return _b.remaining(); }
@Override
public int read() throws IOException { return _b.hasRemaining() ? (_b.get() & 0xFF) : -1; }
@Override
public int read(byte @NotNull [] bytes, int off, int len) throws IOException {
if (!_b.hasRemaining()) return -1;
len = Math.min(len, _b.remaining());
_b.get(bytes, off, len);
return len;
}
}

View File

@ -1,11 +0,0 @@
package org.warp.commonutils.stream;
import java.io.DataInput;
import java.io.DataOutput;
public interface DataInputOutput extends DataInput, DataOutput {
DataInput getIn();
DataOutput getOut();
}

View File

@ -1,173 +0,0 @@
package org.warp.commonutils.stream;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.jetbrains.annotations.NotNull;
public class DataInputOutputImpl implements DataInputOutput {
private final DataInput in;
private final DataOutput out;
public DataInputOutputImpl(DataInput in, DataOutput out) {
this.in = in;
this.out = out;
}
@Override
public DataInput getIn() {
return this;
}
@Override
public DataOutput getOut() {
return this;
}
@Override
public void readFully(byte @NotNull [] bytes) throws IOException {
in.readFully(bytes);
}
@Override
public void readFully(byte @NotNull [] bytes, int i, int i1) throws IOException {
in.readFully(bytes, i, i1);
}
@Override
public int skipBytes(int i) throws IOException {
return in.skipBytes(i);
}
@Override
public boolean readBoolean() throws IOException {
return in.readBoolean();
}
@Override
public byte readByte() throws IOException {
return in.readByte();
}
@Override
public int readUnsignedByte() throws IOException {
return in.readUnsignedByte();
}
@Override
public short readShort() throws IOException {
return in.readShort();
}
@Override
public int readUnsignedShort() throws IOException {
return in.readUnsignedShort();
}
@Override
public char readChar() throws IOException {
return in.readChar();
}
@Override
public int readInt() throws IOException {
return in.readInt();
}
@Override
public long readLong() throws IOException {
return in.readLong();
}
@Override
public float readFloat() throws IOException {
return in.readFloat();
}
@Override
public double readDouble() throws IOException {
return in.readDouble();
}
@Override
public String readLine() throws IOException {
return in.readLine();
}
@NotNull
@Override
public String readUTF() throws IOException {
return in.readUTF();
}
@Override
public void write(int i) throws IOException {
out.write(i);
}
@Override
public void write(byte @NotNull [] bytes) throws IOException {
out.write(bytes);
}
@Override
public void write(byte @NotNull [] bytes, int i, int i1) throws IOException {
out.write(bytes, i, i1);
}
@Override
public void writeBoolean(boolean b) throws IOException {
out.writeBoolean(b);
}
@Override
public void writeByte(int i) throws IOException {
out.writeByte(i);
}
@Override
public void writeShort(int i) throws IOException {
out.writeShort(i);
}
@Override
public void writeChar(int i) throws IOException {
out.writeChar(i);
}
@Override
public void writeInt(int i) throws IOException {
out.writeInt(i);
}
@Override
public void writeLong(long l) throws IOException {
out.writeLong(l);
}
@Override
public void writeFloat(float v) throws IOException {
out.writeFloat(v);
}
@Override
public void writeDouble(double v) throws IOException {
out.writeDouble(v);
}
@Override
public void writeBytes(@NotNull String s) throws IOException {
out.writeBytes(s);
}
@Override
public void writeChars(@NotNull String s) throws IOException {
out.writeChars(s);
}
@Override
public void writeUTF(@NotNull String s) throws IOException {
out.writeUTF(s);
}
}

View File

@ -1,103 +0,0 @@
package org.warp.commonutils.stream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import org.jetbrains.annotations.NotNull;
public class DataInputOutputStream extends DataOutputStream implements DataInputOutput {
private final DataInputStream in;
public DataInputOutputStream(DataInputStream in, DataOutputStream out) {
super(out);
this.in = in;
}
@Override
public DataInputStream getIn() {
return in;
}
@Override
public DataOutputStream getOut() {
return this;
}
@Override
public void readFully(byte @NotNull [] bytes) throws IOException {
in.readFully(bytes);
}
@Override
public void readFully(byte @NotNull [] bytes, int i, int i1) throws IOException {
in.readFully(bytes, i, i1);
}
@Override
public int skipBytes(int i) throws IOException {
return in.skipBytes(i);
}
@Override
public boolean readBoolean() throws IOException {
return in.readBoolean();
}
@Override
public byte readByte() throws IOException {
return in.readByte();
}
@Override
public int readUnsignedByte() throws IOException {
return in.readUnsignedByte();
}
@Override
public short readShort() throws IOException {
return in.readShort();
}
@Override
public int readUnsignedShort() throws IOException {
return in.readUnsignedShort();
}
@Override
public char readChar() throws IOException {
return in.readChar();
}
@Override
public int readInt() throws IOException {
return in.readInt();
}
@Override
public long readLong() throws IOException {
return in.readLong();
}
@Override
public float readFloat() throws IOException {
return in.readFloat();
}
@Override
public double readDouble() throws IOException {
return in.readDouble();
}
@Deprecated
@Override
public String readLine() throws IOException {
return in.readLine();
}
@NotNull
@Override
public String readUTF() throws IOException {
return in.readUTF();
}
}

View File

@ -1,580 +0,0 @@
/*
* Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package org.warp.commonutils.stream;
import java.io.DataInput;
import org.jetbrains.annotations.NotNull;
/**
* A data input stream lets an application read primitive Java data
* types from an underlying input stream in a machine-independent
* way. An application uses a data output stream to write data that
* can later be read by a data input stream.
* <p>
* DataInputStream is not necessarily safe for multithreaded access.
* Thread safety is optional and is the responsibility of users of
* methods in this class.
*
* @author Arthur van Hoff
* @see java.io.DataOutputStream
* @since 1.0
*/
public class SafeDataInputStream extends SafeFilterInputStream implements DataInput {
/**
* Creates a DataInputStream that uses the specified
* underlying InputStream.
*
* @param in the specified input stream
*/
public SafeDataInputStream(SafeInputStream in) {
super(in);
}
/**
* working arrays initialized on demand by readUTF
*/
private byte[] bytearr = new byte[80];
private char[] chararr = new char[80];
/**
* Reads some number of bytes from the contained input stream and
* stores them into the buffer array {@code b}. The number of
* bytes actually read is returned as an integer. This method blocks
* until input data is available, end of file is detected, or an
* exception is thrown.
*
* <p>If {@code b} is null, a {@code NullPointerException} is
* thrown. If the length of {@code b} is zero, then no bytes are
* read and {@code 0} is returned; otherwise, there is an attempt
* to read at least one byte. If no byte is available because the
* stream is at end of file, the value {@code -1} is returned;
* otherwise, at least one byte is read and stored into {@code b}.
*
* <p>The first byte read is stored into element {@code b[0]}, the
* next one into {@code b[1]}, and so on. The number of bytes read
* is, at most, equal to the length of {@code b}. Let {@code k}
* be the number of bytes actually read; these bytes will be stored in
* elements {@code b[0]} through {@code b[k-1]}, leaving
* elements {@code b[k]} through {@code b[b.length-1]}
* unaffected.
*
* <p>The {@code read(b)} method has the same effect as:
* <blockquote><pre>
* read(b, 0, b.length)
* </pre></blockquote>
*
* @param b the buffer into which the data is read.
* @return the total number of bytes read into the buffer, or
* {@code -1} if there is no more data because the end
* of the stream has been reached.
* @see SafeFilterInputStream#in
* @see java.io.InputStream#read(byte[], int, int)
*/
public final int read(byte[] b) {
return in.read(b, 0, b.length);
}
/**
* Reads up to {@code len} bytes of data from the contained
* input stream into an array of bytes. An attempt is made to read
* as many as {@code len} bytes, but a smaller number may be read,
* possibly zero. The number of bytes actually read is returned as an
* integer.
*
* <p> This method blocks until input data is available, end of file is
* detected, or an exception is thrown.
*
* <p> If {@code len} is zero, then no bytes are read and
* {@code 0} is returned; otherwise, there is an attempt to read at
* least one byte. If no byte is available because the stream is at end of
* file, the value {@code -1} is returned; otherwise, at least one
* byte is read and stored into {@code b}.
*
* <p> The first byte read is stored into element {@code b[off]}, the
* next one into {@code b[off+1]}, and so on. The number of bytes read
* is, at most, equal to {@code len}. Let <i>k</i> be the number of
* bytes actually read; these bytes will be stored in elements
* {@code b[off]} through {@code b[off+}<i>k</i>{@code -1]},
* leaving elements {@code b[off+}<i>k</i>{@code ]} through
* {@code b[off+len-1]} unaffected.
*
* <p> In every case, elements {@code b[0]} through
* {@code b[off]} and elements {@code b[off+len]} through
* {@code b[b.length-1]} are unaffected.
*
* @param b the buffer into which the data is read.
* @param off the start offset in the destination array {@code b}
* @param len the maximum number of bytes read.
* @return the total number of bytes read into the buffer, or
* {@code -1} if there is no more data because the end
* of the stream has been reached.
* @throws NullPointerException If {@code b} is {@code null}.
* @throws IndexOutOfBoundsException If {@code off} is negative,
* {@code len} is negative, or {@code len} is greater than
* {@code b.length - off}
* @see SafeFilterInputStream#in
* @see java.io.InputStream#read(byte[], int, int)
*/
public final int read(byte[] b, int off, int len) {
return in.read(b, off, len);
}
/**
* See the general contract of the {@code readFully}
* method of {@code DataInput}.
* <p>
* Bytes
* for this operation are read from the contained
* input stream.
*
* @param b the buffer into which the data is read.
* @throws NullPointerException if {@code b} is {@code null}.
* @see SafeFilterInputStream#in
*/
public final void readFully(byte @NotNull [] b) {
readFully(b, 0, b.length);
}
/**
* See the general contract of the {@code readFully}
* method of {@code DataInput}.
* <p>
* Bytes
* for this operation are read from the contained
* input stream.
*
* @param b the buffer into which the data is read.
* @param off the start offset in the data array {@code b}.
* @param len the number of bytes to read.
* @throws NullPointerException if {@code b} is {@code null}.
* @throws IndexOutOfBoundsException if {@code off} is negative,
* {@code len} is negative, or {@code len} is greater than
* {@code b.length - off}.
* @see SafeFilterInputStream#in
*/
public final void readFully(byte @NotNull [] b, int off, int len) {
if (len < 0)
throw new IndexOutOfBoundsException();
int n = 0;
while (n < len) {
int count = in.read(b, off + n, len - n);
if (count < 0)
throw new IndexOutOfBoundsException();
n += count;
}
}
/**
* See the general contract of the {@code skipBytes}
* method of {@code DataInput}.
* <p>
* Bytes for this operation are read from the contained
* input stream.
*
* @param n the number of bytes to be skipped.
* @return the actual number of bytes skipped.
*/
public final int skipBytes(int n) {
int total = 0;
int cur;
while ((total<n) && ((cur = (int) in.skip(n-total)) > 0)) {
total += cur;
}
return total;
}
/**
* See the general contract of the {@code readBoolean}
* method of {@code DataInput}.
* <p>
* Bytes for this operation are read from the contained
* input stream.
*
* @return the {@code boolean} value read.
* @see SafeFilterInputStream#in
*/
public final boolean readBoolean() {
int ch = in.read();
if (ch < 0)
throw new IndexOutOfBoundsException();
return (ch != 0);
}
/**
* See the general contract of the {@code readByte}
* method of {@code DataInput}.
* <p>
* Bytes
* for this operation are read from the contained
* input stream.
*
* @return the next byte of this input stream as a signed 8-bit
* {@code byte}.
* @see SafeFilterInputStream#in
*/
public final byte readByte() {
int ch = in.read();
if (ch < 0)
throw new IndexOutOfBoundsException();
return (byte)(ch);
}
/**
* See the general contract of the {@code readUnsignedByte}
* method of {@code DataInput}.
* <p>
* Bytes
* for this operation are read from the contained
* input stream.
*
* @return the next byte of this input stream, interpreted as an
* unsigned 8-bit number.
* @see SafeFilterInputStream#in
*/
public final int readUnsignedByte() {
int ch = in.read();
if (ch < 0)
throw new IndexOutOfBoundsException();
return ch;
}
/**
* See the general contract of the {@code readShort}
* method of {@code DataInput}.
* <p>
* Bytes
* for this operation are read from the contained
* input stream.
*
* @return the next two bytes of this input stream, interpreted as a
* signed 16-bit number.
* @see SafeFilterInputStream#in
*/
public final short readShort() {
int ch1 = in.read();
int ch2 = in.read();
if ((ch1 | ch2) < 0)
throw new IndexOutOfBoundsException();
return (short)((ch1 << 8) + (ch2 << 0));
}
/**
* See the general contract of the {@code readUnsignedShort}
* method of {@code DataInput}.
* <p>
* Bytes
* for this operation are read from the contained
* input stream.
*
* @return the next two bytes of this input stream, interpreted as an
* unsigned 16-bit integer.
* @see SafeFilterInputStream#in
*/
public final int readUnsignedShort() {
int ch1 = in.read();
int ch2 = in.read();
if ((ch1 | ch2) < 0)
throw new IndexOutOfBoundsException();
return (ch1 << 8) + (ch2 << 0);
}
/**
* See the general contract of the {@code readChar}
* method of {@code DataInput}.
* <p>
* Bytes
* for this operation are read from the contained
* input stream.
*
* @return the next two bytes of this input stream, interpreted as a
* {@code char}.
* @see SafeFilterInputStream#in
*/
public final char readChar() {
int ch1 = in.read();
int ch2 = in.read();
if ((ch1 | ch2) < 0)
throw new IndexOutOfBoundsException();
return (char)((ch1 << 8) + (ch2 << 0));
}
/**
* See the general contract of the {@code readInt}
* method of {@code DataInput}.
* <p>
* Bytes
* for this operation are read from the contained
* input stream.
*
* @return the next four bytes of this input stream, interpreted as an
* {@code int}.
* @see SafeFilterInputStream#in
*/
public final int readInt() {
int ch1 = in.read();
int ch2 = in.read();
int ch3 = in.read();
int ch4 = in.read();
if ((ch1 | ch2 | ch3 | ch4) < 0)
throw new IndexOutOfBoundsException();
return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
}
private final byte[] readBuffer = new byte[8];
/**
* See the general contract of the {@code readLong}
* method of {@code DataInput}.
* <p>
* Bytes
* for this operation are read from the contained
* input stream.
*
* @return the next eight bytes of this input stream, interpreted as a
* {@code long}.
* @see SafeFilterInputStream#in
*/
public final long readLong() {
readFully(readBuffer, 0, 8);
return (((long)readBuffer[0] << 56) +
((long)(readBuffer[1] & 255) << 48) +
((long)(readBuffer[2] & 255) << 40) +
((long)(readBuffer[3] & 255) << 32) +
((long)(readBuffer[4] & 255) << 24) +
((readBuffer[5] & 255) << 16) +
((readBuffer[6] & 255) << 8) +
((readBuffer[7] & 255) << 0));
}
/**
* See the general contract of the {@code readFloat}
* method of {@code DataInput}.
* <p>
* Bytes
* for this operation are read from the contained
* input stream.
*
* @return the next four bytes of this input stream, interpreted as a
* {@code float}.
* @see SafeDataInputStream#readInt()
* @see java.lang.Float#intBitsToFloat(int)
*/
public final float readFloat() {
return Float.intBitsToFloat(readInt());
}
/**
* See the general contract of the {@code readDouble}
* method of {@code DataInput}.
* <p>
* Bytes
* for this operation are read from the contained
* input stream.
*
* @return the next eight bytes of this input stream, interpreted as a
* {@code double}.
* @see SafeDataInputStream#readLong()
* @see java.lang.Double#longBitsToDouble(long)
*/
public final double readDouble() {
return Double.longBitsToDouble(readLong());
}
private char[] lineBuffer;
/**
* See the general contract of the {@code readLine}
* method of {@code DataInput}.
* <p>
* Bytes
* for this operation are read from the contained
* input stream.
*
* @deprecated This method does not properly convert bytes to characters.
* As of JDK&nbsp;1.1, the preferred way to read lines of text is via the
* {@code BufferedReader.readLine()} method. Programs that use the
* {@code DataInputStream} class to read lines can be converted to use
* the {@code BufferedReader} class by replacing code of the form:
* <blockquote><pre>
* DataInputStream d =&nbsp;new&nbsp;DataInputStream(in);
* </pre></blockquote>
* with:
* <blockquote><pre>
* BufferedReader d
* =&nbsp;new&nbsp;BufferedReader(new&nbsp;InputStreamReader(in));
* </pre></blockquote>
*
* @return the next line of text from this input stream.
* @see java.io.BufferedReader#readLine()
* @see SafeFilterInputStream#in
*/
@Deprecated
public final String readLine() {
char[] buf = lineBuffer;
if (buf == null) {
buf = lineBuffer = new char[128];
}
int room = buf.length;
int offset = 0;
int c;
loop: while (true) {
switch (c = in.read()) {
case -1:
case '\n':
break loop;
case '\r':
int c2 = in.read();
if ((c2 != '\n') && (c2 != -1)) {
if (!(in instanceof SafePushbackInputStream)) {
this.in = new SafePushbackInputStream(in);
}
((SafePushbackInputStream)in).unread(c2);
}
break loop;
default:
if (--room < 0) {
buf = new char[offset + 128];
room = buf.length - offset - 1;
System.arraycopy(lineBuffer, 0, buf, 0, offset);
lineBuffer = buf;
}
buf[offset++] = (char) c;
break;
}
}
if ((c == -1) && (offset == 0)) {
return null;
}
return String.copyValueOf(buf, 0, offset);
}
/**
* See the general contract of the {@code readUTF}
* method of {@code DataInput}.
* <p>
* Bytes
* for this operation are read from the contained
* input stream.
*
* @return a Unicode string.
* @see SafeDataInputStream#readUTF(SafeDataInputStream)
*/
public final @NotNull String readUTF() {
return readUTF(this);
}
/**
* Reads from the
* stream {@code in} a representation
* of a Unicode character string encoded in
* <a href="DataInput.html#modified-utf-8">modified UTF-8</a> format;
* this string of characters is then returned as a {@code String}.
* The details of the modified UTF-8 representation
* are exactly the same as for the {@code readUTF}
* method of {@code DataInput}.
*
* @param in a data input stream.
* @return a Unicode string.
* @see SafeDataInputStream#readUnsignedShort()
*/
public static String readUTF(SafeDataInputStream in) {
int utflen = in.readUnsignedShort();
byte[] bytearr;
char[] chararr;
if (in.bytearr.length < utflen){
in.bytearr = new byte[utflen*2];
in.chararr = new char[utflen*2];
}
chararr = in.chararr;
bytearr = in.bytearr;
int c, char2, char3;
int count = 0;
int chararr_count=0;
in.readFully(bytearr, 0, utflen);
while (count < utflen) {
c = (int) bytearr[count] & 0xff;
if (c > 127) break;
count++;
chararr[chararr_count++]=(char)c;
}
while (count < utflen) {
c = (int) bytearr[count] & 0xff;
switch (c >> 4) {
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
/* 0xxxxxxx*/
count++;
chararr[chararr_count++]=(char)c;
break;
case 12: case 13:
/* 110x xxxx 10xx xxxx*/
count += 2;
if (count > utflen)
throw new IllegalArgumentException(
"malformed input: partial character at end");
char2 = bytearr[count-1];
if ((char2 & 0xC0) != 0x80)
throw new IllegalArgumentException(
"malformed input around byte " + count);
chararr[chararr_count++]=(char)(((c & 0x1F) << 6) |
(char2 & 0x3F));
break;
case 14:
/* 1110 xxxx 10xx xxxx 10xx xxxx */
count += 3;
if (count > utflen)
throw new IllegalArgumentException(
"malformed input: partial character at end");
char2 = bytearr[count-2];
char3 = bytearr[count-1];
if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
throw new IllegalArgumentException(
"malformed input around byte " + (count-1));
chararr[chararr_count++]=(char)(((c & 0x0F) << 12) |
((char2 & 0x3F) << 6) |
((char3 & 0x3F) << 0));
break;
default:
/* 10xx xxxx, 1111 xxxx */
throw new IllegalArgumentException(
"malformed input around byte " + count);
}
}
// The number of chars produced may be less than utflen
return new String(chararr, 0, chararr_count);
}
}

View File

@ -1,339 +0,0 @@
/*
* Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package org.warp.commonutils.stream;
/**
* The {@code SafeDataOutput} interface provides
* for converting data from any of the Java
* primitive types to a series of bytes and
* writing these bytes to a binary stream.
* There is also a facility for converting
* a {@code String} into
* <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
* format and writing the resulting series
* of bytes.
* <p>
* For all the methods in this interface that
* write bytes, it is generally true that if
* a byte cannot be written for any reason,
* an {@code IOException} is thrown.
*
* @author Frank Yellin
* @see java.io.DataInput
* @see java.io.DataOutputStream
* @since 1.0
*/
public interface SafeDataOutput {
/**
* Writes to the output stream the eight
* low-order bits of the argument {@code b}.
* The 24 high-order bits of {@code b}
* are ignored.
*
* @param b the byte to be written.
*/
void write(int b);
/**
* Writes to the output stream all the bytes in array {@code b}.
* If {@code b} is {@code null},
* a {@code NullPointerException} is thrown.
* If {@code b.length} is zero, then
* no bytes are written. Otherwise, the byte
* {@code b[0]} is written first, then
* {@code b[1]}, and so on; the last byte
* written is {@code b[b.length-1]}.
*
* @param b the data.
*/
void write(byte b[]);
/**
* Writes {@code len} bytes from array
* {@code b}, in order, to
* the output stream. If {@code b}
* is {@code null}, a {@code NullPointerException}
* is thrown. If {@code off} is negative,
* or {@code len} is negative, or {@code off+len}
* is greater than the length of the array
* {@code b}, then an {@code IndexOutOfBoundsException}
* is thrown. If {@code len} is zero,
* then no bytes are written. Otherwise, the
* byte {@code b[off]} is written first,
* then {@code b[off+1]}, and so on; the
* last byte written is {@code b[off+len-1]}.
*
* @param b the data.
* @param off the start offset in the data.
* @param len the number of bytes to write.
*/
void write(byte b[], int off, int len);
/**
* Writes a {@code boolean} value to this output stream.
* If the argument {@code v}
* is {@code true}, the value {@code (byte)1}
* is written; if {@code v} is {@code false},
* the value {@code (byte)0} is written.
* The byte written by this method may
* be read by the {@code readBoolean}
* method of interface {@code DataInput},
* which will then return a {@code boolean}
* equal to {@code v}.
*
* @param v the boolean to be written.
*/
void writeBoolean(boolean v);
/**
* Writes to the output stream the eight low-order
* bits of the argument {@code v}.
* The 24 high-order bits of {@code v}
* are ignored. (This means that {@code writeByte}
* does exactly the same thing as {@code write}
* for an integer argument.) The byte written
* by this method may be read by the {@code readByte}
* method of interface {@code DataInput},
* which will then return a {@code byte}
* equal to {@code (byte)v}.
*
* @param v the byte value to be written.
*/
void writeByte(int v);
/**
* Writes two bytes to the output
* stream to represent the value of the argument.
* The byte values to be written, in the order
* shown, are:
* <pre>{@code
* (byte)(0xff & (v >> 8))
* (byte)(0xff & v)
* }</pre> <p>
* The bytes written by this method may be
* read by the {@code readShort} method
* of interface {@code DataInput}, which
* will then return a {@code short} equal
* to {@code (short)v}.
*
* @param v the {@code short} value to be written.
*/
void writeShort(int v);
/**
* Writes a {@code char} value, which
* is comprised of two bytes, to the
* output stream.
* The byte values to be written, in the order
* shown, are:
* <pre>{@code
* (byte)(0xff & (v >> 8))
* (byte)(0xff & v)
* }</pre><p>
* The bytes written by this method may be
* read by the {@code readChar} method
* of interface {@code DataInput}, which
* will then return a {@code char} equal
* to {@code (char)v}.
*
* @param v the {@code char} value to be written.
*/
void writeChar(int v);
/**
* Writes an {@code int} value, which is
* comprised of four bytes, to the output stream.
* The byte values to be written, in the order
* shown, are:
* <pre>{@code
* (byte)(0xff & (v >> 24))
* (byte)(0xff & (v >> 16))
* (byte)(0xff & (v >> 8))
* (byte)(0xff & v)
* }</pre><p>
* The bytes written by this method may be read
* by the {@code readInt} method of interface
* {@code DataInput}, which will then
* return an {@code int} equal to {@code v}.
*
* @param v the {@code int} value to be written.
*/
void writeInt(int v);
/**
* Writes a {@code long} value, which is
* comprised of eight bytes, to the output stream.
* The byte values to be written, in the order
* shown, are:
* <pre>{@code
* (byte)(0xff & (v >> 56))
* (byte)(0xff & (v >> 48))
* (byte)(0xff & (v >> 40))
* (byte)(0xff & (v >> 32))
* (byte)(0xff & (v >> 24))
* (byte)(0xff & (v >> 16))
* (byte)(0xff & (v >> 8))
* (byte)(0xff & v)
* }</pre><p>
* The bytes written by this method may be
* read by the {@code readLong} method
* of interface {@code DataInput}, which
* will then return a {@code long} equal
* to {@code v}.
*
* @param v the {@code long} value to be written.
*/
void writeLong(long v);
/**
* Writes a {@code float} value,
* which is comprised of four bytes, to the output stream.
* It does this as if it first converts this
* {@code float} value to an {@code int}
* in exactly the manner of the {@code Float.floatToIntBits}
* method and then writes the {@code int}
* value in exactly the manner of the {@code writeInt}
* method. The bytes written by this method
* may be read by the {@code readFloat}
* method of interface {@code DataInput},
* which will then return a {@code float}
* equal to {@code v}.
*
* @param v the {@code float} value to be written.
*/
void writeFloat(float v);
/**
* Writes a {@code double} value,
* which is comprised of eight bytes, to the output stream.
* It does this as if it first converts this
* {@code double} value to a {@code long}
* in exactly the manner of the {@code Double.doubleToLongBits}
* method and then writes the {@code long}
* value in exactly the manner of the {@code writeLong}
* method. The bytes written by this method
* may be read by the {@code readDouble}
* method of interface {@code DataInput},
* which will then return a {@code double}
* equal to {@code v}.
*
* @param v the {@code double} value to be written.
*/
void writeDouble(double v);
/**
* Writes a string to the output stream.
* For every character in the string
* {@code s}, taken in order, one byte
* is written to the output stream. If
* {@code s} is {@code null}, a {@code NullPointerException}
* is thrown.<p> If {@code s.length}
* is zero, then no bytes are written. Otherwise,
* the character {@code s[0]} is written
* first, then {@code s[1]}, and so on;
* the last character written is {@code s[s.length-1]}.
* For each character, one byte is written,
* the low-order byte, in exactly the manner
* of the {@code writeByte} method . The
* high-order eight bits of each character
* in the string are ignored.
*
* @param s the string of bytes to be written.
*/
void writeBytes(String s);
/**
* Writes every character in the string {@code s},
* to the output stream, in order,
* two bytes per character. If {@code s}
* is {@code null}, a {@code NullPointerException}
* is thrown. If {@code s.length}
* is zero, then no characters are written.
* Otherwise, the character {@code s[0]}
* is written first, then {@code s[1]},
* and so on; the last character written is
* {@code s[s.length-1]}. For each character,
* two bytes are actually written, high-order
* byte first, in exactly the manner of the
* {@code writeChar} method.
*
* @param s the string value to be written.
*/
void writeChars(String s);
/**
* Writes two bytes of length information
* to the output stream, followed
* by the
* <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
* representation
* of every character in the string {@code s}.
* If {@code s} is {@code null},
* a {@code NullPointerException} is thrown.
* Each character in the string {@code s}
* is converted to a group of one, two, or
* three bytes, depending on the value of the
* character.<p>
* If a character {@code c}
* is in the range <code>&#92;u0001</code> through
* <code>&#92;u007f</code>, it is represented
* by one byte:
* <pre>(byte)c </pre> <p>
* If a character {@code c} is <code>&#92;u0000</code>
* or is in the range <code>&#92;u0080</code>
* through <code>&#92;u07ff</code>, then it is
* represented by two bytes, to be written
* in the order shown: <pre>{@code
* (byte)(0xc0 | (0x1f & (c >> 6)))
* (byte)(0x80 | (0x3f & c))
* }</pre> <p> If a character
* {@code c} is in the range <code>&#92;u0800</code>
* through {@code uffff}, then it is
* represented by three bytes, to be written
* in the order shown: <pre>{@code
* (byte)(0xe0 | (0x0f & (c >> 12)))
* (byte)(0x80 | (0x3f & (c >> 6)))
* (byte)(0x80 | (0x3f & c))
* }</pre> <p> First,
* the total number of bytes needed to represent
* all the characters of {@code s} is
* calculated. If this number is larger than
* {@code 65535}, then a {@code UTFDataFormatException}
* is thrown. Otherwise, this length is written
* to the output stream in exactly the manner
* of the {@code writeShort} method;
* after this, the one-, two-, or three-byte
* representation of each character in the
* string {@code s} is written.<p> The
* bytes written by this method may be read
* by the {@code readUTF} method of interface
* {@code DataInput}, which will then
* return a {@code String} equal to {@code s}.
*
* @param s the string value to be written.
*/
void writeUTF(String s);
}

View File

@ -1,408 +0,0 @@
/*
* Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package org.warp.commonutils.stream;
import java.io.DataOutputStream;
/**
* A data output stream lets an application write primitive Java data
* types to an output stream in a portable way. An application can
* then use a data input stream to read the data back in.
*
* @author unascribed
* @see java.io.DataInputStream
* @since 1.0
*/
public class SafeDataOutputStream extends SafeFilterOutputStream implements SafeDataOutput {
/**
* The number of bytes written to the data output stream so far.
* If this counter overflows, it will be wrapped to Integer.MAX_VALUE.
*/
protected int written;
/**
* bytearr is initialized on demand by writeUTF
*/
private byte[] bytearr = null;
/**
* Creates a new data output stream to write data to the specified
* underlying output stream. The counter {@code written} is
* set to zero.
*
* @param out the underlying output stream, to be saved for later
* use.
* @see SafeFilterOutputStream#out
*/
public SafeDataOutputStream(SafeOutputStream out) {
super(out);
}
/**
* Increases the written counter by the specified value
* until it reaches Integer.MAX_VALUE.
*/
private void incCount(int value) {
int temp = written + value;
if (temp < 0) {
temp = Integer.MAX_VALUE;
}
written = temp;
}
/**
* Writes the specified byte (the low eight bits of the argument
* {@code b}) to the underlying output stream. If no exception
* is thrown, the counter {@code written} is incremented by
* {@code 1}.
* <p>
* Implements the {@code write} method of {@code OutputStream}.
*
* @param b the {@code byte} to be written.
* @see SafeFilterOutputStream#out
*/
public synchronized void write(int b) {
out.write(b);
incCount(1);
}
/**
* Writes {@code len} bytes from the specified byte array
* starting at offset {@code off} to the underlying output stream.
* If no exception is thrown, the counter {@code written} is
* incremented by {@code len}.
*
* @param b the data.
* @param off the start offset in the data.
* @param len the number of bytes to write.
* @see SafeFilterOutputStream#out
*/
public synchronized void write(byte b[], int off, int len)
{
out.write(b, off, len);
incCount(len);
}
/**
* Flushes this data output stream. This forces any buffered output
* bytes to be written out to the stream.
* <p>
* The {@code flush} method of {@code SafeDataOutputStream}
* calls the {@code flush} method of its underlying output stream.
*
* @see SafeFilterOutputStream#out
* @see java.io.OutputStream#flush()
*/
public void flush() {
out.flush();
}
/**
* Writes a {@code boolean} to the underlying output stream as
* a 1-byte value. The value {@code true} is written out as the
* value {@code (byte)1}; the value {@code false} is
* written out as the value {@code (byte)0}. If no exception is
* thrown, the counter {@code written} is incremented by
* {@code 1}.
*
* @param v a {@code boolean} value to be written.
* @see SafeFilterOutputStream#out
*/
public final void writeBoolean(boolean v) {
out.write(v ? 1 : 0);
incCount(1);
}
/**
* Writes out a {@code byte} to the underlying output stream as
* a 1-byte value. If no exception is thrown, the counter
* {@code written} is incremented by {@code 1}.
*
* @param v a {@code byte} value to be written.
* @see SafeFilterOutputStream#out
*/
public final void writeByte(int v) {
out.write(v);
incCount(1);
}
/**
* Writes a {@code short} to the underlying output stream as two
* bytes, high byte first. If no exception is thrown, the counter
* {@code written} is incremented by {@code 2}.
*
* @param v a {@code short} to be written.
* @see SafeFilterOutputStream#out
*/
public final void writeShort(int v) {
out.write((v >>> 8) & 0xFF);
out.write((v >>> 0) & 0xFF);
incCount(2);
}
/**
* Writes a {@code char} to the underlying output stream as a
* 2-byte value, high byte first. If no exception is thrown, the
* counter {@code written} is incremented by {@code 2}.
*
* @param v a {@code char} value to be written.
* @see SafeFilterOutputStream#out
*/
public final void writeChar(int v) {
out.write((v >>> 8) & 0xFF);
out.write((v >>> 0) & 0xFF);
incCount(2);
}
/**
* Writes an {@code int} to the underlying output stream as four
* bytes, high byte first. If no exception is thrown, the counter
* {@code written} is incremented by {@code 4}.
*
* @param v an {@code int} to be written.
* @see SafeFilterOutputStream#out
*/
public final void writeInt(int v) {
out.write((v >>> 24) & 0xFF);
out.write((v >>> 16) & 0xFF);
out.write((v >>> 8) & 0xFF);
out.write((v >>> 0) & 0xFF);
incCount(4);
}
private byte writeBuffer[] = new byte[8];
/**
* Writes a {@code long} to the underlying output stream as eight
* bytes, high byte first. In no exception is thrown, the counter
* {@code written} is incremented by {@code 8}.
*
* @param v a {@code long} to be written.
* @see SafeFilterOutputStream#out
*/
public final void writeLong(long v) {
writeBuffer[0] = (byte)(v >>> 56);
writeBuffer[1] = (byte)(v >>> 48);
writeBuffer[2] = (byte)(v >>> 40);
writeBuffer[3] = (byte)(v >>> 32);
writeBuffer[4] = (byte)(v >>> 24);
writeBuffer[5] = (byte)(v >>> 16);
writeBuffer[6] = (byte)(v >>> 8);
writeBuffer[7] = (byte)(v >>> 0);
out.write(writeBuffer, 0, 8);
incCount(8);
}
/**
* Converts the float argument to an {@code int} using the
* {@code floatToIntBits} method in class {@code Float},
* and then writes that {@code int} value to the underlying
* output stream as a 4-byte quantity, high byte first. If no
* exception is thrown, the counter {@code written} is
* incremented by {@code 4}.
*
* @param v a {@code float} value to be written.
* @see SafeFilterOutputStream#out
* @see java.lang.Float#floatToIntBits(float)
*/
public final void writeFloat(float v) {
writeInt(Float.floatToIntBits(v));
}
/**
* Converts the double argument to a {@code long} using the
* {@code doubleToLongBits} method in class {@code Double},
* and then writes that {@code long} value to the underlying
* output stream as an 8-byte quantity, high byte first. If no
* exception is thrown, the counter {@code written} is
* incremented by {@code 8}.
*
* @param v a {@code double} value to be written.
* @see SafeFilterOutputStream#out
* @see java.lang.Double#doubleToLongBits(double)
*/
public final void writeDouble(double v) {
writeLong(Double.doubleToLongBits(v));
}
/**
* Writes out the string to the underlying output stream as a
* sequence of bytes. Each character in the string is written out, in
* sequence, by discarding its high eight bits. If no exception is
* thrown, the counter {@code written} is incremented by the
* length of {@code s}.
*
* @param s a string of bytes to be written.
* @see SafeFilterOutputStream#out
*/
public final void writeBytes(String s) {
int len = s.length();
for (int i = 0 ; i < len ; i++) {
out.write((byte)s.charAt(i));
}
incCount(len);
}
/**
* Writes a string to the underlying output stream as a sequence of
* characters. Each character is written to the data output stream as
* if by the {@code writeChar} method. If no exception is
* thrown, the counter {@code written} is incremented by twice
* the length of {@code s}.
*
* @param s a {@code String} value to be written.
* @see SafeDataOutputStream#writeChar(int)
* @see SafeFilterOutputStream#out
*/
public final void writeChars(String s) {
int len = s.length();
for (int i = 0 ; i < len ; i++) {
int v = s.charAt(i);
out.write((v >>> 8) & 0xFF);
out.write((v >>> 0) & 0xFF);
}
incCount(len * 2);
}
/**
* Writes a string to the underlying output stream using
* <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
* encoding in a machine-independent manner.
* <p>
* First, two bytes are written to the output stream as if by the
* {@code writeShort} method giving the number of bytes to
* follow. This value is the number of bytes actually written out,
* not the length of the string. Following the length, each character
* of the string is output, in sequence, using the modified UTF-8 encoding
* for the character. If no exception is thrown, the counter
* {@code written} is incremented by the total number of
* bytes written to the output stream. This will be at least two
* plus the length of {@code str}, and at most two plus
* thrice the length of {@code str}.
*
* @param str a string to be written.
* @see #writeChars(String)
*/
public final void writeUTF(String str) {
writeUTF(str, this);
}
/**
* Writes a string to the specified DataOutput using
* <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
* encoding in a machine-independent manner.
* <p>
* First, two bytes are written to out as if by the {@code writeShort}
* method giving the number of bytes to follow. This value is the number of
* bytes actually written out, not the length of the string. Following the
* length, each character of the string is output, in sequence, using the
* modified UTF-8 encoding for the character. If no exception is thrown, the
* counter {@code written} is incremented by the total number of
* bytes written to the output stream. This will be at least two
* plus the length of {@code str}, and at most two plus
* thrice the length of {@code str}.
*
* @param str a string to be written.
* @param out destination to write to
* @return The number of bytes written out.
*/
static int writeUTF(String str, SafeDataOutput out) {
final int strlen = str.length();
int utflen = strlen; // optimized for ASCII
for (int i = 0; i < strlen; i++) {
int c = str.charAt(i);
if (c >= 0x80 || c == 0)
utflen += (c >= 0x800) ? 2 : 1;
}
if (utflen > 65535 || /* overflow */ utflen < strlen)
throw new IllegalArgumentException(tooLongMsg(str, utflen));
final byte[] bytearr;
if (out instanceof SafeDataOutputStream) {
SafeDataOutputStream dos = (SafeDataOutputStream)out;
if (dos.bytearr == null || (dos.bytearr.length < (utflen + 2)))
dos.bytearr = new byte[(utflen*2) + 2];
bytearr = dos.bytearr;
} else {
bytearr = new byte[utflen + 2];
}
int count = 0;
bytearr[count++] = (byte) ((utflen >>> 8) & 0xFF);
bytearr[count++] = (byte) ((utflen >>> 0) & 0xFF);
int i = 0;
for (i = 0; i < strlen; i++) { // optimized for initial run of ASCII
int c = str.charAt(i);
if (c >= 0x80 || c == 0) break;
bytearr[count++] = (byte) c;
}
for (; i < strlen; i++) {
int c = str.charAt(i);
if (c < 0x80 && c != 0) {
bytearr[count++] = (byte) c;
} else if (c >= 0x800) {
bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
bytearr[count++] = (byte) (0x80 | ((c >> 6) & 0x3F));
bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
} else {
bytearr[count++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
}
}
out.write(bytearr, 0, utflen + 2);
return utflen + 2;
}
private static String tooLongMsg(String s, int bits32) {
int slen = s.length();
String head = s.substring(0, 8);
String tail = s.substring(slen - 8, slen);
// handle int overflow with max 3x expansion
long actualLength = (long)slen + Integer.toUnsignedLong(bits32 - slen);
return "encoded string (" + head + "..." + tail + ") too long: "
+ actualLength + " bytes";
}
/**
* Returns the current value of the counter {@code written},
* the number of bytes written to this data output stream so far.
* If the counter overflows, it will be wrapped to Integer.MAX_VALUE.
*
* @return the value of the {@code written} field.
* @see SafeDataOutputStream#written
*/
public final int size() {
return written;
}
public DataOutputStream asDataOutputStream() {
return new DataOutputStream(this.out);
}
}

View File

@ -1,210 +0,0 @@
package org.warp.commonutils.stream;
/**
* A {@code FilterInputStream} contains
* some other input stream, which it uses as
* its basic source of data, possibly transforming
* the data along the way or providing additional
* functionality. The class {@code FilterInputStream}
* itself simply overrides all methods of
* {@code InputStream} with versions that
* pass all requests to the contained input
* stream. Subclasses of {@code FilterInputStream}
* may further override some of these methods
* and may also provide additional methods
* and fields.
*
* @author Jonathan Payne
* @since 1.0
*/
public class SafeFilterInputStream extends SafeInputStream {
/**
* The input stream to be filtered.
*/
protected volatile SafeInputStream in;
/**
* Creates a {@code FilterInputStream}
* by assigning the argument {@code in}
* to the field {@code this.in} so as
* to remember it for later use.
*
* @param in the underlying input stream, or {@code null} if
* this instance is to be created without an underlying stream.
*/
protected SafeFilterInputStream(SafeInputStream in) {
this.in = in;
}
/**
* Reads the next byte of data from this input stream. The value
* byte is returned as an {@code int} in the range
* {@code 0} to {@code 255}. If no byte is available
* because the end of the stream has been reached, the value
* {@code -1} is returned. This method blocks until input data
* is available, the end of the stream is detected, or an exception
* is thrown.
* <p>
* This method
* simply performs {@code in.read()} and returns the result.
*
* @return the next byte of data, or {@code -1} if the end of the
* stream is reached.
* @see SafeFilterInputStream#in
*/
public int read() {
return in.read();
}
/**
* Reads up to {@code b.length} bytes of data from this
* input stream into an array of bytes. This method blocks until some
* input is available.
* <p>
* This method simply performs the call
* {@code read(b, 0, b.length)} and returns
* the result. It is important that it does
* <i>not</i> do {@code in.read(b)} instead;
* certain subclasses of {@code FilterInputStream}
* depend on the implementation strategy actually
* used.
*
* @param b the buffer into which the data is read.
* @return the total number of bytes read into the buffer, or
* {@code -1} if there is no more data because the end of
* the stream has been reached.
* @see SafeFilterInputStream#read(byte[], int, int)
*/
public int read(byte b[]) {
return read(b, 0, b.length);
}
/**
* Reads up to {@code len} bytes of data from this input stream
* into an array of bytes. If {@code len} is not zero, the method
* blocks until some input is available; otherwise, no
* bytes are read and {@code 0} is returned.
* <p>
* This method simply performs {@code in.read(b, off, len)}
* and returns the result.
*
* @param b the buffer into which the data is read.
* @param off the start offset in the destination array {@code b}
* @param len the maximum number of bytes read.
* @return the total number of bytes read into the buffer, or
* {@code -1} if there is no more data because the end of
* the stream has been reached.
* @throws NullPointerException If {@code b} is {@code null}.
* @throws IndexOutOfBoundsException If {@code off} is negative,
* {@code len} is negative, or {@code len} is greater than
* {@code b.length - off}
* @see SafeFilterInputStream#in
*/
public int read(byte b[], int off, int len) {
return in.read(b, off, len);
}
/**
* Skips over and discards {@code n} bytes of data from the
* input stream. The {@code skip} method may, for a variety of
* reasons, end up skipping over some smaller number of bytes,
* possibly {@code 0}. The actual number of bytes skipped is
* returned.
* <p>
* This method simply performs {@code in.skip(n)}.
*
* @param n the number of bytes to be skipped.
* @return the actual number of bytes skipped.
*/
public long skip(long n) {
return in.skip(n);
}
/**
* Returns an estimate of the number of bytes that can be read (or
* skipped over) from this input stream without blocking by the next
* caller of a method for this input stream. The next caller might be
* the same thread or another thread. A single read or skip of this
* many bytes will not block, but may read or skip fewer bytes.
* <p>
* This method returns the result of {@link #in in}.available().
*
* @return an estimate of the number of bytes that can be read (or skipped
* over) from this input stream without blocking.
*/
public int available() {
return in.available();
}
/**
* Closes this input stream and releases any system resources
* associated with the stream.
* This
* method simply performs {@code in.close()}.
*
* @see SafeFilterInputStream#in
*/
public void close() {
in.close();
}
/**
* Marks the current position in this input stream. A subsequent
* call to the {@code reset} method repositions this stream at
* the last marked position so that subsequent reads re-read the same bytes.
* <p>
* The {@code readlimit} argument tells this input stream to
* allow that many bytes to be read before the mark position gets
* invalidated.
* <p>
* This method simply performs {@code in.mark(readlimit)}.
*
* @param readlimit the maximum limit of bytes that can be read before
* the mark position becomes invalid.
* @see SafeFilterInputStream#in
* @see SafeFilterInputStream#reset()
*/
public synchronized void mark(int readlimit) {
in.mark(readlimit);
}
/**
* Repositions this stream to the position at the time the
* {@code mark} method was last called on this input stream.
* <p>
* This method
* simply performs {@code in.reset()}.
* <p>
* Stream marks are intended to be used in
* situations where you need to read ahead a little to see what's in
* the stream. Often this is most easily done by invoking some
* general parser. If the stream is of the type handled by the
* parse, it just chugs along happily. If the stream is not of
* that type, the parser should toss an exception when it fails.
* If this happens within readlimit bytes, it allows the outer
* code to reset the stream and try another parser.
*
* @see SafeFilterInputStream#in
* @see SafeFilterInputStream#mark(int)
*/
public synchronized void reset() {
in.reset();
}
/**
* Tests if this input stream supports the {@code mark}
* and {@code reset} methods.
* This method
* simply performs {@code in.markSupported()}.
*
* @return {@code true} if this stream type supports the
* {@code mark} and {@code reset} method;
* {@code false} otherwise.
* @see SafeFilterInputStream#in
* @see java.io.InputStream#mark(int)
* @see java.io.InputStream#reset()
*/
public boolean markSupported() {
return in.markSupported();
}
}

View File

@ -1,180 +0,0 @@
package org.warp.commonutils.stream;
/**
* This class is the superclass of all classes that filter output
* streams. These streams sit on top of an already existing output
* stream (the <i>underlying</i> output stream) which it uses as its
* basic sink of data, but possibly transforming the data along the
* way or providing additional functionality.
* <p>
* The class {@code FilterOutputStream} itself simply overrides
* all methods of {@code SafeOutputStream} with versions that pass
* all requests to the underlying output stream. Subclasses of
* {@code FilterOutputStream} may further override some of these
* methods as well as provide additional methods and fields.
*
* @author Jonathan Payne
* @since 1.0
*/
public class SafeFilterOutputStream extends SafeOutputStream {
/**
* The underlying output stream to be filtered.
*/
protected SafeOutputStream out;
/**
* Whether the stream is closed; implicitly initialized to false.
*/
private volatile boolean closed;
/**
* Object used to prevent a race on the 'closed' instance variable.
*/
private final Object closeLock = new Object();
/**
* Creates an output stream filter built on top of the specified
* underlying output stream.
*
* @param out the underlying output stream to be assigned to
* the field {@code this.out} for later use, or
* {@code null} if this instance is to be
* created without an underlying stream.
*/
public SafeFilterOutputStream(SafeOutputStream out) {
this.out = out;
}
/**
* Writes the specified {@code byte} to this output stream.
* <p>
* The {@code write} method of {@code FilterOutputStream}
* calls the {@code write} method of its underlying output stream,
* that is, it performs {@code out.write(b)}.
* <p>
* Implements the abstract {@code write} method of {@code SafeOutputStream}.
*
* @param b the {@code byte}.
*/
@Override
public void write(int b) {
out.write(b);
}
/**
* Writes {@code b.length} bytes to this output stream.
* <p>
* The {@code write} method of {@code FilterOutputStream}
* calls its {@code write} method of three arguments with the
* arguments {@code b}, {@code 0}, and
* {@code b.length}.
* <p>
* Note that this method does not call the one-argument
* {@code write} method of its underlying output stream with
* the single argument {@code b}.
*
* @param b the data to be written.
* @see SafeFilterOutputStream#write(byte[], int, int)
*/
@Override
public void write(byte b[]) {
write(b, 0, b.length);
}
/**
* Writes {@code len} bytes from the specified
* {@code byte} array starting at offset {@code off} to
* this output stream.
* <p>
* The {@code write} method of {@code FilterOutputStream}
* calls the {@code write} method of one argument on each
* {@code byte} to output.
* <p>
* Note that this method does not call the {@code write} method
* of its underlying output stream with the same arguments. Subclasses
* of {@code FilterOutputStream} should provide a more efficient
* implementation of this method.
*
* @param b the data.
* @param off the start offset in the data.
* @param len the number of bytes to write.
* @see SafeFilterOutputStream#write(int)
*/
@Override
public void write(byte b[], int off, int len) {
if ((off | len | (b.length - (len + off)) | (off + len)) < 0)
throw new IndexOutOfBoundsException();
for (int i = 0 ; i < len ; i++) {
write(b[off + i]);
}
}
/**
* Flushes this output stream and forces any buffered output bytes
* to be written out to the stream.
* <p>
* The {@code flush} method of {@code FilterOutputStream}
* calls the {@code flush} method of its underlying output stream.
*
* @see SafeFilterOutputStream#out
*/
@Override
public void flush() {
out.flush();
}
/**
* Closes this output stream and releases any system resources
* associated with the stream.
* <p>
* When not already closed, the {@code close} method of {@code
* FilterOutputStream} calls its {@code flush} method, and then
* calls the {@code close} method of its underlying output stream.
*
* @see SafeFilterOutputStream#flush()
* @see SafeFilterOutputStream#out
*/
@Override
public void close() {
if (closed) {
return;
}
synchronized (closeLock) {
if (closed) {
return;
}
closed = true;
}
Throwable flushException = null;
try {
flush();
} catch (Throwable e) {
flushException = e;
throw e;
} finally {
if (flushException == null) {
out.close();
} else {
try {
out.close();
} catch (Throwable closeException) {
// evaluate possible precedence of flushException over closeException
if ((flushException instanceof ThreadDeath) &&
!(closeException instanceof ThreadDeath)) {
flushException.addSuppressed(closeException);
throw (ThreadDeath) flushException;
}
if (flushException != closeException) {
closeException.addSuppressed(flushException);
}
throw closeException;
}
}
}
}
}

View File

@ -1,201 +0,0 @@
package org.warp.commonutils.stream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
public abstract class SafeInputStream extends InputStream {
// MAX_SKIP_BUFFER_SIZE is used to determine the maximum buffer size to
// use when skipping.
private static final int MAX_SKIP_BUFFER_SIZE = 2048;
private static final int DEFAULT_BUFFER_SIZE = 8192;
@Override
public abstract int read();
public int read(byte b[]) {
return read(b, 0, b.length);
}
public int read(byte b[], int off, int len) {
Objects.checkFromIndexSize(off, len, b.length);
if (len == 0) {
return 0;
}
int c = read();
if (c == -1) {
return -1;
}
b[off] = (byte)c;
int i = 1;
for (; i < len ; i++) {
c = read();
if (c == -1) {
break;
}
b[off + i] = (byte)c;
}
return i;
}
public byte[] readAllBytes() {
return readNBytes(Integer.MAX_VALUE);
}
private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
public byte[] readNBytes(int len) {
if (len < 0) {
throw new IllegalArgumentException("len < 0");
}
List<byte[]> bufs = null;
byte[] result = null;
int total = 0;
int remaining = len;
int n;
do {
byte[] buf = new byte[Math.min(remaining, DEFAULT_BUFFER_SIZE)];
int nread = 0;
// read to EOF which may read more or less than buffer size
while ((n = read(buf, nread,
Math.min(buf.length - nread, remaining))) > 0) {
nread += n;
remaining -= n;
}
if (nread > 0) {
if (MAX_BUFFER_SIZE - total < nread) {
throw new OutOfMemoryError("Required array size too large");
}
total += nread;
if (result == null) {
result = buf;
} else {
if (bufs == null) {
bufs = new ArrayList<>();
bufs.add(result);
}
bufs.add(buf);
}
}
// if the last call to read returned -1 or the number of bytes
// requested have been read then break
} while (n >= 0 && remaining > 0);
if (bufs == null) {
if (result == null) {
return new byte[0];
}
return result.length == total ?
result : Arrays.copyOf(result, total);
}
result = new byte[total];
int offset = 0;
remaining = total;
for (byte[] b : bufs) {
int count = Math.min(b.length, remaining);
System.arraycopy(b, 0, result, offset, count);
offset += count;
remaining -= count;
}
return result;
}
public int readNBytes(byte[] b, int off, int len) {
Objects.checkFromIndexSize(off, len, b.length);
int n = 0;
while (n < len) {
int count = read(b, off + n, len - n);
if (count < 0)
break;
n += count;
}
return n;
}
public long skip(long n) {
long remaining = n;
int nr;
if (n <= 0) {
return 0;
}
int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining);
byte[] skipBuffer = new byte[size];
while (remaining > 0) {
nr = read(skipBuffer, 0, (int)Math.min(size, remaining));
if (nr < 0) {
break;
}
remaining -= nr;
}
return n - remaining;
}
public void skipNBytes(long n) {
if (n > 0) {
long ns = skip(n);
if (ns >= 0 && ns < n) { // skipped too few bytes
// adjust number to skip
n -= ns;
// read until requested number skipped or EOS reached
while (n > 0 && read() != -1) {
n--;
}
// if not enough skipped, then EOFE
if (n != 0) {
throw new IndexOutOfBoundsException();
}
} else if (ns != n) { // skipped negative or too many bytes
throw new IllegalArgumentException("Unable to skip exactly");
}
}
}
public int available() {
return 0;
}
public void close() {}
public synchronized void mark(int readlimit) {}
public synchronized void reset() {
throw new UnsupportedOperationException("mark/reset not supported");
}
public boolean markSupported() {
return false;
}
public long transferTo(OutputStream out) {
Objects.requireNonNull(out, "out");
long transferred = 0;
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
int read;
while ((read = this.read(buffer, 0, DEFAULT_BUFFER_SIZE)) >= 0) {
try {
out.write(buffer, 0, read);
} catch (IOException e) {
throw new IllegalStateException(e);
}
transferred += read;
}
return transferred;
}
}

View File

@ -1,28 +0,0 @@
package org.warp.commonutils.stream;
/*
* Copyright (C) 2005-2020 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.InputStream;
/** An {@link InputStream} that implements also the {@link SafeMeasurableStream} interface.
*
* @since 5.0.4
*/
public abstract class SafeMeasurableInputStream extends SafeInputStream implements SafeMeasurableStream {
}

View File

@ -1,27 +0,0 @@
package org.warp.commonutils.stream;
/*
* Copyright (C) 2005-2020 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.OutputStream;
/** An {@link OutputStream} that implements also the {@link SafeMeasurableStream} interface.
*
* @since 6.0.0
*/
public abstract class SafeMeasurableOutputStream extends SafeOutputStream implements SafeMeasurableStream {
}

View File

@ -1,49 +0,0 @@
package org.warp.commonutils.stream;
/*
* Copyright (C) 2005-2020 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** An stream that provides eager access to its length,
* and keeps track of the current position (e.g., the number of bytes read so far, or the current
* position of the file pointer).
*
* <p>This class has two methods, both specified as optional. This apparently bizarre
* behaviour is necessary because of wrapper classes which use reflection
* to support those methods (see, e.g., {@link MeasurableInputStream}, {@link FastBufferedInputStream} and {@link FastBufferedOutputStream}).
*
* @since 6.0.0
*/
public interface SafeMeasurableStream {
/** Returns the overall length of this stream (optional operation). In most cases, this will require the
* stream to perform some extra action, possibly changing the state of the input stream itself (typically, reading
* all the bytes up to the end, or flushing on output stream).
* Implementing classes should always document what state will the input stream be in
* after calling this method, and which kind of exception could be thrown.
*/
long length();
/** Returns the current position in this stream (optional operation).
*
* <p>Usually, the position is just the number of bytes read or written
* since the stream was opened, but in the case of a
* {@link it.unimi.dsi.fastutil.io.RepositionableStream} it
* represent the current position.
*/
long position();
}

View File

@ -1,169 +0,0 @@
package org.warp.commonutils.stream;
import java.io.Closeable;
import java.io.Flushable;
import java.io.OutputStream;
import java.util.Objects;
import org.jetbrains.annotations.NotNull;
/**
* This abstract class is the superclass of all classes representing
* an output stream of bytes. An output stream accepts output bytes
* and sends them to some sink.
* <p>
* Applications that need to define a subclass of
* {@code OutputStream} must always provide at least a method
* that writes one byte of output.
*
* @author Arthur van Hoff
* @see java.io.BufferedOutputStream
* @see java.io.ByteArrayOutputStream
* @see java.io.DataOutputStream
* @see java.io.FilterOutputStream
* @see java.io.InputStream
* @see java.io.OutputStream#write(int)
* @since 1.0
*/
public abstract class SafeOutputStream extends OutputStream implements Closeable, Flushable {
/**
* Constructor for subclasses to call.
*/
public SafeOutputStream() {}
/**
* Returns a new {@code OutputStream} which discards all bytes. The
* returned stream is initially open. The stream is closed by calling
* the {@code close()} method. Subsequent calls to {@code close()} have
* no effect.
*
* <p> While the stream is open, the {@code write(int)}, {@code
* write(byte[])}, and {@code write(byte[], int, int)} methods do nothing.
* After the stream has been closed, these methods all throw {@code
* IOException}.
*
* <p> The {@code flush()} method does nothing.
*
* @return an {@code OutputStream} which discards all bytes
*
* @since 11
*/
public static java.io.OutputStream nullOutputStream() {
return new java.io.OutputStream() {
private volatile boolean closed;
private void ensureOpen() {
if (closed) {
throw new IllegalStateException("Stream closed");
}
}
@Override
public void write(int b) {
ensureOpen();
}
@Override
public void write(byte @NotNull [] b, int off, int len) {
Objects.checkFromIndexSize(off, len, b.length);
ensureOpen();
}
@Override
public void close() {
closed = true;
}
};
}
/**
* Writes the specified byte to this output stream. The general
* contract for {@code write} is that one byte is written
* to the output stream. The byte to be written is the eight
* low-order bits of the argument {@code b}. The 24
* high-order bits of {@code b} are ignored.
* <p>
* Subclasses of {@code OutputStream} must provide an
* implementation for this method.
*
* @param b the {@code byte}.
*/
public abstract void write(int b);
/**
* Writes {@code b.length} bytes from the specified byte array
* to this output stream. The general contract for {@code write(b)}
* is that it should have exactly the same effect as the call
* {@code write(b, 0, b.length)}.
*
* @param b the data.
* @see java.io.OutputStream#write(byte[], int, int)
*/
public void write(byte @NotNull [] b) {
write(b, 0, b.length);
}
/**
* Writes {@code len} bytes from the specified byte array
* starting at offset {@code off} to this output stream.
* The general contract for {@code write(b, off, len)} is that
* some of the bytes in the array {@code b} are written to the
* output stream in order; element {@code b[off]} is the first
* byte written and {@code b[off+len-1]} is the last byte written
* by this operation.
* <p>
* The {@code write} method of {@code OutputStream} calls
* the write method of one argument on each of the bytes to be
* written out. Subclasses are encouraged to override this method and
* provide a more efficient implementation.
* <p>
* If {@code b} is {@code null}, a
* {@code NullPointerException} is thrown.
* <p>
* If {@code off} is negative, or {@code len} is negative, or
* {@code off+len} is greater than the length of the array
* {@code b}, then an {@code IndexOutOfBoundsException} is thrown.
*
* @param b the data.
* @param off the start offset in the data.
* @param len the number of bytes to write.
*/
public void write(byte[] b, int off, int len) {
Objects.checkFromIndexSize(off, len, b.length);
// len == 0 condition implicitly handled by loop bounds
for (int i = 0 ; i < len ; i++) {
write(b[off + i]);
}
}
/**
* Flushes this output stream and forces any buffered output bytes
* to be written out. The general contract of {@code flush} is
* that calling it is an indication that, if any bytes previously
* written have been buffered by the implementation of the output
* stream, such bytes should immediately be written to their
* intended destination.
* <p>
* If the intended destination of this stream is an abstraction provided by
* the underlying operating system, for example a file, then flushing the
* stream guarantees only that bytes previously written to the stream are
* passed to the operating system for writing; it does not guarantee that
* they are actually written to a physical device such as a disk drive.
* <p>
* The {@code flush} method of {@code OutputStream} does nothing.
*
*/
public void flush() {
}
/**
* Closes this output stream and releases any system resources
* associated with this stream. The general contract of {@code close}
* is that it closes the output stream. A closed stream cannot perform
* output operations and cannot be reopened.
* <p>
* The {@code close} method of {@code OutputStream} does nothing.
*
*/
public void close() {
}
}

View File

@ -1,332 +0,0 @@
package org.warp.commonutils.stream;
/**
* A {@code PushbackInputStream} adds
* functionality to another input stream, namely
* the ability to "push back" or "unread" bytes,
* by storing pushed-back bytes in an internal buffer.
* This is useful in situations where
* it is convenient for a fragment of code
* to read an indefinite number of data bytes
* that are delimited by a particular byte
* value; after reading the terminating byte,
* the code fragment can "unread" it, so that
* the next read operation on the input stream
* will reread the byte that was pushed back.
* For example, bytes representing the characters
* constituting an identifier might be terminated
* by a byte representing an operator character;
* a method whose job is to read just an identifier
* can read until it sees the operator and
* then push the operator back to be re-read.
*
* @author David Connelly
* @author Jonathan Payne
* @since 1.0
*/
public class SafePushbackInputStream extends SafeFilterInputStream {
/**
* The pushback buffer.
* @since 1.1
*/
protected byte[] buf;
/**
* The position within the pushback buffer from which the next byte will
* be read. When the buffer is empty, {@code pos} is equal to
* {@code buf.length}; when the buffer is full, {@code pos} is
* equal to zero.
*
* @since 1.1
*/
protected int pos;
/**
* Check to make sure that this stream has not been closed
*/
private void ensureOpen() {
if (in == null)
throw new IllegalStateException("Stream closed");
}
/**
* Creates a {@code PushbackInputStream}
* with a pushback buffer of the specified {@code size},
* and saves its argument, the input stream
* {@code in}, for later use. Initially,
* the pushback buffer is empty.
*
* @param in the input stream from which bytes will be read.
* @param size the size of the pushback buffer.
* @throws IllegalArgumentException if {@code size <= 0}
* @since 1.1
*/
public SafePushbackInputStream(SafeInputStream in, int size) {
super(in);
if (size <= 0) {
throw new IllegalArgumentException("size <= 0");
}
this.buf = new byte[size];
this.pos = size;
}
/**
* Creates a {@code PushbackInputStream}
* with a 1-byte pushback buffer, and saves its argument, the input stream
* {@code in}, for later use. Initially,
* the pushback buffer is empty.
*
* @param in the input stream from which bytes will be read.
*/
public SafePushbackInputStream(SafeInputStream in) {
this(in, 1);
}
/**
* Reads the next byte of data from this input stream. The value
* byte is returned as an {@code int} in the range
* {@code 0} to {@code 255}. If no byte is available
* because the end of the stream has been reached, the value
* {@code -1} is returned. This method blocks until input data
* is available, the end of the stream is detected, or an exception
* is thrown.
*
* <p> This method returns the most recently pushed-back byte, if there is
* one, and otherwise calls the {@code read} method of its underlying
* input stream and returns whatever value that method returns.
*
* @return the next byte of data, or {@code -1} if the end of the
* stream has been reached.
* or an I/O error occurs.
* @see java.io.InputStream#read()
*/
public int read() {
ensureOpen();
if (pos < buf.length) {
return buf[pos++] & 0xff;
}
return super.read();
}
/**
* Reads up to {@code len} bytes of data from this input stream into
* an array of bytes. This method first reads any pushed-back bytes; after
* that, if fewer than {@code len} bytes have been read then it
* reads from the underlying input stream. If {@code len} is not zero, the method
* blocks until at least 1 byte of input is available; otherwise, no
* bytes are read and {@code 0} is returned.
*
* @param b the buffer into which the data is read.
* @param off the start offset in the destination array {@code b}
* @param len the maximum number of bytes read.
* @return the total number of bytes read into the buffer, or
* {@code -1} if there is no more data because the end of
* the stream has been reached.
* @throws NullPointerException If {@code b} is {@code null}.
* @throws IndexOutOfBoundsException If {@code off} is negative,
* {@code len} is negative, or {@code len} is greater than
* {@code b.length - off}
* or an I/O error occurs.
* @see java.io.InputStream#read(byte[], int, int)
*/
public int read(byte[] b, int off, int len) {
ensureOpen();
if (b == null) {
throw new NullPointerException();
} else if (off < 0 || len < 0 || len > b.length - off) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}
int avail = buf.length - pos;
if (avail > 0) {
if (len < avail) {
avail = len;
}
System.arraycopy(buf, pos, b, off, avail);
pos += avail;
off += avail;
len -= avail;
}
if (len > 0) {
len = super.read(b, off, len);
if (len == -1) {
return avail == 0 ? -1 : avail;
}
return avail + len;
}
return avail;
}
/**
* Pushes back a byte by copying it to the front of the pushback buffer.
* After this method returns, the next byte to be read will have the value
* {@code (byte)b}.
*
* @param b the {@code int} value whose low-order
* byte is to be pushed back.
*/
public void unread(int b) {
ensureOpen();
if (pos == 0) {
throw new IllegalStateException("Push back buffer is full");
}
buf[--pos] = (byte)b;
}
/**
* Pushes back a portion of an array of bytes by copying it to the front
* of the pushback buffer. After this method returns, the next byte to be
* read will have the value {@code b[off]}, the byte after that will
* have the value {@code b[off+1]}, and so forth.
*
* @param b the byte array to push back.
* @param off the start offset of the data.
* @param len the number of bytes to push back.
* @throws NullPointerException If {@code b} is {@code null}.
* @since 1.1
*/
public void unread(byte[] b, int off, int len) {
ensureOpen();
if (len > pos) {
throw new IllegalStateException("Push back buffer is full");
}
pos -= len;
System.arraycopy(b, off, buf, pos, len);
}
/**
* Pushes back an array of bytes by copying it to the front of the
* pushback buffer. After this method returns, the next byte to be read
* will have the value {@code b[0]}, the byte after that will have the
* value {@code b[1]}, and so forth.
*
* @param b the byte array to push back
* @throws NullPointerException If {@code b} is {@code null}.
* @since 1.1
*/
public void unread(byte[] b) {
unread(b, 0, b.length);
}
/**
* Returns an estimate of the number of bytes that can be read (or
* skipped over) from this input stream without blocking by the next
* invocation of a method for this input stream. The next invocation might be
* the same thread or another thread. A single read or skip of this
* many bytes will not block, but may read or skip fewer bytes.
*
* <p> The method returns the sum of the number of bytes that have been
* pushed back and the value returned by {@link
* SafeFilterInputStream#available available}.
*
* @return the number of bytes that can be read (or skipped over) from
* the input stream without blocking.
* @see SafeFilterInputStream#in
* @see java.io.InputStream#available()
*/
public int available() {
ensureOpen();
int n = buf.length - pos;
int avail = super.available();
return n > (Integer.MAX_VALUE - avail)
? Integer.MAX_VALUE
: n + avail;
}
/**
* Skips over and discards {@code n} bytes of data from this
* input stream. The {@code skip} method may, for a variety of
* reasons, end up skipping over some smaller number of bytes,
* possibly zero. If {@code n} is negative, no bytes are skipped.
*
* <p> The {@code skip} method of {@code PushbackInputStream}
* first skips over the bytes in the pushback buffer, if any. It then
* calls the {@code skip} method of the underlying input stream if
* more bytes need to be skipped. The actual number of bytes skipped
* is returned.
*
* @param n {@inheritDoc}
* @return {@inheritDoc}
* @see SafeFilterInputStream#in
* @see java.io.InputStream#skip(long n)
* @since 1.2
*/
public long skip(long n) {
ensureOpen();
if (n <= 0) {
return 0;
}
long pskip = buf.length - pos;
if (pskip > 0) {
if (n < pskip) {
pskip = n;
}
pos += pskip;
n -= pskip;
}
if (n > 0) {
pskip += super.skip(n);
}
return pskip;
}
/**
* Tests if this input stream supports the {@code mark} and
* {@code reset} methods, which it does not.
*
* @return {@code false}, since this class does not support the
* {@code mark} and {@code reset} methods.
* @see java.io.InputStream#mark(int)
* @see java.io.InputStream#reset()
*/
public boolean markSupported() {
return false;
}
/**
* Marks the current position in this input stream.
*
* <p> The {@code mark} method of {@code PushbackInputStream}
* does nothing.
*
* @param readlimit the maximum limit of bytes that can be read before
* the mark position becomes invalid.
* @see java.io.InputStream#reset()
*/
public synchronized void mark(int readlimit) {
}
/**
* Repositions this stream to the position at the time the
* {@code mark} method was last called on this input stream.
*
* <p> The method {@code reset} for class
* {@code PushbackInputStream} does nothing except throw an
* {@code IOException}.
*
* @see java.io.InputStream#mark(int)
* @see java.io.IOException
*/
public synchronized void reset() {
throw new UnsupportedOperationException("mark/reset not supported");
}
/**
* Closes this input stream and releases any system resources
* associated with the stream.
* Once the stream has been closed, further read(), unread(),
* available(), reset(), or skip() invocations will throw an IOException.
* Closing a previously closed stream has no effect.
*
*/
public synchronized void close() {
if (in == null)
return;
in.close();
in = null;
buf = null;
}
}

View File

@ -1,40 +0,0 @@
package org.warp.commonutils.stream;
/*
* Copyright (C) 2005-2020 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** A basic interface specifying positioning methods for a byte stream.
*
* @author Sebastiano Vigna
* @since 4.4
*/
public interface SafeRepositionableStream {
/** Sets the current stream position.
*
* @param newPosition the new stream position.
*/
void position(long newPosition);
/** Returns the current stream position.
*
* @return the current stream position.
*/
long position();
}

View File

@ -1,10 +0,0 @@
package org.warp.commonutils.type;
public enum AddStrategy {
OVERWRITE_POSITION,
KEEP_POSITION;
public static AddStrategy getDefault() {
return KEEP_POSITION;
}
}

View File

@ -1,15 +0,0 @@
package org.warp.commonutils.type;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.util.Collection;
public class ArrayStack<T> extends FastUtilStackWrapper<T> {
public ArrayStack() {
super(new ObjectArrayList<>());
}
public ArrayStack(Collection<T> stack) {
super(new ObjectArrayList<>(stack));
}
}

View File

@ -1,68 +0,0 @@
package org.warp.commonutils.type;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jetbrains.annotations.NotNull;
public class Bytes {
public final byte[] data;
public Bytes(byte @NotNull[] data) {
this.data = data;
}
public static Map<? extends Bytes,? extends Bytes> ofMap(Map<byte[], byte[]> oldMap) {
var newMap = new HashMap<Bytes, Bytes>(oldMap.size());
oldMap.forEach((key, value) -> newMap.put(new Bytes(key), new Bytes(value)));
return newMap;
}
public static List<? extends Bytes> ofList(List<byte[]> oldList) {
var newList = new ArrayList<Bytes>(oldList.size());
oldList.forEach((item) -> newList.add(new Bytes(item)));
return newList;
}
public static Set<? extends Bytes> ofSet(Set<byte[]> oldSet) {
var newSet = new ObjectOpenHashSet<Bytes>(oldSet.size());
oldSet.forEach((item) -> newSet.add(new Bytes(item)));
return newSet;
}
public static byte[][] toByteArray(Collection<Bytes> value) {
Bytes[] valueBytesArray = value.toArray(Bytes[]::new);
byte[][] convertedResult = new byte[valueBytesArray.length][];
for (int i = 0; i < valueBytesArray.length; i++) {
convertedResult[i] = valueBytesArray[i].data;
}
return convertedResult;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Bytes that = (Bytes) o;
return Arrays.equals(data, that.data);
}
@Override
public int hashCode() {
return Arrays.hashCode(data);
}
@Override
public String toString() {
return Arrays.toString(data);
}
}

View File

@ -1,35 +0,0 @@
package org.warp.commonutils.type;
import java.util.Objects;
public class EqualsWrapper<T> {
private final T value;
private final Object equal;
public EqualsWrapper(T value, Object equal) {
this.value = value;
this.equal = equal;
}
public T get() {
return value;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
EqualsWrapper<?> that = (EqualsWrapper<?>) o;
return Objects.equals(equal, that.equal);
}
@Override
public int hashCode() {
return Objects.hash(equal);
}
}

View File

@ -1,128 +0,0 @@
package org.warp.commonutils.type;
import java.util.Collection;
import java.util.Iterator;
import java.util.Objects;
import java.util.StringJoiner;
import org.jetbrains.annotations.NotNull;
public class FastUtilStackWrapper<T> implements Stack<T>, Collection<T> {
private final it.unimi.dsi.fastutil.Stack<T> stack;
private final Collection<T> collection;
public <U extends it.unimi.dsi.fastutil.Stack<T> & Collection<T>> FastUtilStackWrapper(U stack) {
this.stack = stack;
this.collection = stack;
}
@Override
public void push(T o) {
this.stack.push(o);
}
@Override
public T pop() {
return this.stack.pop();
}
@Override
public T peek(int n) {
return this.stack.peek(n);
}
@Override
public int size() {
return collection.size();
}
@Override
public boolean isEmpty() {
return this.stack.isEmpty();
}
@Override
public boolean contains(Object o) {
return collection.contains(o);
}
@NotNull
@Override
public Iterator<T> iterator() {
return collection.iterator();
}
@NotNull
@Override
public Object @NotNull [] toArray() {
return collection.toArray();
}
@NotNull
@Override
public <T1> T1 @NotNull [] toArray(@NotNull T1 @NotNull [] a) {
//noinspection SuspiciousToArrayCall
return collection.toArray(a);
}
@Override
public boolean add(T t) {
return collection.add(t);
}
@Override
public boolean remove(Object o) {
return collection.remove(o);
}
@Override
public boolean containsAll(@NotNull Collection<?> c) {
return collection.containsAll(c);
}
@Override
public boolean addAll(@NotNull Collection<? extends T> c) {
return collection.addAll(c);
}
@Override
public boolean removeAll(@NotNull Collection<?> c) {
return collection.removeAll(c);
}
@Override
public boolean retainAll(@NotNull Collection<?> c) {
return collection.retainAll(c);
}
@Override
public void clear() {
collection.clear();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
FastUtilStackWrapper<?> that = (FastUtilStackWrapper<?>) o;
return Objects.equals(stack, that.stack);
}
@Override
public int hashCode() {
return stack != null ? stack.hashCode() : 0;
}
@Override
public String toString() {
return new StringJoiner(", ", FastUtilStackWrapper.class.getSimpleName() + "[", "]")
.add("stack=" + stack)
.toString();
}
}

View File

@ -1,157 +0,0 @@
package org.warp.commonutils.type;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.function.IntFunction;
import java.util.function.Predicate;
import java.util.stream.Stream;
import org.jetbrains.annotations.NotNull;
public class ImmutableLinkedSet<E> implements Set<E> {
private final LinkedHashSet<E> set;
public ImmutableLinkedSet(LinkedHashSet<E> set) {
this.set = set;
}
@Override
public int size() {
return set.size();
}
@Override
public boolean isEmpty() {
return set.isEmpty();
}
@Override
public boolean contains(Object o) {
return set.contains(o);
}
@NotNull
@Override
public Iterator<E> iterator() {
var it = set.iterator();
return new Iterator<>() {
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
public E next() {
return it.next();
}
};
}
@Override
public void forEach(Consumer<? super E> action) {
set.forEach(action);
}
@NotNull
@Override
public Object @NotNull [] toArray() {
return set.toArray();
}
@NotNull
@Override
public <T> T @NotNull [] toArray(@NotNull T @NotNull [] a) {
//noinspection SuspiciousToArrayCall
return set.toArray(a);
}
@Override
public <T> T[] toArray(IntFunction<T[]> generator) {
//noinspection SuspiciousToArrayCall
return set.toArray(generator);
}
@Override
public boolean add(E e) {
throw new UnsupportedOperationException("Read only");
}
@Override
public boolean remove(Object o) {
throw new UnsupportedOperationException("Read only");
}
@Override
public boolean containsAll(@NotNull Collection<?> c) {
return set.containsAll(c);
}
@Override
public boolean addAll(@NotNull Collection<? extends E> c) {
throw new UnsupportedOperationException("Read only");
}
@Override
public boolean retainAll(@NotNull Collection<?> c) {
throw new UnsupportedOperationException("Read only");
}
@Override
public boolean removeAll(@NotNull Collection<?> c) {
throw new UnsupportedOperationException("Read only");
}
@Override
public boolean removeIf(Predicate<? super E> filter) {
throw new UnsupportedOperationException("Read only");
}
@Override
public void clear() {
throw new UnsupportedOperationException("Read only");
}
@Override
public Spliterator<E> spliterator() {
var spl = set.spliterator();
return new Spliterator<>() {
@Override
public boolean tryAdvance(Consumer<? super E> action) {
return spl.tryAdvance(action);
}
@Override
public Spliterator<E> trySplit() {
return spl.trySplit();
}
@Override
public long estimateSize() {
return spl.estimateSize();
}
@Override
public int characteristics() {
return spl.characteristics();
}
};
}
@Override
public Stream<E> stream() {
return set.stream();
}
@Override
public Stream<E> parallelStream() {
return set.parallelStream();
}
public LinkedHashSet<E> copyMutable() {
return new LinkedHashSet<>(set);
}
}

View File

@ -1,116 +0,0 @@
package org.warp.commonutils.type;
import it.unimi.dsi.fastutil.objects.ObjectSet;
import java.util.Set;
/**
* One to many relationship
*
* o ------- o
* +--- o
* o ---+--- o
* +-|- o
* o -----|- o
* o ------- o
* o ---+--- o
* +--- o
*
* @param <T> Source type
* @param <U> Destination type
*/
public interface MultiAssociation<T, U> {
/**
* Link source to dest
* @param src Source
* @param dest Destination
* @return true if linked, false if it was already linked with that destination
*/
boolean link(T src, U dest);
/**
* Unlink only if src is linked with dest
* @param src Source
* @param dest Destination
* @return true if unlinked, false if not present
*/
boolean unlink(T src, U dest);
/**
* Unlink
* @param src Source
* @return previous linked destinations
*/
Set<U> unlink(T src);
/**
* Unlink
* @param dest Destination
* @return previous linked source
*/
Set<T> unlinkFromSource(U dest);
/**
* Check if link exists
* @param src Source
* @return true if source is linked with at least 1 destination
*/
default boolean hasAnyLink(T src) {
return !getLinks(src).isEmpty();
}
/**
* Check if link exists
* @param dest Destination
* @return true if destination is linked with at least 1 destination
*/
default boolean hasAnyLinkSource(U dest) {
return !getLinkSources(dest).isEmpty();
}
/**
* Check if link exists
* @param src Source
* @param dest Destination
* @return true if source and destination are linked together
*/
boolean hasLink(T src, U dest);
/**
* Get a link destination
* @param src Source
* @return Existing linked destinations
*/
Set<U> getLinks(T src);
/**
* Get a link source
* @param dest Source
* @return Existing linked sources
*/
Set<T> getLinkSources(U dest);
/**
* Delete all links
*/
void clear();
/**
* Get the count of existing links
* @return size
*/
int size();
/**
* Get all the sources
* @return Set of sources
*/
ObjectSet<T> getSources();
/**
* Get all the destinations
* @return Set of destinations
*/
ObjectSet<U> getDestinations();
}

View File

@ -1,86 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.warp.commonutils.type;
import java.util.Locale;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
import org.jetbrains.annotations.NotNull;
/**
* A default {@link ThreadFactory} implementation that accepts the name prefix
* of the created threads as a constructor argument. Otherwise, this factory
* yields the same semantics as the thread factory returned by
* {@link Executors#defaultThreadFactory()}.
*/
public class ShortNamedThreadFactory implements ThreadFactory {
private static int POOL_NUMBERS_COUNT = 50;
private static final AtomicInteger[] threadPoolNumber = new AtomicInteger[POOL_NUMBERS_COUNT];
static {
for (int i = 0; i < threadPoolNumber.length; i++) {
threadPoolNumber[i] = new AtomicInteger(1);
}
}
private ThreadGroup group;
private boolean daemon;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private static final String NAME_PATTERN = "%s-%d";
private final String threadNamePrefix;
/**
* Creates a new {@link ShortNamedThreadFactory} instance
*
* @param threadNamePrefix the name prefix assigned to each thread created.
*/
public ShortNamedThreadFactory(String threadNamePrefix) {
group = Thread.currentThread().getThreadGroup();
this.threadNamePrefix = String.format(Locale.ROOT, NAME_PATTERN,
checkPrefix(threadNamePrefix), threadPoolNumber[(threadNamePrefix.hashCode() % POOL_NUMBERS_COUNT / 2) + POOL_NUMBERS_COUNT / 2].getAndIncrement());
}
public ShortNamedThreadFactory withGroup(ThreadGroup threadGroup) {
this.group = threadGroup;
return this;
}
public ShortNamedThreadFactory setDaemon(boolean daemon) {
this.daemon = daemon;
return this;
}
private static String checkPrefix(String prefix) {
return prefix == null || prefix.length() == 0 ? "Unnamed" : prefix;
}
/**
* Creates a new {@link Thread}
*
* @see java.util.concurrent.ThreadFactory#newThread(java.lang.Runnable)
*/
@Override
public Thread newThread(@NotNull Runnable r) {
final Thread t = new Thread(group, r, String.format(Locale.ROOT, "%s-%d",
this.threadNamePrefix, threadNumber.getAndIncrement()), 0);
t.setDaemon(daemon);
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}

View File

@ -1,43 +0,0 @@
package org.warp.commonutils.type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.warp.commonutils.error.IndexOutOfBoundsException;
/**
* A stack
*
* <p>A stack must provide the classical {@link #push(Object)} and
* {@link #pop()} operations, but may be also <em>peekable</em> to some extent: it may provide just the {@link #top()}
* function, or even a more powerful {@link #peek(int)} method that provides access to all elements on the stack
* (indexed from the top, which has index 0).
*/
public interface Stack<K> extends it.unimi.dsi.fastutil.Stack<K> {
/**
* Pop multiple times
* @param count the number of times to pop
* @return list of popped elements
*/
default List<K> pop(int count) {
if (count < 0) {
throw new IndexOutOfBoundsException(count);
}
var items = new ArrayList<K>(count);
for (int i = 0; i < count; i++) {
items.add(this.pop());
}
return items;
}
static <T> Stack<T> create() {
return new ArrayStack<>();
}
static <T, U extends Stack<T> & Collection<T>> Stack<T> wrap(U stack) {
return new FastUtilStackWrapper<>(stack);
}
}

View File

@ -1,10 +0,0 @@
package org.warp.commonutils.type;
public class VariableWrapper<T> {
public volatile T var;
public VariableWrapper(T value) {
this.var = value;
}
}