summaryrefslogtreecommitdiffstats
path: root/src/main/java/org/bukkit/craftbukkit/util/UnsafeList.java
blob: f23801e45ba956d7aaa180ecba1b88d088489a4e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package org.bukkit.craftbukkit.util;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.AbstractList;
import java.util.Arrays;
import java.util.List;
import java.util.RandomAccess;

// implementation of an ArrayList that offers a getter without range checks
public class UnsafeList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
    private static final long serialVersionUID = 8683452581112892189L;
    private transient Object[] data;
    private int size;

    public UnsafeList(int capacity) {
        super();
        if (capacity < 0) capacity = 128;
        int rounded = Integer.highestOneBit(capacity - 1) << 1;
        data = new Object[rounded];
    }

    public UnsafeList() {
        this(128);
    }

    public E get(int index) {
        rangeCheck(index);

        return (E) data[index];
    }

    public E unsafeGet(int index) {
        return (E) data[index];
    }

    public E set(int index, E element) {
        rangeCheck(index);

        E old = (E) data[index];
        data[index] = element;
        return old;
    }

    public boolean add(E element) {
        growIfNeeded();
        data[size++] = element;
        return true;
    }

    public void add(int index, E element) {
        growIfNeeded();
        System.arraycopy(data, index, data, index + 1, size - index);
        data[index] = element;
        size++;
    }

    public E remove(int index) {
        rangeCheck(index);

        E old = (E) data[index];
        int movedCount = size - index - 1;
        if (movedCount > 0) {
            System.arraycopy(data, index + 1, data, index, movedCount);
        }
        data[--size] = null;

        return old;
    }

    public boolean remove(Object o) {
        int index = indexOf(o);
        if (index >= 0) {
            remove(index);
            return true;
        }

        return false;
    }

    public int indexOf(Object o) {
        for (int i = 0; i < size; i++) {
            if (o == data[i] || o.equals(data[i])) {
                return i;
            }
        }

        return -1;
    }

    public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }

    public void clear() {
        for (int i = 0; i < size; i++) {
            data[i] = null;
        }

        size = 0;
    }

    // actually rounds up to nearest power of two
    public void trimToSize() {
        int old = data.length;
        int rounded = Integer.highestOneBit(size - 1) << 1;
        if (rounded < old) {
            data = Arrays.copyOf(data, rounded);
        }
    }

    public int size() {
        return size;
    }

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

    private void rangeCheck(int index) {
        if (index >= size || index < 0) {
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
        }
    }

    private void growIfNeeded() {
        if (size == data.length) {
            Object[] newData = new Object[data.length << 1];
            System.arraycopy(data, 0, newData, 0, size);
            data = newData;
        }
    }

    private void writeObject(ObjectOutputStream os) throws IOException {
        os.defaultWriteObject();

        os.writeInt(size);
        for (int i = 0; i < size; i++) {
            os.writeObject(data[i]);
        }
    }

    private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException {
        is.defaultReadObject();

        size = is.readInt();
        data = new Object[Integer.highestOneBit(size - 1) << 1];
        for (int i = 0; i < size; i++) {
            data[i] = is.readObject();
        }
    }
}