Skip to content

Commit aa9e886

Browse files
committed
continue working on collections module
1 parent 9e882f9 commit aa9e886

19 files changed

Lines changed: 565 additions & 91 deletions

File tree

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ subprojects {
3232
annotationProcessor libs.lombok
3333

3434
testImplementation libs.junit.api
35+
testImplementation libs.junit.jupiter.params
3536
testCompileOnly libs.lombok
3637
testCompileOnly libs.jspecify
3738
testRuntimeOnly libs.junit.engine

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ jspecify = { module = "org.jspecify:jspecify", version.ref = "jspecify" }
2424
lombok = { module = "org.projectlombok:lombok", version.ref = "lombok" }
2525
junit-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit-jupiter" }
2626
junit-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit-jupiter" }
27+
junit-jupiter-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "junit-jupiter" }
2728
junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher", version.ref = "junit-platform-launcher" }
2829
slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
2930
slf4j-simple = { module = "org.slf4j:slf4j-simple", version.ref = "slf4j" }
@@ -33,5 +34,4 @@ angus-mail = { module = "org.eclipse.angus:angus-mail", version.ref = "angus-mai
3334
testcontainers = { module = "org.testcontainers:testcontainers", version.ref = "testcontainers" }
3435

3536
[bundles]
36-
junit = ["junit-engine", "junit-api"]
3737
mail = ["jakarta-mail-api", "angus-mail"]

rlib-collections/src/main/java/javasabr/rlib/collections/array/ArrayFactory.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import javasabr.rlib.collections.array.impl.CopyOnWriteMutableArray;
44
import javasabr.rlib.collections.array.impl.DefaultMutableArray;
5+
import javasabr.rlib.collections.array.impl.StampedLockBasedMutableArray;
56
import javasabr.rlib.common.util.ClassUtils;
67
import lombok.experimental.UtilityClass;
78

@@ -16,7 +17,11 @@ public static <E> MutableArray<E> mutableArray(Class<? super E> type, int capaci
1617
return new DefaultMutableArray<>(ClassUtils.unsafeCast(type), capacity);
1718
}
1819

19-
public static <E> MutableArray<E> newCopyOnModifyArray(Class<? super E> type) {
20+
public static <E> MutableArray<E> copyOnModifyArray(Class<? super E> type) {
2021
return new CopyOnWriteMutableArray<>(type);
2122
}
23+
24+
public static <E> LockableMutableArray<E> stampedLockBasedArray(Class<? super E> type) {
25+
return new StampedLockBasedMutableArray<>(type);
26+
}
2227
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package javasabr.rlib.collections.array;
2+
3+
import javasabr.rlib.common.util.ThreadSafe;
4+
5+
public interface LockableMutableArray<E> extends MutableArray<E>, ThreadSafe {
6+
7+
long readLock();
8+
void readUnlock(long stamp);
9+
long tryOptimisticRead();
10+
11+
boolean validateLock(long stamp);
12+
13+
long writeLock();
14+
void writeUnlock(long stamp);
15+
}

rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/AbstractArray.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import java.util.Arrays;
66
import java.util.Collection;
7+
import java.util.Objects;
78
import java.util.function.Consumer;
89
import java.util.function.Function;
910
import javasabr.rlib.collections.array.Array;
@@ -51,6 +52,11 @@ public E get(int index) {
5152
return unsafeGet(index);
5253
}
5354

55+
@Override
56+
public E unsafeGet(int index) {
57+
return wrapped()[index];
58+
}
59+
5460
protected void checkIndex(int index) {
5561
if (index < 0 || index >= size()) {
5662
throw new ArrayIndexOutOfBoundsException();
@@ -191,14 +197,52 @@ public <T> T[] toArray(Class<T> componentType) {
191197
@Override
192198
public E[] toArray() {
193199
@Nullable E[] wrapped = wrapped();
200+
//noinspection unchecked
194201
return Arrays.copyOf(wrapped, size(), (Class<E[]>) wrapped.getClass());
195202
}
196203

197204
@Override
198205
public String toString(Function<E, String> toString) {
206+
//noinspection NullableProblems
199207
return ArrayUtils.toString(wrapped(), size(), toString);
200208
}
201209

210+
@Override
211+
public String toString() {
212+
//noinspection NullableProblems
213+
return ArrayUtils.toString(wrapped(), size(), String::valueOf);
214+
}
215+
216+
@Override
217+
public boolean equals(Object another) {
218+
219+
if (!(another instanceof Array<?> array)) {
220+
return false;
221+
}
222+
223+
//noinspection NullableProblems
224+
Object[] wrapped = array
225+
.asUnsafe()
226+
.wrapped();
227+
228+
return Arrays.equals(wrapped(), 0, size(), wrapped, 0, array.size());
229+
}
230+
231+
@Override
232+
public int hashCode() {
233+
234+
@Nullable E[] wrapped = wrapped();
235+
236+
int result = 1;
237+
238+
for (int i = 0, wrappedLength = size(); i < wrappedLength; i++) {
239+
Object element = wrapped[i];
240+
result = 31 * result + (element == null ? 0 : element.hashCode());
241+
}
242+
243+
return result;
244+
}
245+
202246
@Override
203247
public UnsafeArray<E> asUnsafe() {
204248
return this;
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package javasabr.rlib.collections.array.impl;
2+
3+
import java.util.concurrent.atomic.AtomicInteger;
4+
import javasabr.rlib.collections.array.LockableMutableArray;
5+
import javasabr.rlib.common.util.ArrayUtils;
6+
import lombok.AccessLevel;
7+
import lombok.Getter;
8+
import lombok.Setter;
9+
import lombok.experimental.Accessors;
10+
import lombok.experimental.FieldDefaults;
11+
import org.jspecify.annotations.Nullable;
12+
13+
@Accessors(fluent = true, chain = false)
14+
@FieldDefaults(level = AccessLevel.PROTECTED)
15+
public abstract class AbstractLockableMutableArray<E> extends AbstractMutableArray<E> implements
16+
LockableMutableArray<E> {
17+
18+
protected static final int DEFAULT_CAPACITY = 10;
19+
20+
final AtomicInteger size;
21+
22+
@Getter
23+
@Setter(AccessLevel.PROTECTED)
24+
volatile @Nullable E[] wrapped;
25+
26+
protected AbstractLockableMutableArray(Class<? super E> type) {
27+
this(type, DEFAULT_CAPACITY);
28+
}
29+
30+
protected AbstractLockableMutableArray(Class<? super E> type, int capacity) {
31+
super(type);
32+
validateCapacity(capacity);
33+
this.wrapped = ArrayUtils.create(type, capacity);
34+
this.size = new AtomicInteger(0);
35+
}
36+
37+
@Override
38+
public int size() {
39+
return size.get();
40+
}
41+
42+
@Override
43+
protected void size(int size) {
44+
this.size.set(size);
45+
}
46+
47+
@Override
48+
public boolean isEmpty() {
49+
return size.get() < 1;
50+
}
51+
52+
@Override
53+
protected int getAndIncrementSize() {
54+
return size.getAndIncrement();
55+
}
56+
57+
@Override
58+
protected int decrementAnGetSize() {
59+
return size.decrementAndGet();
60+
}
61+
}

rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/AbstractMutableArray.java

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.Arrays;
44
import java.util.Collection;
5+
import java.util.Iterator;
56
import java.util.Objects;
67
import java.util.Spliterator;
78
import java.util.Spliterators;
@@ -69,12 +70,24 @@ public boolean addAll(Collection<? extends E> collection) {
6970
return true;
7071
}
7172

73+
@Override
74+
public UnsafeMutableArray<E> unsafeAdd(E element) {
75+
wrapped()[getAndIncrementSize()] = element;
76+
return this;
77+
}
78+
7279
@Override
7380
public void replace(int index, E element) {
7481
checkIndex(index);
7582
unsafeSet(index, element);
7683
}
7784

85+
@Override
86+
public UnsafeMutableArray<E> unsafeSet(int index, E element) {
87+
wrapped()[index] = element;
88+
return this;
89+
}
90+
7891
@Override
7992
public E remove(int index) {
8093
checkIndex(index);
@@ -91,6 +104,24 @@ public boolean remove(Object element) {
91104
return true;
92105
}
93106

107+
@Override
108+
public E unsafeRemove(int index) {
109+
110+
int numMoved = size() - index - 1;
111+
112+
@Nullable E[] wrapped = wrapped();
113+
E element = wrapped[index];
114+
115+
if (numMoved > 0) {
116+
System.arraycopy(wrapped, index + 1, wrapped, index, numMoved);
117+
}
118+
119+
wrapped[decrementAnGetSize()] = null;
120+
121+
//noinspection DataFlowIssue
122+
return element;
123+
}
124+
94125
@Override
95126
public boolean removeAll(Collection<?> collection) {
96127
if (collection.isEmpty()) {
@@ -130,11 +161,16 @@ public boolean retainAll(Collection<?> collection) {
130161

131162
@Override
132163
public void clear() {
133-
if (isEmpty()) {
134-
return;
164+
int size = size();
165+
if (size > 0) {
166+
Arrays.fill(wrapped(), 0, size, null);
167+
size(0);
135168
}
136-
Arrays.fill(wrapped(), 0, size(), null);
137-
size(0);
169+
}
170+
171+
@Override
172+
public Iterator<E> iterator() {
173+
return new DefaultMutableArrayIterator<>(this);
138174
}
139175

140176
@Override
@@ -159,10 +195,42 @@ protected void processAdd(E[] array, int currentSize, int elementsToAdd) {
159195

160196
protected abstract void size(int size);
161197

198+
protected abstract int getAndIncrementSize();
199+
protected abstract int decrementAnGetSize();
200+
162201
protected abstract void wrapped(@Nullable E[] wrapped);
163202

203+
@Override
204+
public UnsafeMutableArray<E> prepareForSize(int expectedSize) {
205+
@Nullable E[] wrapped = wrapped();
206+
if (expectedSize > wrapped.length) {
207+
int newLength = Math.max((wrapped.length * 3) / 2, expectedSize);
208+
wrapped(Arrays.copyOf(wrapped, newLength));
209+
}
210+
return this;
211+
}
212+
213+
214+
@Override
215+
public UnsafeMutableArray<E> trimToSize() {
216+
@Nullable E[] wrapped = wrapped();
217+
int size = size();
218+
219+
if (size == wrapped.length) {
220+
return this;
221+
}
222+
wrapped(Arrays.copyOfRange(wrapped, 0, size));
223+
return this;
224+
}
225+
164226
@Override
165227
public UnsafeMutableArray<E> asUnsafe() {
166228
return this;
167229
}
230+
231+
protected static void validateCapacity(int capacity) {
232+
if (capacity < 0) {
233+
throw new IllegalArgumentException("Capacity cannot be negative");
234+
}
235+
}
168236
}

rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/CopyOnWriteMutableArray.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package javasabr.rlib.collections.array.impl;
22

3-
import java.lang.invoke.VarHandle;
43
import java.util.Arrays;
54
import java.util.Collection;
65
import java.util.ConcurrentModificationException;
@@ -188,6 +187,8 @@ public E unsafeGet(int index) {
188187
return wrapped.get()[index];
189188
}
190189

190+
/* disabled methods */
191+
191192
@Override
192193
public UnsafeMutableArray<E> prepareForSize(int expectedSize) {
193194
return this;
@@ -197,4 +198,14 @@ public UnsafeMutableArray<E> prepareForSize(int expectedSize) {
197198
public UnsafeMutableArray<E> trimToSize() {
198199
return this;
199200
}
201+
202+
@Override
203+
protected int getAndIncrementSize() {
204+
return 0;
205+
}
206+
207+
@Override
208+
protected int decrementAnGetSize() {
209+
return 0;
210+
}
200211
}

rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/DefaultArrayIterator.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@
1010
/**
1111
* @author JavaSaBr
1212
*/
13-
@FieldDefaults(level = AccessLevel.PRIVATE)
13+
@FieldDefaults(level = AccessLevel.PROTECTED)
1414
public class DefaultArrayIterator<E> implements Iterator<E> {
1515

1616
final @Nullable E[] wrapped;
1717
final int size;
1818

19-
private int position;
19+
int position;
2020

2121
public DefaultArrayIterator(Array<E> array) {
2222
this.wrapped = array.asUnsafe().wrapped();

0 commit comments

Comments
 (0)