diff --git a/.github/workflows/maven-publish.yml b/.github/workflows/maven-publish.yml new file mode 100644 index 0000000..1f416ae --- /dev/null +++ b/.github/workflows/maven-publish.yml @@ -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 }} \ No newline at end of file diff --git a/pom.xml b/pom.xml index f32339f..e292253 100644 --- a/pom.xml +++ b/pom.xml @@ -5,11 +5,12 @@ jar 4.0.0 - common-utils - org.warp - 1.1.8 + it.tdlight + common-util + ${revision} + 1.0.0-SNAPSHOT UTF-8 @@ -35,6 +36,11 @@ + + org.jctools + jctools-core + 4.0.1 + org.junit.jupiter junit-jupiter-api @@ -47,65 +53,6 @@ - - it.unimi.dsi - fastutil - 8.5.8 - - - org.apache.commons - commons-lang3 - 3.12.0 - - - org.jetbrains - annotations - 23.0.0 - compile - - - com.google.guava - guava - 31.1-jre - - - com.squareup.moshi - moshi - 1.13.0 - - - org.jetbrains.kotlin - kotlin-stdlib - - - org.jetbrains.kotlin - kotlin-stdlib-common - - - - - dev.zacsweers.moshix - moshi-records-reflect - 0.14.1 - - - com.squareup.moshi - moshi - - - - - org.jetbrains.kotlin - - kotlin-stdlib - 1.6.0 - - - org.jetbrains - annotations - - - @@ -115,7 +62,7 @@ 3.8.1 UTF-8 - 11 + 8 @@ -136,6 +83,31 @@ + + org.codehaus.mojo + flatten-maven-plugin + 1.1.0 + + true + oss + + + + flatten + process-resources + + flatten + + + + flatten.clean + clean + + clean + + + + \ No newline at end of file diff --git a/src/main/java/edu/rice/cs/util/ArgumentTokenizer.java b/src/main/java/edu/rice/cs/util/ArgumentTokenizer.java deleted file mode 100644 index 7198e74..0000000 --- a/src/main/java/edu/rice/cs/util/ArgumentTokenizer.java +++ /dev/null @@ -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 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 tokenize(String arguments, boolean stringify) { - - LinkedList argList = new LinkedList(); - 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(); - } -} diff --git a/src/main/java/it/tdlight/commonutil/IntIterator.java b/src/main/java/it/tdlight/commonutil/IntIterator.java new file mode 100644 index 0000000..35d7be6 --- /dev/null +++ b/src/main/java/it/tdlight/commonutil/IntIterator.java @@ -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(); +} diff --git a/src/main/java/it/tdlight/commonutil/LongIterator.java b/src/main/java/it/tdlight/commonutil/LongIterator.java new file mode 100644 index 0000000..918404d --- /dev/null +++ b/src/main/java/it/tdlight/commonutil/LongIterator.java @@ -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 { + /** + * Returns the next long value without auto-boxing. Using this is preferred to {@link #next()}. + * + * @return The next long value. + */ + long nextLong(); +} diff --git a/src/main/java/it/tdlight/commonutil/NonBlockingHashSetLong.java b/src/main/java/it/tdlight/commonutil/NonBlockingHashSetLong.java new file mode 100644 index 0000000..066ddf5 --- /dev/null +++ b/src/main/java/it/tdlight/commonutil/NonBlockingHashSetLong.java @@ -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 implements Serializable { + private static final Object V = ""; + + private final NonBlockingHashMapLong _map; + + /** Make a new empty {@link NonBlockingHashSetLong}. */ + public NonBlockingHashSetLong() { + super(); + _map = new NonBlockingHashMapLong(); + } + + @Override + public boolean addAll(Collection 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 true if {@code o} was added to the set, false + * 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 true 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 true if {@code o} was removed to the set, false + * 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 Iteratoriterator() { 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). + * + *

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"); + } +} diff --git a/src/main/java/it/tdlight/commonutil/NonBlockingSetInt.java b/src/main/java/it/tdlight/commonutil/NonBlockingSetInt.java new file mode 100644 index 0000000..9207cfb --- /dev/null +++ b/src/main/java/it/tdlight/commonutil/NonBlockingSetInt.java @@ -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. + * + *

General note of caution: 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. + * + *

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 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 { // + 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 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 true 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 true 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 true 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 true 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 true 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 true 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 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 { + 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= 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 { // + 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>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 { - - void consume(T t, U u) throws IOException; -} diff --git a/src/main/java/org/warp/commonutils/functional/IOBooleanSupplier.java b/src/main/java/org/warp/commonutils/functional/IOBooleanSupplier.java deleted file mode 100644 index c2912cc..0000000 --- a/src/main/java/org/warp/commonutils/functional/IOBooleanSupplier.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.warp.commonutils.functional; - -import java.io.IOException; - -public interface IOBooleanSupplier { - - boolean get() throws IOException; -} diff --git a/src/main/java/org/warp/commonutils/functional/IOCompletableFunction.java b/src/main/java/org/warp/commonutils/functional/IOCompletableFunction.java deleted file mode 100644 index e040a3a..0000000 --- a/src/main/java/org/warp/commonutils/functional/IOCompletableFunction.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.warp.commonutils.functional; - -import java.io.IOException; -import java.util.concurrent.CompletableFuture; - -public interface IOCompletableFunction { - CompletableFuture apply(T value) throws IOException; -} diff --git a/src/main/java/org/warp/commonutils/functional/IOConsumer.java b/src/main/java/org/warp/commonutils/functional/IOConsumer.java deleted file mode 100644 index 09b779a..0000000 --- a/src/main/java/org/warp/commonutils/functional/IOConsumer.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.warp.commonutils.functional; - -import java.io.IOException; - -public interface IOConsumer { - - void consume(T value) throws IOException; -} diff --git a/src/main/java/org/warp/commonutils/functional/IOFunction.java b/src/main/java/org/warp/commonutils/functional/IOFunction.java deleted file mode 100644 index e5704c3..0000000 --- a/src/main/java/org/warp/commonutils/functional/IOFunction.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.warp.commonutils.functional; - -import java.io.IOException; - -public interface IOFunction { - - U apply(T data) throws IOException; -} diff --git a/src/main/java/org/warp/commonutils/functional/IOIntegerSupplier.java b/src/main/java/org/warp/commonutils/functional/IOIntegerSupplier.java deleted file mode 100644 index b311899..0000000 --- a/src/main/java/org/warp/commonutils/functional/IOIntegerSupplier.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.warp.commonutils.functional; - -import java.io.IOException; - -public interface IOIntegerSupplier { - - int get() throws IOException; -} diff --git a/src/main/java/org/warp/commonutils/functional/IOLongSupplier.java b/src/main/java/org/warp/commonutils/functional/IOLongSupplier.java deleted file mode 100644 index 78bed27..0000000 --- a/src/main/java/org/warp/commonutils/functional/IOLongSupplier.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.warp.commonutils.functional; - -import java.io.IOException; - -public interface IOLongSupplier { - - long get() throws IOException; -} diff --git a/src/main/java/org/warp/commonutils/functional/IORunnable.java b/src/main/java/org/warp/commonutils/functional/IORunnable.java deleted file mode 100644 index 20431e6..0000000 --- a/src/main/java/org/warp/commonutils/functional/IORunnable.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.warp.commonutils.functional; - -import java.io.IOException; - -public interface IORunnable { - - void run() throws IOException; -} diff --git a/src/main/java/org/warp/commonutils/functional/IOSupplier.java b/src/main/java/org/warp/commonutils/functional/IOSupplier.java deleted file mode 100644 index 1c26436..0000000 --- a/src/main/java/org/warp/commonutils/functional/IOSupplier.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.warp.commonutils.functional; - -import java.io.IOException; - -public interface IOSupplier { - - T get() throws IOException; -} diff --git a/src/main/java/org/warp/commonutils/functional/IOTriConsumer.java b/src/main/java/org/warp/commonutils/functional/IOTriConsumer.java deleted file mode 100644 index 6b496a3..0000000 --- a/src/main/java/org/warp/commonutils/functional/IOTriConsumer.java +++ /dev/null @@ -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. - * - *

This is a functional interface - * whose functional method is {@link #accept(Object, Object, Object)}. - * - * @param the type of the first argument to the operation - * @param the type of the second argument to the operation - * @param the type of the thord argument to the operation - * - * @see Consumer - * @since 1.8 - */ -@FunctionalInterface -public interface IOTriConsumer { - - /** - * 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 andThen(IOTriConsumer after) { - Objects.requireNonNull(after); - - return (l, r, u) -> { - accept(l, r, u); - after.accept(l, r, u); - }; - } -} diff --git a/src/main/java/org/warp/commonutils/functional/TriConsumer.java b/src/main/java/org/warp/commonutils/functional/TriConsumer.java deleted file mode 100644 index e7c19bb..0000000 --- a/src/main/java/org/warp/commonutils/functional/TriConsumer.java +++ /dev/null @@ -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. - * - *

This is a functional interface - * whose functional method is {@link #accept(Object, Object, Object)}. - * - * @param the type of the first argument to the operation - * @param the type of the second argument to the operation - * @param the type of the thord argument to the operation - * - * @see Consumer - * @since 1.8 - */ -@FunctionalInterface -public interface TriConsumer { - - /** - * 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 andThen(org.warp.commonutils.functional.TriConsumer after) { - Objects.requireNonNull(after); - - return (l, r, u) -> { - accept(l, r, u); - after.accept(l, r, u); - }; - } -} diff --git a/src/main/java/org/warp/commonutils/functional/TriFunction.java b/src/main/java/org/warp/commonutils/functional/TriFunction.java deleted file mode 100644 index 3e5abf9..0000000 --- a/src/main/java/org/warp/commonutils/functional/TriFunction.java +++ /dev/null @@ -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}. - * - *

This is a functional interface - * whose functional method is {@link #apply(Object, Object, Object)}. - * - * @param the type of the first argument to the function - * @param the type of the second argument to the function - * @param the type of the third argument to the function - * @param the type of the result of the function - * - * @see Function - * @since 1.8 - */ -@FunctionalInterface -public interface TriFunction { - - /** - * 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 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 org.warp.commonutils.functional.TriFunction andThen(Function after) { - Objects.requireNonNull(after); - return (T t, U u, X x) -> after.apply(apply(t, u, x)); - } -} diff --git a/src/main/java/org/warp/commonutils/locks/LockUtils.java b/src/main/java/org/warp/commonutils/locks/LockUtils.java deleted file mode 100644 index 137149c..0000000 --- a/src/main/java/org/warp/commonutils/locks/LockUtils.java +++ /dev/null @@ -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 lock(@Nullable Lock lock, @NotNull Supplier r) { - if (lock != null) { - lock.lock(); - } - try { - return r.get(); - } finally { - if (lock != null) { - lock.unlock(); - } - } - } - - public static T readLock(@Nullable StampedLock lock, @NotNull Supplier 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 writeLock(@Nullable StampedLock lock, @NotNull Supplier 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 lockIO(@Nullable Lock lock, @NotNull IOSupplier r) throws IOException { - if (lock != null) { - lock.lock(); - } - try { - return r.get(); - } finally { - if (lock != null) { - lock.unlock(); - } - } - } - - public static T readLockIO(@Nullable StampedLock lock, @NotNull IOSupplier 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 writeLockIO(@Nullable StampedLock lock, @NotNull IOSupplier 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); - } - } - } -} diff --git a/src/main/java/org/warp/commonutils/moshi/BooleanListJsonAdapter.java b/src/main/java/org/warp/commonutils/moshi/BooleanListJsonAdapter.java deleted file mode 100644 index 2f5a2b1..0000000 --- a/src/main/java/org/warp/commonutils/moshi/BooleanListJsonAdapter.java +++ /dev/null @@ -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 { - - @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(); - } -} diff --git a/src/main/java/org/warp/commonutils/moshi/ByteListJsonAdapter.java b/src/main/java/org/warp/commonutils/moshi/ByteListJsonAdapter.java deleted file mode 100644 index b5b7d46..0000000 --- a/src/main/java/org/warp/commonutils/moshi/ByteListJsonAdapter.java +++ /dev/null @@ -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 { - - @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(); - } -} diff --git a/src/main/java/org/warp/commonutils/moshi/CharListJsonAdapter.java b/src/main/java/org/warp/commonutils/moshi/CharListJsonAdapter.java deleted file mode 100644 index fd971b2..0000000 --- a/src/main/java/org/warp/commonutils/moshi/CharListJsonAdapter.java +++ /dev/null @@ -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 { - - @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(); - } -} diff --git a/src/main/java/org/warp/commonutils/moshi/IntListJsonAdapter.java b/src/main/java/org/warp/commonutils/moshi/IntListJsonAdapter.java deleted file mode 100644 index d531335..0000000 --- a/src/main/java/org/warp/commonutils/moshi/IntListJsonAdapter.java +++ /dev/null @@ -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 { - - @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(); - } -} diff --git a/src/main/java/org/warp/commonutils/moshi/LongListJsonAdapter.java b/src/main/java/org/warp/commonutils/moshi/LongListJsonAdapter.java deleted file mode 100644 index c5dd5ad..0000000 --- a/src/main/java/org/warp/commonutils/moshi/LongListJsonAdapter.java +++ /dev/null @@ -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 { - - @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(); - } -} diff --git a/src/main/java/org/warp/commonutils/moshi/MoshiPolymorphic.java b/src/main/java/org/warp/commonutils/moshi/MoshiPolymorphic.java deleted file mode 100644 index e340b3f..0000000 --- a/src/main/java/org/warp/commonutils/moshi/MoshiPolymorphic.java +++ /dev/null @@ -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 { - - 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> abstractClassesSerializers = new ConcurrentHashMap<>(); - private final Map>> abstractListClassesSerializers = new ConcurrentHashMap<>(); - private final Map> concreteClassesSerializers = new ConcurrentHashMap<>(); - private final Map>> concreteListClassesSerializers = new ConcurrentHashMap<>(); - private final Map> extraClassesSerializers = new ConcurrentHashMap<>(); - private final Map> 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 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 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> getAbstractClasses(); - - protected abstract Set> getConcreteClasses(); - - protected Map, 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 extends JsonAdapter { - - 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 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 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 extends JsonAdapter { - - private final String adapterName; - private final Options names; - private final Class declaredClass; - private final List declaredFields; - private final Function[] 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.get(fieldType).toJson(jsonWriter, (OBJ) fieldGetters[i].apply(t)); - } else if (concreteClassesSerializers.containsKey(fieldType)) { - //noinspection unchecked - concreteClassesSerializers.get(fieldType).toJson(jsonWriter, (OBJ) fieldGetters[i].apply(t)); - } else { - abstractMoshi.adapter(fieldType).toJson(jsonWriter, fieldGetters[i].apply(t)); - } - i++; - } - jsonWriter.endObject(); - } - } - } - - private static class ListValueAdapter extends JsonAdapter> { - - private final JsonAdapter valueAdapter; - - public ListValueAdapter(JsonAdapter valueAdapter) { - this.valueAdapter = valueAdapter; - } - - @Nullable - @Override - public List fromJson(@NotNull JsonReader jsonReader) throws IOException { - jsonReader.beginArray(); - var result = new ArrayList(); - while (jsonReader.hasNext()) { - result.add(valueAdapter.fromJson(jsonReader)); - } - jsonReader.endArray(); - return Collections.unmodifiableList(result); - } - - @Override - public void toJson(@NotNull JsonWriter jsonWriter, @Nullable List 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); - } -} \ No newline at end of file diff --git a/src/main/java/org/warp/commonutils/moshi/ShortListJsonAdapter.java b/src/main/java/org/warp/commonutils/moshi/ShortListJsonAdapter.java deleted file mode 100644 index 761939e..0000000 --- a/src/main/java/org/warp/commonutils/moshi/ShortListJsonAdapter.java +++ /dev/null @@ -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 { - - @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(); - } -} diff --git a/src/main/java/org/warp/commonutils/random/LFSR.java b/src/main/java/org/warp/commonutils/random/LFSR.java deleted file mode 100644 index a3fba5b..0000000 --- a/src/main/java/org/warp/commonutils/random/LFSR.java +++ /dev/null @@ -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 - *

- * 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 { - - 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 { - // 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); - } -} \ No newline at end of file diff --git a/src/main/java/org/warp/commonutils/range/MappedRanges.java b/src/main/java/org/warp/commonutils/range/MappedRanges.java deleted file mode 100644 index 8ca2464..0000000 --- a/src/main/java/org/warp/commonutils/range/MappedRanges.java +++ /dev/null @@ -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 { - - private final Object2ObjectMap 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 replaceWhenSplitting, Function cloneWhenSplitting) { - if (start > end) { - throw new IndexOutOfBoundsException(); - } - Object2ObjectOpenHashMap rangesToAdd = new Object2ObjectOpenHashMap<>(); - ObjectOpenHashSet 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 replaceWhenOverlapping, Function cloneWhenSplitting) { - if (start > end) { - throw new IndexOutOfBoundsException(); - } - Object2ObjectOpenHashMap rangesToTransform = new Object2ObjectOpenHashMap<>(); - Object2ObjectOpenHashMap rangesToAdd = new Object2ObjectOpenHashMap<>(); - ObjectOpenHashSet 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 getRanges() { - Object2ObjectSortedMap a = new Object2ObjectRBTreeMap<>(Comparator.comparingLong(UnmodifiableRange::getStart)); - ranges.forEach((range, value) -> a.put(range.unmodifiableClone(), value)); - return Object2ObjectMaps.unmodifiable(a); - } -} diff --git a/src/main/java/org/warp/commonutils/range/Range.java b/src/main/java/org/warp/commonutils/range/Range.java deleted file mode 100644 index 26093a5..0000000 --- a/src/main/java/org/warp/commonutils/range/Range.java +++ /dev/null @@ -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); - } -} diff --git a/src/main/java/org/warp/commonutils/range/Ranges.java b/src/main/java/org/warp/commonutils/range/Ranges.java deleted file mode 100644 index 3f140cd..0000000 --- a/src/main/java/org/warp/commonutils/range/Ranges.java +++ /dev/null @@ -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 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 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 getRanges() { - ObjectSortedSet a = new ObjectRBTreeSet<>(Comparator.comparingLong(UnmodifiableRange::getStart)); - ranges.forEach((range) -> a.add(range.unmodifiableClone())); - return ObjectSortedSets.unmodifiable(a); - } -} diff --git a/src/main/java/org/warp/commonutils/range/UnmodifiableRange.java b/src/main/java/org/warp/commonutils/range/UnmodifiableRange.java deleted file mode 100644 index bce0655..0000000 --- a/src/main/java/org/warp/commonutils/range/UnmodifiableRange.java +++ /dev/null @@ -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); - } -} diff --git a/src/main/java/org/warp/commonutils/serialization/UTFUtils.java b/src/main/java/org/warp/commonutils/serialization/UTFUtils.java deleted file mode 100644 index 67b278b..0000000 --- a/src/main/java/org/warp/commonutils/serialization/UTFUtils.java +++ /dev/null @@ -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); - } -} diff --git a/src/main/java/org/warp/commonutils/stream/ByteBufferBackedInputStream.java b/src/main/java/org/warp/commonutils/stream/ByteBufferBackedInputStream.java deleted file mode 100644 index 3f4bc37..0000000 --- a/src/main/java/org/warp/commonutils/stream/ByteBufferBackedInputStream.java +++ /dev/null @@ -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; - } -} \ No newline at end of file diff --git a/src/main/java/org/warp/commonutils/stream/DataInputOutput.java b/src/main/java/org/warp/commonutils/stream/DataInputOutput.java deleted file mode 100644 index 7435511..0000000 --- a/src/main/java/org/warp/commonutils/stream/DataInputOutput.java +++ /dev/null @@ -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(); -} diff --git a/src/main/java/org/warp/commonutils/stream/DataInputOutputImpl.java b/src/main/java/org/warp/commonutils/stream/DataInputOutputImpl.java deleted file mode 100644 index 9acf2fe..0000000 --- a/src/main/java/org/warp/commonutils/stream/DataInputOutputImpl.java +++ /dev/null @@ -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); - } -} diff --git a/src/main/java/org/warp/commonutils/stream/DataInputOutputStream.java b/src/main/java/org/warp/commonutils/stream/DataInputOutputStream.java deleted file mode 100644 index 16a1a3a..0000000 --- a/src/main/java/org/warp/commonutils/stream/DataInputOutputStream.java +++ /dev/null @@ -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(); - } -} diff --git a/src/main/java/org/warp/commonutils/stream/SafeDataInputStream.java b/src/main/java/org/warp/commonutils/stream/SafeDataInputStream.java deleted file mode 100644 index e5a3936..0000000 --- a/src/main/java/org/warp/commonutils/stream/SafeDataInputStream.java +++ /dev/null @@ -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. - *

- * 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. - * - *

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}. - * - *

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. - * - *

The {@code read(b)} method has the same effect as: - *

-	 * read(b, 0, b.length)
-	 * 
- * - * @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. - * - *

This method blocks until input data is available, end of file is - * detected, or an exception is thrown. - * - *

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}. - * - *

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 k be the number of - * bytes actually read; these bytes will be stored in elements - * {@code b[off]} through {@code b[off+}k{@code -1]}, - * leaving elements {@code b[off+}k{@code ]} through - * {@code b[off+len-1]} unaffected. - * - *

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}. - *

- * 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}. - *

- * 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}. - *

- * 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 0)) { - total += cur; - } - - return total; - } - - /** - * See the general contract of the {@code readBoolean} - * method of {@code DataInput}. - *

- * 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}. - *

- * 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}. - *

- * 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}. - *

- * 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}. - *

- * 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}. - *

- * 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}. - *

- * 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}. - *

- * 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}. - *

- * 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}. - *

- * 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}. - *

- * Bytes - * for this operation are read from the contained - * input stream. - * - * @deprecated This method does not properly convert bytes to characters. - * As of JDK 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: - *

-	 *     DataInputStream d = new DataInputStream(in);
-	 * 
- * with: - *
-	 *     BufferedReader d
-	 *          = new BufferedReader(new InputStreamReader(in));
-	 * 
- * - * @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}. - *

- * 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 - * modified UTF-8 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); - } -} diff --git a/src/main/java/org/warp/commonutils/stream/SafeDataOutput.java b/src/main/java/org/warp/commonutils/stream/SafeDataOutput.java deleted file mode 100644 index a48aa34..0000000 --- a/src/main/java/org/warp/commonutils/stream/SafeDataOutput.java +++ /dev/null @@ -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 - * modified UTF-8 - * format and writing the resulting series - * of bytes. - *

- * 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: - *

{@code
-	 * (byte)(0xff & (v >> 8))
-	 * (byte)(0xff & v)
-	 * }

- * 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: - *

{@code
-	 * (byte)(0xff & (v >> 8))
-	 * (byte)(0xff & v)
-	 * }

- * 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: - *

{@code
-	 * (byte)(0xff & (v >> 24))
-	 * (byte)(0xff & (v >> 16))
-	 * (byte)(0xff & (v >>  8))
-	 * (byte)(0xff & v)
-	 * }

- * 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: - *

{@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)
-	 * }

- * 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.

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 - * modified UTF-8 - * 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.

- * If a character {@code c} - * is in the range \u0001 through - * \u007f, it is represented - * by one byte: - *

(byte)c 

- * If a character {@code c} is \u0000 - * or is in the range \u0080 - * through \u07ff, then it is - * represented by two bytes, to be written - * in the order shown:

{@code
-	 * (byte)(0xc0 | (0x1f & (c >> 6)))
-	 * (byte)(0x80 | (0x3f & c))
-	 * }

If a character - * {@code c} is in the range \u0800 - * through {@code uffff}, then it is - * represented by three bytes, to be written - * in the order shown:

{@code
-	 * (byte)(0xe0 | (0x0f & (c >> 12)))
-	 * (byte)(0x80 | (0x3f & (c >>  6)))
-	 * (byte)(0x80 | (0x3f & c))
-	 * }

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.

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); -} diff --git a/src/main/java/org/warp/commonutils/stream/SafeDataOutputStream.java b/src/main/java/org/warp/commonutils/stream/SafeDataOutputStream.java deleted file mode 100644 index 32cc8d5..0000000 --- a/src/main/java/org/warp/commonutils/stream/SafeDataOutputStream.java +++ /dev/null @@ -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}. - *

- * 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. - *

- * 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 - * modified UTF-8 - * encoding in a machine-independent manner. - *

- * 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 - * modified UTF-8 - * encoding in a machine-independent manner. - *

- * 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); - } -} diff --git a/src/main/java/org/warp/commonutils/stream/SafeFilterInputStream.java b/src/main/java/org/warp/commonutils/stream/SafeFilterInputStream.java deleted file mode 100644 index 28be7e9..0000000 --- a/src/main/java/org/warp/commonutils/stream/SafeFilterInputStream.java +++ /dev/null @@ -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. - *

- * 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. - *

- * This method simply performs the call - * {@code read(b, 0, b.length)} and returns - * the result. It is important that it does - * not 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. - *

- * 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. - *

- * 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. - *

- * 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. - *

- * The {@code readlimit} argument tells this input stream to - * allow that many bytes to be read before the mark position gets - * invalidated. - *

- * 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. - *

- * This method - * simply performs {@code in.reset()}. - *

- * 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(); - } -} diff --git a/src/main/java/org/warp/commonutils/stream/SafeFilterOutputStream.java b/src/main/java/org/warp/commonutils/stream/SafeFilterOutputStream.java deleted file mode 100644 index f4fd0e5..0000000 --- a/src/main/java/org/warp/commonutils/stream/SafeFilterOutputStream.java +++ /dev/null @@ -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 underlying output stream) which it uses as its - * basic sink of data, but possibly transforming the data along the - * way or providing additional functionality. - *

- * 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. - *

- * 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)}. - *

- * 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. - *

- * 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}. - *

- * 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. - *

- * The {@code write} method of {@code FilterOutputStream} - * calls the {@code write} method of one argument on each - * {@code byte} to output. - *

- * 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. - *

- * 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. - *

- * 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; - } - } - } - } -} diff --git a/src/main/java/org/warp/commonutils/stream/SafeInputStream.java b/src/main/java/org/warp/commonutils/stream/SafeInputStream.java deleted file mode 100644 index db60727..0000000 --- a/src/main/java/org/warp/commonutils/stream/SafeInputStream.java +++ /dev/null @@ -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 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; - } -} diff --git a/src/main/java/org/warp/commonutils/stream/SafeMeasurableInputStream.java b/src/main/java/org/warp/commonutils/stream/SafeMeasurableInputStream.java deleted file mode 100644 index 547f847..0000000 --- a/src/main/java/org/warp/commonutils/stream/SafeMeasurableInputStream.java +++ /dev/null @@ -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 { -} diff --git a/src/main/java/org/warp/commonutils/stream/SafeMeasurableOutputStream.java b/src/main/java/org/warp/commonutils/stream/SafeMeasurableOutputStream.java deleted file mode 100644 index fb67530..0000000 --- a/src/main/java/org/warp/commonutils/stream/SafeMeasurableOutputStream.java +++ /dev/null @@ -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 { -} diff --git a/src/main/java/org/warp/commonutils/stream/SafeMeasurableStream.java b/src/main/java/org/warp/commonutils/stream/SafeMeasurableStream.java deleted file mode 100644 index 3e8ecc5..0000000 --- a/src/main/java/org/warp/commonutils/stream/SafeMeasurableStream.java +++ /dev/null @@ -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). - * - *

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). - * - *

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(); -} diff --git a/src/main/java/org/warp/commonutils/stream/SafeOutputStream.java b/src/main/java/org/warp/commonutils/stream/SafeOutputStream.java deleted file mode 100644 index 0fa9867..0000000 --- a/src/main/java/org/warp/commonutils/stream/SafeOutputStream.java +++ /dev/null @@ -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. - *

- * 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. - * - *

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}. - * - *

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. - *

- * 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. - *

- * 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. - *

- * 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. - * - * @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. - *

- * 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. - *

- * 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. - *

- * The {@code close} method of {@code OutputStream} does nothing. - * - */ - public void close() { - } -} diff --git a/src/main/java/org/warp/commonutils/stream/SafePushbackInputStream.java b/src/main/java/org/warp/commonutils/stream/SafePushbackInputStream.java deleted file mode 100644 index 04420d9..0000000 --- a/src/main/java/org/warp/commonutils/stream/SafePushbackInputStream.java +++ /dev/null @@ -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. - * - *

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. - * - *

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. - * - *

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. - * - *

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. - * - *

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; - } -} diff --git a/src/main/java/org/warp/commonutils/stream/SafeRepositionableStream.java b/src/main/java/org/warp/commonutils/stream/SafeRepositionableStream.java deleted file mode 100644 index e79f2df..0000000 --- a/src/main/java/org/warp/commonutils/stream/SafeRepositionableStream.java +++ /dev/null @@ -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(); - -} diff --git a/src/main/java/org/warp/commonutils/type/AddStrategy.java b/src/main/java/org/warp/commonutils/type/AddStrategy.java deleted file mode 100644 index 4506a53..0000000 --- a/src/main/java/org/warp/commonutils/type/AddStrategy.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.warp.commonutils.type; - -public enum AddStrategy { - OVERWRITE_POSITION, - KEEP_POSITION; - - public static AddStrategy getDefault() { - return KEEP_POSITION; - } -} diff --git a/src/main/java/org/warp/commonutils/type/ArrayStack.java b/src/main/java/org/warp/commonutils/type/ArrayStack.java deleted file mode 100644 index 86cfe37..0000000 --- a/src/main/java/org/warp/commonutils/type/ArrayStack.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.warp.commonutils.type; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import java.util.Collection; - -public class ArrayStack extends FastUtilStackWrapper { - - public ArrayStack() { - super(new ObjectArrayList<>()); - } - - public ArrayStack(Collection stack) { - super(new ObjectArrayList<>(stack)); - } -} diff --git a/src/main/java/org/warp/commonutils/type/Bytes.java b/src/main/java/org/warp/commonutils/type/Bytes.java deleted file mode 100644 index 65cf933..0000000 --- a/src/main/java/org/warp/commonutils/type/Bytes.java +++ /dev/null @@ -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 ofMap(Map oldMap) { - var newMap = new HashMap(oldMap.size()); - oldMap.forEach((key, value) -> newMap.put(new Bytes(key), new Bytes(value))); - return newMap; - } - - public static List ofList(List oldList) { - var newList = new ArrayList(oldList.size()); - oldList.forEach((item) -> newList.add(new Bytes(item))); - return newList; - } - - public static Set ofSet(Set oldSet) { - var newSet = new ObjectOpenHashSet(oldSet.size()); - oldSet.forEach((item) -> newSet.add(new Bytes(item))); - return newSet; - } - - public static byte[][] toByteArray(Collection 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); - } -} diff --git a/src/main/java/org/warp/commonutils/type/EqualsWrapper.java b/src/main/java/org/warp/commonutils/type/EqualsWrapper.java deleted file mode 100644 index d74b12f..0000000 --- a/src/main/java/org/warp/commonutils/type/EqualsWrapper.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.warp.commonutils.type; - -import java.util.Objects; - -public class EqualsWrapper { - - 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); - } -} diff --git a/src/main/java/org/warp/commonutils/type/FastUtilStackWrapper.java b/src/main/java/org/warp/commonutils/type/FastUtilStackWrapper.java deleted file mode 100644 index e08e4e4..0000000 --- a/src/main/java/org/warp/commonutils/type/FastUtilStackWrapper.java +++ /dev/null @@ -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 implements Stack, Collection { - - private final it.unimi.dsi.fastutil.Stack stack; - private final Collection collection; - - public & Collection> 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 iterator() { - return collection.iterator(); - } - - @NotNull - @Override - public Object @NotNull [] toArray() { - return collection.toArray(); - } - - @NotNull - @Override - public 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 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(); - } -} diff --git a/src/main/java/org/warp/commonutils/type/ImmutableLinkedSet.java b/src/main/java/org/warp/commonutils/type/ImmutableLinkedSet.java deleted file mode 100644 index 1501c00..0000000 --- a/src/main/java/org/warp/commonutils/type/ImmutableLinkedSet.java +++ /dev/null @@ -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 implements Set { - - private final LinkedHashSet set; - - public ImmutableLinkedSet(LinkedHashSet 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 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 action) { - set.forEach(action); - } - - @NotNull - @Override - public Object @NotNull [] toArray() { - return set.toArray(); - } - - @NotNull - @Override - public T @NotNull [] toArray(@NotNull T @NotNull [] a) { - //noinspection SuspiciousToArrayCall - return set.toArray(a); - } - - @Override - public T[] toArray(IntFunction 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 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 filter) { - throw new UnsupportedOperationException("Read only"); - } - - @Override - public void clear() { - throw new UnsupportedOperationException("Read only"); - } - - @Override - public Spliterator spliterator() { - var spl = set.spliterator(); - return new Spliterator<>() { - @Override - public boolean tryAdvance(Consumer action) { - return spl.tryAdvance(action); - } - - @Override - public Spliterator trySplit() { - return spl.trySplit(); - } - - @Override - public long estimateSize() { - return spl.estimateSize(); - } - - @Override - public int characteristics() { - return spl.characteristics(); - } - }; - } - - @Override - public Stream stream() { - return set.stream(); - } - - @Override - public Stream parallelStream() { - return set.parallelStream(); - } - - public LinkedHashSet copyMutable() { - return new LinkedHashSet<>(set); - } -} diff --git a/src/main/java/org/warp/commonutils/type/MultiAssociation.java b/src/main/java/org/warp/commonutils/type/MultiAssociation.java deleted file mode 100644 index d529795..0000000 --- a/src/main/java/org/warp/commonutils/type/MultiAssociation.java +++ /dev/null @@ -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 Source type - * @param Destination type - */ -public interface MultiAssociation { - - /** - * 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 unlink(T src); - - /** - * Unlink - * @param dest Destination - * @return previous linked source - */ - Set 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 getLinks(T src); - - /** - * Get a link source - * @param dest Source - * @return Existing linked sources - */ - Set 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 getSources(); - - /** - * Get all the destinations - * @return Set of destinations - */ - ObjectSet getDestinations(); - -} diff --git a/src/main/java/org/warp/commonutils/type/ShortNamedThreadFactory.java b/src/main/java/org/warp/commonutils/type/ShortNamedThreadFactory.java deleted file mode 100644 index 0bb4eee..0000000 --- a/src/main/java/org/warp/commonutils/type/ShortNamedThreadFactory.java +++ /dev/null @@ -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; - } - -} diff --git a/src/main/java/org/warp/commonutils/type/Stack.java b/src/main/java/org/warp/commonutils/type/Stack.java deleted file mode 100644 index 9dc3dac..0000000 --- a/src/main/java/org/warp/commonutils/type/Stack.java +++ /dev/null @@ -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 - * - *

A stack must provide the classical {@link #push(Object)} and - * {@link #pop()} operations, but may be also peekable 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 extends it.unimi.dsi.fastutil.Stack { - - /** - * Pop multiple times - * @param count the number of times to pop - * @return list of popped elements - */ - default List pop(int count) { - if (count < 0) { - throw new IndexOutOfBoundsException(count); - } - var items = new ArrayList(count); - for (int i = 0; i < count; i++) { - items.add(this.pop()); - } - return items; - } - - static Stack create() { - return new ArrayStack<>(); - } - - static & Collection> Stack wrap(U stack) { - return new FastUtilStackWrapper<>(stack); - } - -} diff --git a/src/main/java/org/warp/commonutils/type/VariableWrapper.java b/src/main/java/org/warp/commonutils/type/VariableWrapper.java deleted file mode 100644 index b0b5857..0000000 --- a/src/main/java/org/warp/commonutils/type/VariableWrapper.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.warp.commonutils.type; - -public class VariableWrapper { - - public volatile T var; - - public VariableWrapper(T value) { - this.var = value; - } -}