All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.tommyettinger.random.ReverseWrapper Maven / Gradle / Ivy

There is a newer version: 0.6.1
Show newest version
package com.github.tommyettinger.random;

import com.github.tommyettinger.digital.Base;

import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.List;
import java.util.Random;

/**
 * A wrapper around a different {@link EnhancedRandom} object that runs it in reverse, calling
 * {@link EnhancedRandom#previousLong()} instead anywhere {@link #nextLong()} would be called.
 * This can be useful to reverse a sequence of calls made to the wrapped generator earlier; the reversed
 * calls have to happen in reverse order to undo an operation such as a shuffle, typically.
 * Calling previousLong() is typically not as fast as nextLong(), but usually not by any large degree.
 */
public class ReverseWrapper extends EnhancedRandom {
    public EnhancedRandom wrapped;

    /**
     * Creates a ReverseWrapper that wraps a DistinctRandom with a random seed.
     */
    public ReverseWrapper() {
        super();
        wrapped = new DistinctRandom();
    }

    /**
     * Creates a ReverseWrapper that wraps a DistinctRandom created with {@link DistinctRandom#DistinctRandom(long)}.
     * @param seed the seed that will be used for the wrapped DistinctRandom
     */
    public ReverseWrapper(long seed) {
        super(seed);
        wrapped = new DistinctRandom(seed);
    }

    /**
     * This does not copy {@code toWrap}, and uses a reference as-is, so this can be useful to reverse
     * some series of calls made earlier to toWrap in a forward direction.
     * @param toWrap a non-null EnhancedRandom, preferably not also a wrapper
     */
    public ReverseWrapper(EnhancedRandom toWrap) {
        super(toWrap.getSelectedState(0));
        wrapped = toWrap;
    }

    /**
     * The copy constructor.
     * @param other a non-null ReverseWrapper; its {@link #getWrapped() wrapped EnhancedRandom} must also be non-null.
     */
    public ReverseWrapper(ReverseWrapper other) {
        super(other.wrapped.getSelectedState(0));
        wrapped = other.wrapped;
    }

    public EnhancedRandom getWrapped() {
        return wrapped;
    }

    public void setWrapped(EnhancedRandom wrapped) {
        this.wrapped = wrapped;
    }

    /**
     * Gets the number of possible state variables that can be selected with
     * {@link #getSelectedState(int)} or {@link #setSelectedState(int, long)}.
     * This defaults to returning 0, making no state variable available for
     * reading or writing. An implementation that has only one {@code long}
     * state, like {@link DistinctRandom} generator, should return {@code 1}. A
     * generator that permits setting two different {@code long} values, like
     * {@link LaserRandom}, should return {@code 2}. Much larger values are
     * possible for types like the Mersenne Twister or some CMWC generators.
     *
     * @return the non-negative number of selections possible for state variables
     */
    @Override
    public int getStateCount() {
        return wrapped.getStateCount();
    }

    /**
     * Gets the tag used to identify this type of EnhancedRandom, as a String. This tag should be unique,
     * and for uniformity purposes, all tags used in this library are 4 characters long. User-defined tags
     * should have a different length.
     *
     * @return a unique String identifier for this type of EnhancedRandom; usually 4 chars long.
     */
    @Override
    public String getTag() {
        return "RevW";
    }

    /**
     * Sets the seed of this random number generator using a single
     * {@code long} seed. This should behave exactly the same as if a new
     * object of this type was created with the constructor that takes a single
     * {@code long} value. This does not necessarily assign the state
     * variable(s) of the implementation with the exact contents of seed, so
     * {@link #getSelectedState(int)} should not be expected to return
     * {@code seed} after this, though it may. If this implementation has more
     * than one {@code long} of state, then the expectation is that none of
     * those state variables will be exactly equal to {@code seed} (almost all
     * the time).
     *
     * @param seed the initial seed
     */
    @Override
    public void setSeed(long seed) {
        if(wrapped != null)
            wrapped.setSeed(seed);
    }

    /**
     * Gets a selected state value from this EnhancedRandom. The number of possible selections
     * is up to the implementing class, and is accessible via {@link #getStateCount()}, but
     * negative values for {@code selection} are typically not tolerated. This should return
     * the exact value of the selected state, assuming it is implemented. The default
     * implementation throws an UnsupportedOperationException, and implementors only have to
     * allow reading the state if they choose to implement this differently. If this method
     * is intended to be used, {@link #getStateCount()} must also be implemented.
     *
     * @param selection used to select which state variable to get; generally non-negative
     * @return the exact value of the selected state
     */
    @Override
    public long getSelectedState(int selection) {
        return wrapped.getSelectedState(selection);
    }

    /**
     * Sets a selected state value to the given long {@code value}. The number of possible
     * selections is up to the implementing class, but negative values for {@code selection}
     * are typically not tolerated. Implementors are permitted to change {@code value} if it
     * is not valid, but they should not alter it if it is valid. The public implementation
     * calls {@link #setSeed(long)} with {@code value}, which doesn't need changing if the
     * generator has one state that is set verbatim by setSeed(). Otherwise, this method
     * should be implemented when {@link #getSelectedState(int)} is and the state is allowed
     * to be set by users. Having accurate ways to get and set the full state of a random
     * number generator makes it much easier to serialize and deserialize that class.
     *
     * @param selection used to select which state variable to set; generally non-negative
     * @param value     the exact value to use for the selected state, if valid
     */
    @Override
    public void setSelectedState(int selection, long value) {
        wrapped.setSelectedState(selection, value);
    }

    /**
     * Sets each state variable to the given {@code state}. If {@link #getStateCount()} is
     * 1, then this should set the whole state to the given value using
     * {@link #setSelectedState(int, long)}. If getStateCount() is more than 1, then all
     * states will be set in the same way (using setSelectedState(), all to {@code state}).
     *
     * @param state the long value to use for each state variable
     */
    @Override
    public void setState(long state) {
        wrapped.setState(state);
    }

    /**
     * Sets each state variable to either {@code stateA} or {@code stateB}, alternating.
     * This uses {@link #setSelectedState(int, long)} to set the values. If there is one
     * state variable ({@link #getStateCount()} is 1), then this only sets that state
     * variable to stateA. If there are two state variables, the first is set to stateA,
     * and the second to stateB. If there are more, it reuses stateA, then stateB, then
     * stateA, and so on until all variables are set.
     *
     * @param stateA the long value to use for states at index 0, 2, 4, 6...
     * @param stateB the long value to use for states at index 1, 3, 5, 7...
     */
    @Override
    public void setState(long stateA, long stateB) {
        wrapped.setState(stateA, stateB);
    }

    /**
     * Sets each state variable to {@code stateA}, {@code stateB}, or {@code stateC},
     * alternating. This uses {@link #setSelectedState(int, long)} to set the values.
     * If there is one state variable ({@link #getStateCount()} is 1), then this only
     * sets that state variable to stateA. If there are two state variables, the first
     * is set to stateA, and the second to stateB. With three state variables, the
     * first is set to stateA, the second to stateB, and the third to stateC. If there
     * are more, it reuses stateA, then stateB, then stateC, then stateA, and so on
     * until all variables are set.
     *
     * @param stateA the long value to use for states at index 0, 3, 6, 9...
     * @param stateB the long value to use for states at index 1, 4, 7, 10...
     * @param stateC the long value to use for states at index 2, 5, 8, 11...
     */
    @Override
    public void setState(long stateA, long stateB, long stateC) {
        wrapped.setState(stateA, stateB, stateC);
    }

    /**
     * Sets each state variable to {@code stateA}, {@code stateB}, {@code stateC}, or
     * {@code stateD}, alternating. This uses {@link #setSelectedState(int, long)} to
     * set the values. If there is one state variable ({@link #getStateCount()} is 1),
     * then this only sets that state variable to stateA. If there are two state
     * variables, the first is set to stateA, and the second to stateB. With three
     * state variables, the first is set to stateA, the second to stateB, and the third
     * to stateC. With four state variables, the first is set to stateA, the second to
     * stateB, the third to stateC, and the fourth to stateD. If there are more, it
     * reuses stateA, then stateB, then stateC, then stateD, then stateA, and so on
     * until all variables are set.
     *
     * @param stateA the long value to use for states at index 0, 4, 8, 12...
     * @param stateB the long value to use for states at index 1, 5, 9, 13...
     * @param stateC the long value to use for states at index 2, 6, 10, 14...
     * @param stateD the long value to use for states at index 3, 7, 11, 15...
     */
    @Override
    public void setState(long stateA, long stateB, long stateC, long stateD) {
        wrapped.setState(stateA, stateB, stateC, stateD);
    }

    /**
     * Sets each state variable to {@code stateA}, {@code stateB}, {@code stateC}, or
     * {@code stateD}, alternating. This uses {@link #setSelectedState(int, long)} to
     * set the values. If there is one state variable ({@link #getStateCount()} is 1),
     * then this only sets that state variable to stateA. If there are two state
     * variables, the first is set to stateA, and the second to stateB. With three
     * state variables, the first is set to stateA, the second to stateB, and the third
     * to stateC. With four state variables, the first is set to stateA, the second to
     * stateB, the third to stateC, and the fourth to stateD. If there are more, it
     * reuses stateA, then stateB, then stateC, then stateD, then stateA, and so on
     * until all variables are set.
     *
     * @param stateA the long value to use for states at index 0, 5, 10, 15...
     * @param stateB the long value to use for states at index 1, 6, 11, 16...
     * @param stateC the long value to use for states at index 2, 7, 12, 17...
     * @param stateD the long value to use for states at index 3, 8, 13, 18...
     * @param stateE the long value to use for states at index 4, 9, 14, 19...
     */
    @Override
    public void setState(long stateA, long stateB, long stateC, long stateD, long stateE) {
        wrapped.setState(stateA, stateB, stateC, stateD, stateE);
    }

    /**
     * Sets all state variables to alternating values chosen from {@code states}. If states is empty,
     * then this does nothing, and leaves the current generator unchanged. This works for
     * generators with any {@link #getStateCount()}, but may allocate an array if states is
     * used as a varargs (you can pass an existing array without needing to allocate). This
     * uses {@link #setSelectedState(int, long)} to change the states.
     *
     * @param states an array or varargs of long values to use as states
     */
    @Override
    public void setState(long... states) {
        wrapped.setState(states);
    }

    /**
     * Returns the previous pseudorandom, uniformly distributed {@code long}
     * value from the wrapped random number generator's sequence. The general
     * contract of {@code nextLong} is that one {@code long} value is
     * pseudorandomly generated and returned.
     *
     * @return the previous pseudorandom, uniformly distributed {@code long}
     * value from the wrapped random number generator's sequence
     */
    @Override
    public long nextLong() {
        return wrapped.previousLong();
    }

    /**
     * Returns the previous pseudorandom, uniformly distributed {@code int}
     * value from the wrapped random number generator's sequence. The general
     * contract of {@code nextInt} is that one {@code int} value is
     * pseudorandomly generated and returned. All 232 possible
     * {@code int} values are produced with (approximately) equal probability.
     *
     * @return the previous pseudorandom, uniformly distributed {@code int}
     * value from the wrapped random number generator's sequence
     */
    @Override
    public int nextInt() {
        return wrapped.previousInt();
    }

    /**
     * Delegates to the {@link EnhancedRandom#nextLong()} method of the wrapped generator; this is the
     * counterpart to how {@link #nextLong()} here delegates to the {@link EnhancedRandom#previousLong()}
     * method of the wrapped generator.
     *
     * @return the number that {@code wrapped.nextLong()} would produce
     */
    @Override
    public long previousLong() {
        return wrapped.nextLong();
    }

    /**
     * Delegates to the {@link EnhancedRandom#nextInt()} method of the wrapped generator; this is the
     * counterpart to how {@link #nextInt()} here delegates to the {@link EnhancedRandom#previousInt()} ()}
     * method of the wrapped generator.
     *
     * @return the number that {@code wrapped.nextLong()} would produce
     */
    @Override
    public int previousInt() {
        return wrapped.nextInt();
    }

    /**
     * Delegates to the {@link EnhancedRandom#skip(long)} method if the wrapped generator, but passes it
     * {@code -advance} instead of advance without changes. This makes it skip in the reverse direction.
     *
     * @param advance Number of future generations to skip over; can be negative to backtrack, 0 gets the most-recently-generated number
     * @return the random long generated after skipping forward or backwards by {@code advance} numbers
     */
    @Override
    public long skip(long advance) {
        return wrapped.skip(-advance);
    }

    /**
     * Shuffles a section of the given array in-place pseudo-randomly, using this to determine how to shuffle.
     * Similarly to how {@link #nextLong()} uses the wrapped generator's {@link EnhancedRandom#previousLong()},
     * this shuffles in reverse order. This allows you to shuffle an array using one of the wrapped generator's
     * shuffle() methods, then later undo that shuffle by using a ReverseWrapper's shuffle method.
     *
     * @param items  an array of some reference type; must be non-null but may contain null items
     * @param offset the index of the first element of the array that can be shuffled
     * @param length the length of the section to shuffle
     */
    public void shuffle (long[] items, int offset, int length) {
        offset = Math.min(Math.max(0, offset), items.length);
        length = Math.min(items.length - offset, Math.max(0, length));
        for (int i = offset + 1, n = offset + length; i < n; i++) {
            int ii = nextInt(offset, i + 1);
            long temp = items[i];
            items[i] = items[ii];
            items[ii] = temp;
        }
    }

    /**
     * Shuffles a section of the given array in-place pseudo-randomly, using this to determine how to shuffle.
     * Similarly to how {@link #nextLong()} uses the wrapped generator's {@link EnhancedRandom#previousLong()},
     * this shuffles in reverse order. This allows you to shuffle an array using one of the wrapped generator's
     * shuffle() methods, then later undo that shuffle by using a ReverseWrapper's shuffle method.
     *
     * @param items  an array of some reference type; must be non-null but may contain null items
     * @param offset the index of the first element of the array that can be shuffled
     * @param length the length of the section to shuffle
     */
    public void shuffle (byte[] items, int offset, int length) {
        offset = Math.min(Math.max(0, offset), items.length);
        length = Math.min(items.length - offset, Math.max(0, length));
        for (int i = offset + 1, n = offset + length; i < n; i++) {
            int ii = nextInt(offset, i + 1);
            byte temp = items[i];
            items[i] = items[ii];
            items[ii] = temp;
        }
    }

    /**
     * Shuffles a section of the given array in-place pseudo-randomly, using this to determine how to shuffle.
     * Similarly to how {@link #nextLong()} uses the wrapped generator's {@link EnhancedRandom#previousLong()},
     * this shuffles in reverse order. This allows you to shuffle an array using one of the wrapped generator's
     * shuffle() methods, then later undo that shuffle by using a ReverseWrapper's shuffle method.
     *
     * @param items  an array of some reference type; must be non-null but may contain null items
     * @param offset the index of the first element of the array that can be shuffled
     * @param length the length of the section to shuffle
     */
    public void shuffle (int[] items, int offset, int length) {
        offset = Math.min(Math.max(0, offset), items.length);
        length = Math.min(items.length - offset, Math.max(0, length));
        for (int i = offset + 1, n = offset + length; i < n; i++) {
            int ii = nextInt(offset, i + 1);
            int temp = items[i];
            items[i] = items[ii];
            items[ii] = temp;
        }
    }

    /**
     * Shuffles a section of the given array in-place pseudo-randomly, using this to determine how to shuffle.
     * Similarly to how {@link #nextLong()} uses the wrapped generator's {@link EnhancedRandom#previousLong()},
     * this shuffles in reverse order. This allows you to shuffle an array using one of the wrapped generator's
     * shuffle() methods, then later undo that shuffle by using a ReverseWrapper's shuffle method.
     *
     * @param items  an array of some reference type; must be non-null but may contain null items
     * @param offset the index of the first element of the array that can be shuffled
     * @param length the length of the section to shuffle
     */
    public void shuffle (short[] items, int offset, int length) {
        offset = Math.min(Math.max(0, offset), items.length);
        length = Math.min(items.length - offset, Math.max(0, length));
        for (int i = offset + 1, n = offset + length; i < n; i++) {
            int ii = nextInt(offset, i + 1);
            short temp = items[i];
            items[i] = items[ii];
            items[ii] = temp;
        }
    }

    /**
     * Shuffles a section of the given array in-place pseudo-randomly, using this to determine how to shuffle.
     * Similarly to how {@link #nextLong()} uses the wrapped generator's {@link EnhancedRandom#previousLong()},
     * this shuffles in reverse order. This allows you to shuffle an array using one of the wrapped generator's
     * shuffle() methods, then later undo that shuffle by using a ReverseWrapper's shuffle method.
     *
     * @param items  an array of some reference type; must be non-null but may contain null items
     * @param offset the index of the first element of the array that can be shuffled
     * @param length the length of the section to shuffle
     */
    public void shuffle (float[] items, int offset, int length) {
        offset = Math.min(Math.max(0, offset), items.length);
        length = Math.min(items.length - offset, Math.max(0, length));
        for (int i = offset + 1, n = offset + length; i < n; i++) {
            int ii = nextInt(offset, i + 1);
            float temp = items[i];
            items[i] = items[ii];
            items[ii] = temp;
        }
    }

    /**
     * Shuffles a section of the given array in-place pseudo-randomly, using this to determine how to shuffle.
     * Similarly to how {@link #nextLong()} uses the wrapped generator's {@link EnhancedRandom#previousLong()},
     * this shuffles in reverse order. This allows you to shuffle an array using one of the wrapped generator's
     * shuffle() methods, then later undo that shuffle by using a ReverseWrapper's shuffle method.
     *
     * @param items  an array of some reference type; must be non-null but may contain null items
     * @param offset the index of the first element of the array that can be shuffled
     * @param length the length of the section to shuffle
     */
    public void shuffle (double[] items, int offset, int length) {
        offset = Math.min(Math.max(0, offset), items.length);
        length = Math.min(items.length - offset, Math.max(0, length));
        for (int i = offset + 1, n = offset + length; i < n; i++) {
            int ii = nextInt(offset, i + 1);
            double temp = items[i];
            items[i] = items[ii];
            items[ii] = temp;
        }
    }

    /**
     * Shuffles a section of the given array in-place pseudo-randomly, using this to determine how to shuffle.
     * Similarly to how {@link #nextLong()} uses the wrapped generator's {@link EnhancedRandom#previousLong()},
     * this shuffles in reverse order. This allows you to shuffle an array using one of the wrapped generator's
     * shuffle() methods, then later undo that shuffle by using a ReverseWrapper's shuffle method.
     *
     * @param items  an array of some reference type; must be non-null but may contain null items
     * @param offset the index of the first element of the array that can be shuffled
     * @param length the length of the section to shuffle
     */
    public void shuffle (boolean[] items, int offset, int length) {
        offset = Math.min(Math.max(0, offset), items.length);
        length = Math.min(items.length - offset, Math.max(0, length));
        for (int i = offset + 1, n = offset + length; i < n; i++) {
            int ii = nextInt(offset, i + 1);
            boolean temp = items[i];
            items[i] = items[ii];
            items[ii] = temp;
        }
    }

    /**
     * Shuffles a section of the given array in-place pseudo-randomly, using this to determine how to shuffle.
     * Similarly to how {@link #nextLong()} uses the wrapped generator's {@link EnhancedRandom#previousLong()},
     * this shuffles in reverse order. This allows you to shuffle an array using one of the wrapped generator's
     * shuffle() methods, then later undo that shuffle by using a ReverseWrapper's shuffle method.
     *
     * @param items  an array of some reference type; must be non-null but may contain null items
     * @param offset the index of the first element of the array that can be shuffled
     * @param length the length of the section to shuffle
     */
    public void shuffle (char[] items, int offset, int length) {
        offset = Math.min(Math.max(0, offset), items.length);
        length = Math.min(items.length - offset, Math.max(0, length));
        for (int i = offset + 1, n = offset + length; i < n; i++) {
            int ii = nextInt(offset, i + 1);
            char temp = items[i];
            items[i] = items[ii];
            items[ii] = temp;
        }
    }

    /**
     * Shuffles a section of the given array in-place pseudo-randomly, using this to determine how to shuffle.
     * Similarly to how {@link #nextLong()} uses the wrapped generator's {@link EnhancedRandom#previousLong()},
     * this shuffles in reverse order. This allows you to shuffle an array using one of the wrapped generator's
     * shuffle() methods, then later undo that shuffle by using a ReverseWrapper's shuffle method.
     *
     * @param items  an array of some reference type; must be non-null but may contain null items
     * @param offset the index of the first element of the array that can be shuffled
     * @param length the length of the section to shuffle
     */
    public  void shuffle (T[] items, int offset, int length) {
        offset = Math.min(Math.max(0, offset), items.length);
        length = Math.min(items.length - offset, Math.max(0, length));
        for (int i = offset + 1, n = offset + length; i < n; i++) {
            int ii = nextInt(offset, i + 1);
            T temp = items[i];
            items[i] = items[ii];
            items[ii] = temp;
        }
    }

    /**
     * Shuffles the given array in-place pseudo-randomly, using this to determine how to shuffle.
     *
     * @param items an int array; must be non-null
     */
    @Override
    public void shuffle(int[] items) {
        shuffle(items, 0, items.length);
    }

    /**
     * Shuffles the given array in-place pseudo-randomly, using this to determine how to shuffle.
     *
     * @param items a long array; must be non-null
     */
    @Override
    public void shuffle(long[] items) {
        shuffle(items, 0, items.length);
    }

    /**
     * Shuffles the given array in-place pseudo-randomly, using this to determine how to shuffle.
     *
     * @param items a float array; must be non-null
     */
    @Override
    public void shuffle(float[] items) {
        shuffle(items, 0, items.length);
    }

    /**
     * Shuffles the given array in-place pseudo-randomly, using this to determine how to shuffle.
     *
     * @param items a char array; must be non-null
     */
    @Override
    public void shuffle(char[] items) {
        shuffle(items, 0, items.length);
    }

    /**
     * Shuffles the given array in-place pseudo-randomly, using this to determine how to shuffle.
     *
     * @param items a byte array; must be non-null
     */
    @Override
    public void shuffle(byte[] items) {
        shuffle(items, 0, items.length);
    }

    /**
     * Shuffles the given array in-place pseudo-randomly, using this to determine how to shuffle.
     *
     * @param items a double array; must be non-null
     */
    @Override
    public void shuffle(double[] items) {
        shuffle(items, 0, items.length);
    }

    /**
     * Shuffles the given array in-place pseudo-randomly, using this to determine how to shuffle.
     *
     * @param items a short array; must be non-null
     */
    @Override
    public void shuffle(short[] items) {
        shuffle(items, 0, items.length);
    }

    /**
     * Shuffles the given array in-place pseudo-randomly, using this to determine how to shuffle.
     *
     * @param items a boolean array; must be non-null
     */
    @Override
    public void shuffle(boolean[] items) {
        shuffle(items, 0, items.length);
    }

    /**
     * Shuffles the given array in-place pseudo-randomly, using this to determine how to shuffle.
     *
     * @param items an array of some reference type; must be non-null but may contain null items
     */
    @Override
    public  void shuffle(T[] items) {
        shuffle(items, 0, items.length);
    }

    /**
     * Shuffles the given List in-place pseudo-randomly, using this to determine how to shuffle.
     *
     * @param items a List of some type {@code T}; must be non-null but may contain null items
     */
    @Override
    public  void shuffle(List items) {
        shuffle(items, 0, items.size());
    }

    /**
     * Shuffles a section of the given List in-place pseudo-randomly, using this to determine how to shuffle.
     *
     * @param items  a List of some type {@code T}; must be non-null but may contain null items
     * @param offset the index of the first element of the array that can be shuffled
     * @param length the length of the section to shuffle
     */
    @Override
    public  void shuffle(List items, int offset, int length) {
        offset = Math.min(Math.max(0, offset), items.size());
        length = Math.min(items.size() - offset, Math.max(0, length));
        for (int i = offset + 1, n = offset + length; i < n; i++) {
            int ii = offset + nextInt(i + 1 - offset);
            T temp = items.get(i);
            items.set(i, items.get(ii));
            items.set(ii, temp);
        }
    }

    /**
     * Creates a new EnhancedRandom with identical states to this one, so if the same EnhancedRandom methods are
     * called on this object and its copy (in the same order), the same outputs will be produced. This is not
     * guaranteed to copy the inherited state of any parent class, so if you call methods that are
     * only implemented by a superclass (like {@link Random}) and not this one, the results may differ.
     *
     * @return a deep copy of this EnhancedRandom.
     */
    @Override
    public ReverseWrapper copy() {
        return new ReverseWrapper(wrapped.copy());
    }

    /**
     * Serializes the current state of this EnhancedRandom to a String that can be used by
     * {@link #stringDeserialize(String)} to load this state at another time.
     *
     * @param base which Base to use, from the "digital" library, such as {@link Base#BASE10}
     * @return a String storing all data from the EnhancedRandom part of this generator
     */
    @Override
    public String stringSerialize(Base base) {
        return getTag() + "`" + wrapped.stringSerialize(base) + "`";
    }

    /**
     * Given a String in the format produced by {@link #stringSerialize(Base)}, and the same {@link Base} used by
     * the serialization, this will attempt to set this EnhancedRandom object to match the state in the serialized
     * data. This only works if this EnhancedRandom is the same implementation that was serialized, and also needs
     * the Bases to be identical. Returns this EnhancedRandom, after possibly changing its state.
     *
     * @param data a String probably produced by {@link #stringSerialize(Base)}
     * @param base which Base to use, from the "digital" library, such as {@link Base#BASE10}
     * @return this, after setting its state
     */
    @Override
    public ReverseWrapper stringDeserialize(String data, Base base) {
        setWrapped(Deserializer.deserialize(data.substring(data.indexOf('`')+1), base));
        return this;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        ReverseWrapper that = (ReverseWrapper) o;

        return wrapped.equals(that.wrapped);
    }

    @Override
    public int hashCode() {
        return wrapped.hashCode();
    }

    @Override
    public String toString() {
        return "ReverseWrapper{" +
                "wrapped=" + wrapped +
                '}';
    }

    /**
     * The object implements the readExternal method to restore its
     * contents by calling the methods of DataInput for primitive
     * types and readObject for objects, strings and arrays.  The
     * readExternal method must read the values in the same sequence
     * and with the same types as were written by writeExternal.
     *
     * @param in the stream to read data from in order to restore the object
     * @throws IOException if I/O errors occur
     */
    @GwtIncompatible
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        wrapped = (EnhancedRandom) in.readObject();
    }

    /**
     * Needs the type of {@link #wrapped} registered.
     *
     * @param out the stream to write the object to
     * @throws IOException Includes any I/O exceptions that may occur
     * @serialData 
    *
  • int stateCount; the number of states this EnhancedRandom has
  • *
  • Repeat {@code stateCount} times: *
      *
    • long state_n; the nth state used here.
    • *
    *
  • *
*/ @GwtIncompatible public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(wrapped); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy