com.replaymod.replaystudio.collection.PacketList.java Source code

Java tutorial

Introduction

Here is the source code for com.replaymod.replaystudio.collection.PacketList.java

Source

/*
 * This file is part of ReplayStudio, licensed under the MIT License (MIT).
 *
 * Copyright (c) 2016 johni0702 <https://github.com/johni0702>
 * Copyright (c) contributors
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.replaymod.replaystudio.collection;

import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.replaymod.replaystudio.PacketData;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Array;
import java.util.*;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * A list for PacketData allowing efficient modification.
 * The difference to LinkedList is that it always ensures correct packet ordering unless specified otherwise.
 * This list is not thread-safe.
 */
public class PacketList implements List<PacketData> {

    /**
     * Number of elements in this list.
     */
    protected int size;

    /**
     * The first element in this list.
     */
    protected ListEntry first;

    /**
     * The last element in this list.
     */
    protected ListEntry last;

    /**
     * Creates a new empty list.
     */
    public PacketList() {

    }

    /**
     * Creates a new list containing the specified packet data.
     * @param from Iterable of packet data
     * @throws java.lang.IllegalArgumentException If the iterable contains packets in an invalid order.
     */
    public PacketList(Iterable<PacketData> from) {
        this(from, Predicates.alwaysTrue());
    }

    /**
     * Creates a new list containing the specified packet data.
     * @param from Iterable of packet data
     * @param filter Filter for whether to include a packet
     * @throws java.lang.IllegalArgumentException If the iterable contains packets in an invalid order.
     */
    public PacketList(Iterable<PacketData> from, Predicate<PacketData> filter) {
        checkNotNull(from, "from");
        checkNotNull(filter, "filter");
        long lastTime = 0;
        ListEntry last = null;
        for (PacketData data : from) {
            if (filter.apply(data)) {
                ListEntry entry = new ListEntry(data);
                if (last == null) {
                    first = entry;
                } else {
                    if (lastTime > data.getTime()) {
                        throw new IllegalArgumentException(
                                "The specified iterable contains elements in an invalid order.");
                    }
                    last.next = entry;
                }
                entry.previous = last;
                last = entry;
                size++;
            }
        }
        if (last != null) {
            this.last = last;
            last.next = null;
        }
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public boolean contains(Object o) {
        ListEntry e = first;
        while (e != null) {
            if (e.data.equals(o)) {
                return true;
            }
            e = e.next;
        }
        return false;
    }

    @Override
    public PacketListIterator iterator() {
        return listIterator();
    }

    @Override
    public Object[] toArray() {
        Object[] array = new Object[size];
        int i = 0;
        ListEntry e = first;
        while (e != null) {
            array[i++] = e.data;
            e = e.next;
        }
        return array;
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> T[] toArray(T[] a) {
        if (a.length < size) {
            a = (T[]) Array.newInstance(a.getClass().getComponentType(), size);
        }
        ListEntry e = first;
        for (int i = 0; i < a.length; i++) {
            if (e != null) {
                a[i] = (T) e.data;
                e = e.next;
            } else {
                a[i] = null;
            }
        }
        return a;
    }

    @Override
    public boolean add(PacketData packetData) {
        // Go beyond the last packet with the specified timestamp and insert the new packet there
        iterator().skipTo(packetData.getTime() + 1).add(packetData);
        return true;
    }

    @Override
    public boolean remove(Object o) {
        PacketListIterator iter = iterator();
        while (iter.hasNext()) {
            if (iter.next().equals(o)) {
                iter.remove();
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        for (Object o : c) {
            if (!contains(o)) {
                return false;
            }
        }
        return true;
    }

    @Override
    public boolean addAll(Collection<? extends PacketData> c) {
        PacketListIterator iter = iterator();
        for (PacketData data : c) {
            iter.skipTo(data.getTime()).add(data);
        }
        return !c.isEmpty();
    }

    @Override
    public boolean addAll(int index, Collection<? extends PacketData> c) {
        return addAll(c);
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        boolean changed = false;
        PacketListIterator iter = iterator();
        while (iter.hasNext()) {
            if (c.contains(iter.next())) {
                iter.remove();
                changed = true;
            }
        }
        return changed;
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        boolean changed = false;
        PacketListIterator iter = iterator();
        while (iter.hasNext()) {
            if (!c.contains(iter.next())) {
                iter.remove();
                changed = true;
            }
        }
        return changed;
    }

    @Override
    public void sort(Comparator<? super PacketData> c) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void clear() {
        size = 0;
        first = null;
        last = null;
    }

    @Override
    public PacketData get(int index) {
        try {
            return listIterator(index).next();
        } catch (NoSuchElementException e) {
            throw new IndexOutOfBoundsException();
        }
    }

    @Override
    public PacketData set(int index, PacketData element) {
        PacketListIterator iter = listIterator(index);
        PacketData previous = iter.next();
        iter.set(element);
        return previous;
    }

    @Override
    public void add(int index, PacketData element) {
        listIterator(index).add(element);
    }

    @Override
    public PacketData remove(int index) {
        if (index < 0 || index >= size)
            throw new IndexOutOfBoundsException();
        PacketListIterator iter = listIterator(index);
        PacketData previous = iter.next();
        iter.remove();
        return previous;
    }

    @Override
    public int indexOf(Object o) {
        PacketListIterator iter = iterator();
        int i = 0;
        while (iter.hasNext()) {
            if (iter.next().equals(o)) {
                return i;
            }
            i++;
        }
        return -1;
    }

    @Override
    public int lastIndexOf(Object o) {
        PacketListIterator iter = listIterator(size);
        int i = size;
        while (iter.hasPrevious()) {
            i--;
            if (iter.previous().equals(o)) {
                return i;
            }
        }
        return -1;
    }

    @Override
    public PacketListIterator listIterator() {
        return new PacketListIterator(this);
    }

    @Override
    public PacketListIterator listIterator(int index) {
        return new PacketListIterator(this, index);
    }

    @Override
    public List<PacketData> subList(int fromIndex, int toIndex) {
        throw new UnsupportedOperationException();
    }

    @Override
    public String toString() {
        return "[" + StringUtils.join(this, ", ") + "]";
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof List) {
            PacketListIterator iter = this.listIterator();
            ListIterator<?> other = ((List<?>) obj).listIterator();
            while (other.hasNext() && iter.hasNext()) {
                if (!Objects.equals(other.next(), iter.next())) {
                    return false;
                }
            }
            return !(other.hasNext() || iter.hasNext());
        }
        return super.equals(obj);
    }

    @Override
    public int hashCode() {
        int result = 1;
        for (PacketData data : this) {
            result = 31 * result + data.hashCode();
        }
        return result;
    }

    static final class ListEntry {
        final PacketData data;

        ListEntry next;
        ListEntry previous;

        public ListEntry(PacketData data) {
            this.data = data;
        }
    }
}