From d512ff198866567d516008f303781ed688b9c35f Mon Sep 17 00:00:00 2001 From: javasabr Date: Sun, 14 Sep 2025 18:15:52 +0200 Subject: [PATCH 1/4] continue implementing array based deque --- .../rlib/collections/deque/DequeFactory.java | 10 + .../deque/impl/AbstractArrayBasedDeque.java | 501 ++++++++++++++++ .../collections/deque/impl/AbstractDeque.java | 71 +++ .../impl/AbstractLinkedListBasedDeque.java | 68 +-- .../deque/impl/DefaultArrayBasedDeque.java | 63 ++ .../rlib/collections/array/DequeTest.java | 544 ++++++++++++++++++ .../javasabr/rlib/common/util/ArrayUtils.java | 32 +- 7 files changed, 1209 insertions(+), 80 deletions(-) create mode 100644 rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/AbstractArrayBasedDeque.java create mode 100644 rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/AbstractDeque.java create mode 100644 rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/DefaultArrayBasedDeque.java create mode 100644 rlib-collections/src/test/java/javasabr/rlib/collections/array/DequeTest.java diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/deque/DequeFactory.java b/rlib-collections/src/main/java/javasabr/rlib/collections/deque/DequeFactory.java index cee65390..f07a3c79 100644 --- a/rlib-collections/src/main/java/javasabr/rlib/collections/deque/DequeFactory.java +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/deque/DequeFactory.java @@ -1,6 +1,7 @@ package javasabr.rlib.collections.deque; import java.util.Deque; +import javasabr.rlib.collections.deque.impl.DefaultArrayBasedDeque; import javasabr.rlib.collections.deque.impl.DefaultLinkedListBasedDeque; import lombok.experimental.UtilityClass; @@ -9,7 +10,16 @@ */ @UtilityClass public class DequeFactory { + public static Deque linkedListBased() { return new DefaultLinkedListBasedDeque<>(); } + + public static Deque arrayBasedBased(Class type) { + return new DefaultArrayBasedDeque<>(type); + } + + public static Deque arrayBasedBased(Class type, int capacity) { + return new DefaultArrayBasedDeque<>(type, capacity); + } } diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/AbstractArrayBasedDeque.java b/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/AbstractArrayBasedDeque.java new file mode 100644 index 00000000..a1f6e232 --- /dev/null +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/AbstractArrayBasedDeque.java @@ -0,0 +1,501 @@ +package javasabr.rlib.collections.deque.impl; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Deque; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Objects; +import javasabr.rlib.common.util.ArrayUtils; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; +import org.jspecify.annotations.Nullable; + +@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) +public abstract class AbstractArrayBasedDeque implements Deque { + + protected static final int SMALL_SIZE = 100; + protected static final int SMALL_STEP = 10; + protected static final int BIG_STEP = 50; + protected static final int DEFAULT_CAPACITY = 20; + protected static final float REBALANCE_FACTOR = 0.8F; + protected static final int MIN_SIZE_FOR_REBALANCE = 50; + + Class type; + float rebalanceFactor; + + protected AbstractArrayBasedDeque(Class type, float rebalanceFactor) { + this.type = type; + this.rebalanceFactor = rebalanceFactor; + } + + protected abstract int head(); + protected abstract void head(int head); + + protected abstract int tail(); + protected abstract void tail(int tail); + + protected abstract int rebalanceTrigger(); + + protected abstract void rebalanceTrigger(int rebalanceTrigger); + + protected abstract @Nullable E[] items(); + protected abstract void items(E[] items); + + protected void resetIndexes() { + @Nullable E[] items = items(); + int head = items.length / 2; + head(head); + tail(head); + updateRebalanceTrigger(items); + } + + protected void updateRebalanceTrigger(@Nullable E[] items) { + int length = items.length; + int rebalanceTrigger = length > MIN_SIZE_FOR_REBALANCE ? (int) (length * rebalanceFactor) : Integer.MAX_VALUE; + rebalanceTrigger(rebalanceTrigger); + } + + @Override + public void addFirst(E element) { + + @Nullable E[] items = items(); + int size = size(); + int head = head(); + + if (head == 0) { + items = increaseLeft(items, size); + } + + int index = size > 0 ? decrementHeadAndGet() : head; + items[index] = element; + + incrementSize(); + } + + @Override + public boolean offerFirst(E element) { + addFirst(element); + return true; + } + + @Override + public void addLast(E element) { + + @Nullable E[] items = items(); + int size = size(); + int tail = tail(); + + if (tail == items.length - 1) { + items = increaseRight(items, size); + } + + int index = size > 0 ? incrementTailAndGet() : tail; + items[index] = element; + + incrementSize(); + } + + @Override + public boolean offerLast(E element) { + addLast(element); + return true; + } + + protected abstract int decrementHeadAndGet(); + protected abstract int incrementHeadAndGet(); + + protected abstract int incrementTailAndGet(); + protected abstract int decrementTailAndGet(); + + protected abstract void incrementSize(); + protected abstract void decrementSize(); + + protected @Nullable E[] increaseLeft(@Nullable E[] items, int size) { + + int stepSize = stepSize(items); + E[] newItems = ArrayUtils.create(type, items.length + stepSize); + + System.arraycopy(items, 0, newItems, stepSize, size); + + items(newItems); + head(stepSize); + tail(tail() + stepSize); + updateRebalanceTrigger(items); + return newItems; + } + + protected @Nullable E[] increaseRight(@Nullable E[] items, int size) { + + int stepSize = stepSize(items); + E[] newItems = ArrayUtils.create(type, items.length + stepSize); + int head = head(); + + System.arraycopy(items, head, newItems, head, size); + + items(newItems); + updateRebalanceTrigger(items); + return newItems; + } + + private void rebalance() { + + @Nullable E[] items = items(); + int size = size(); + int offset = size / 2; + int suggestedHead = items.length / 2 - offset; + int suggestedTail = suggestedHead + size - 1; + int head = head(); + int tail = tail(); + + if (head < suggestedHead && tail > suggestedTail) { + return; + } + + System.arraycopy(items, head, items, suggestedHead, size); + + head(suggestedHead); + tail(suggestedTail); + + if (head > suggestedHead) { + Arrays.fill(items, suggestedHead + size, tail + 1, null); + } else if (tail < suggestedTail) { + Arrays.fill(items, head, suggestedHead, null); + } + } + + @Override + public E removeFirst() { + + if (isEmpty()) { + throw new NoSuchElementException(); + } + + @Nullable E[] items = items(); + int head = head(); + + E item = items[head]; + items[head] = null; + + decrementSize(); + int newHead = incrementHeadAndGet(); + + if (head == tail()) { + tail(newHead); + } + + if (newHead > rebalanceTrigger()) { + rebalance(); + } + + //noinspection DataFlowIssue + return item; + } + + @Override + public E removeLast() { + + if (isEmpty()) { + throw new NoSuchElementException(); + } + + @Nullable E[] items = items(); + int tail = tail(); + + E item = items[tail]; + items[tail] = null; + + decrementSize(); + int newTail = decrementTailAndGet(); + + if (tail == head()) { + head(newTail); + } + + if (items.length - tail > rebalanceTrigger()) { + rebalance(); + } + + //noinspection DataFlowIssue + return item; + } + + @Nullable + @Override + public E pollFirst() { + if (isEmpty()) { + return null; + } else { + return removeFirst(); + } + } + + @Nullable + @Override + public E pollLast() { + if (isEmpty()) { + return null; + } else { + return removeLast(); + } + } + + @Nullable + @Override + public E peekFirst() { + if (isEmpty()) { + return null; + } else { + return items()[head()]; + } + } + + @Nullable + @Override + public E peekLast() { + if (isEmpty()) { + return null; + } else { + return items()[tail()]; + } + } + + @Override + public E getFirst() { + E first = peekFirst(); + if (first == null) { + throw new NoSuchElementException(); + } + return first; + } + + @Override + public E getLast() { + E last = peekLast(); + if (last == null) { + throw new NoSuchElementException(); + } + return last; + } + + @Override + public boolean removeFirstOccurrence(Object o) { + return false; + } + + @Override + public boolean removeLastOccurrence(Object o) { + return false; + } + + @Override + public boolean add(E element) { + offerLast(element); + return true; + } + + @Override + public boolean offer(E element) { + offerLast(element); + return true; + } + + @Override + public E remove() { + return removeFirst(); + } + + @Nullable + @Override + public E poll() { + return pollFirst(); + } + + @Override + public E element() { + return getFirst(); + } + + @Nullable + @Override + public E peek() { + return peekFirst(); + } + + @Override + public boolean addAll(Collection collection) { + for (E element : collection) { + addLast(element); + } + return true; + } + + @Override + public boolean removeAll(Collection c) { + return false; + } + + @Override + public boolean retainAll(Collection c) { + return false; + } + + @Override + public void clear() { + if (!isEmpty()) { + @Nullable E[] items = items(); + Arrays.fill(items, head(), tail(), null); + head(items.length); + tail(-1); + } + } + + @Override + public void push(E element) { + addFirst(element); + } + + @Override + public E pop() { + return removeFirst(); + } + + @Override + public boolean remove(Object object) { + + if (isEmpty()) { + return false; + } + + @Nullable E[] items = items(); + int head = head(); + int tail = tail(); + + if (Objects.equals(items[head], object)) { + removeFirst(); + return true; + } else if (head != tail && Objects.equals(items[tail], object)) { + removeLast(); + return true; + } + + for (int i = head + 1; i < tail; i++) { + E item = items[i]; + + if (!Objects.equals(item, object)) { + continue; + } + + int distanceToHead = i - head; + int distanceToTail = tail - i; + + if (distanceToHead < distanceToTail) { + // [n][n][o][o][t][o]|[o][o][n][n] -> [n][n][n][o][o][o]|[o][o][n][n] + System.arraycopy(items, head, items, head + 1, distanceToHead); + items[head] = null; + incrementHeadAndGet(); + decrementSize(); + } else { + // [n][n][o][o]|[o][o][t][o][n][n] -> [n][n][o][o]|[o][o][o][n][n][n] + System.arraycopy(items, i + 1, items, i, distanceToTail); + items[tail] = null; + decrementTailAndGet(); + decrementSize(); + } + + return true; + } + + return false; + } + + @Override + public boolean containsAll(Collection collection) { + for (Object object : collection) { + if (!contains(object)) { + return false; + } + } + return true; + } + + @Override + public boolean contains(Object object) { + + if (isEmpty()) { + return false; + } + + @Nullable E[] items = items(); + for (int i = head(), limit = tail(); i <= limit; i++) { + E item = items[i]; + if (Objects.equals(item, object)) { + return true; + } + } + + return false; + } + + @Override + public boolean isEmpty() { + return size() < 1; + } + + @Override + public Iterator iterator() { + return null; + } + + @Override + public Object[] toArray() { + + if (isEmpty()) { + return ArrayUtils.EMPTY_OBJECT_ARRAY; + } + + @Nullable E[] items = items(); + Object[] result = new Object[size()]; + + for (int i = head(), j = 0, limit = tail(); i <= limit; i++) { + //noinspection DataFlowIssue + result[j++] = items[i]; + } + + return result; + } + + @Override + public T[] toArray(T[] container) { + + int size = size(); + if (size < 1) { + return container; + } else if (size > container.length) { + container = ArrayUtils.create(container, size); + } + + @Nullable E[] items = items(); + + for (int i = head(), j = 0, limit = tail(); i <= limit; i++) { + //noinspection DataFlowIssue,SingleStatementInBlock,unchecked + container[j++] = (T) items[i]; + } + + return container; + } + + @Override + public Iterator descendingIterator() { + return null; + } + + @Override + public String toString() { + return ArrayUtils.toString(items(), head(), size(), ", ", false, true); + } + + protected static int stepSize(@Nullable T[] items) { + return items.length > SMALL_SIZE ? BIG_STEP : SMALL_STEP; + } +} diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/AbstractDeque.java b/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/AbstractDeque.java new file mode 100644 index 00000000..8976c6d5 --- /dev/null +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/AbstractDeque.java @@ -0,0 +1,71 @@ +package javasabr.rlib.collections.deque.impl; + +import java.util.Collection; +import java.util.Deque; + +public abstract class AbstractDeque implements Deque { + + @Override + public boolean addAll(Collection collection) { + int changed = 0; + for (E object : collection) { + if (add(object)) { + changed++; + } + } + return changed > 0; + } + + @Override + public boolean containsAll(Collection collection) { + for (Object object : collection) { + if (!contains(object)) { + return false; + } + } + return true; + } + + @Override + public E element() { + return getFirst(); + } + + @Override + public boolean isEmpty() { + return size() < 1; + } + + @Override + public E pop() { + return removeFirst(); + } + + @Override + public E remove() { + return removeFirst(); + } + + @Override + public String toString() { + + StringBuilder builder = new StringBuilder("["); + + if (!isEmpty()) { + + for (E element : this) { + builder + .append(element) + .append(", "); + } + + if (builder.indexOf(",") != -1) { + builder.delete(builder.length() - 2, builder.length()); + } + } + + builder.append("]"); + + return builder.toString(); + } +} diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/AbstractLinkedListBasedDeque.java b/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/AbstractLinkedListBasedDeque.java index c93d5b90..dbe51600 100644 --- a/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/AbstractLinkedListBasedDeque.java +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/AbstractLinkedListBasedDeque.java @@ -1,14 +1,13 @@ package javasabr.rlib.collections.deque.impl; import java.util.Collection; -import java.util.Deque; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Objects; import javasabr.rlib.common.util.ArrayUtils; import org.jspecify.annotations.Nullable; -public abstract class AbstractLinkedListBasedDeque implements Deque { +public abstract class AbstractLinkedListBasedDeque extends AbstractDeque { @Nullable protected abstract LinkedNode firstNode(); @@ -25,18 +24,6 @@ public abstract class AbstractLinkedListBasedDeque implements Deque { protected abstract void linkFirst(E item); protected abstract void linkLast(E item); - @Override - public boolean addAll(Collection collection) { - - for (E object : collection) { - if (!add(object)) { - return false; - } - } - - return true; - } - @Override public boolean contains(@Nullable Object object) { if (object == null) { @@ -50,21 +37,6 @@ public boolean contains(@Nullable Object object) { return false; } - @Override - public boolean containsAll(Collection collection) { - for (Object object : collection) { - if (!contains(object)) { - return false; - } - } - return true; - } - - @Override - public E element() { - return getFirst(); - } - @Override public E getFirst() { @@ -89,11 +61,6 @@ public E getLast() { return linkedNode.item; } - @Override - public boolean isEmpty() { - return size() < 1; - } - @Override public boolean offer(E element) { return add(element); @@ -132,11 +99,6 @@ public E peekLast() { return last == null ? null : last.item; } - @Override - public E pop() { - return removeFirst(); - } - @Override public void push(E element) { linkFirst(element); @@ -179,11 +141,6 @@ public E pollLast() { return last == null ? null : unlinkLast(last); } - @Override - public E remove() { - return removeFirst(); - } - @Override public E removeFirst() { LinkedNode first = firstNode(); @@ -312,27 +269,4 @@ public T[] toArray(T[] container) { return container; } - - @Override - public String toString() { - - StringBuilder builder = new StringBuilder("["); - - if (!isEmpty()) { - - for (E element : this) { - builder - .append(element) - .append(", "); - } - - if (builder.indexOf(",") != -1) { - builder.delete(builder.length() - 2, builder.length()); - } - } - - builder.append("]"); - - return builder.toString(); - } } diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/DefaultArrayBasedDeque.java b/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/DefaultArrayBasedDeque.java new file mode 100644 index 00000000..b53048dd --- /dev/null +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/DefaultArrayBasedDeque.java @@ -0,0 +1,63 @@ +package javasabr.rlib.collections.deque.impl; + +import javasabr.rlib.common.util.ArrayUtils; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; +import org.jspecify.annotations.Nullable; + +@Getter(AccessLevel.PROTECTED) +@Setter(AccessLevel.PROTECTED) +@Accessors(fluent = true, chain = false) +@FieldDefaults(level = AccessLevel.PROTECTED) +public class DefaultArrayBasedDeque extends AbstractArrayBasedDeque { + + @Nullable E[] items; + int head; + int tail; + int rebalanceTrigger; + + @Getter int size; + + public DefaultArrayBasedDeque(Class type) { + this(type, DEFAULT_CAPACITY); + } + + public DefaultArrayBasedDeque(Class type, int capacity) { + super(type, REBALANCE_FACTOR); + this.items = ArrayUtils.create(type, capacity); + resetIndexes(); + } + + @Override + protected int decrementHeadAndGet() { + return --head; + } + + @Override + protected int incrementHeadAndGet() { + return ++head; + } + + @Override + protected int incrementTailAndGet() { + return ++tail; + } + + @Override + protected int decrementTailAndGet() { + return --tail; + } + + @Override + protected void incrementSize() { + size++; + } + + @Override + protected void decrementSize() { + size--; + } +} diff --git a/rlib-collections/src/test/java/javasabr/rlib/collections/array/DequeTest.java b/rlib-collections/src/test/java/javasabr/rlib/collections/array/DequeTest.java new file mode 100644 index 00000000..4278f1ee --- /dev/null +++ b/rlib-collections/src/test/java/javasabr/rlib/collections/array/DequeTest.java @@ -0,0 +1,544 @@ +package javasabr.rlib.collections.array; + +import static javasabr.rlib.common.util.ArrayUtils.array; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.lang.reflect.Field; +import java.util.Deque; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.stream.Stream; +import javasabr.rlib.collections.deque.DequeFactory; +import javasabr.rlib.common.util.ReflectionUtils; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class DequeTest { + + @ParameterizedTest + @MethodSource("generateDeque") + void shouldAddFirst(Deque deque) { + + // when: + deque.addFirst("val1"); + deque.addFirst("val2"); + + // then: + assertArrayEquals(deque.toArray(), array("val2", "val1")); + + // when: + deque.addFirst("val3"); + deque.addFirst("val4"); + + // then: + assertArrayEquals(deque.toArray(), array("val4", "val3", "val2", "val1")); + + // when: + deque.addFirst("val5"); + deque.addFirst("val6"); + deque.addFirst("val7"); + deque.addFirst("val8"); + deque.addFirst("val9"); + deque.addFirst("val10"); + deque.addFirst("val11"); + deque.addFirst("val12"); + + // then: + assertArrayEquals(deque.toArray(), array("val12", "val11", "val10", "val9", "val8", + "val7", "val6", "val5", "val4", "val3", "val2", "val1")); + } + + @ParameterizedTest + @MethodSource("generateDeque") + void shouldAddLast(Deque deque) { + + // when: + deque.addLast("val1"); + deque.addLast("val2"); + + // then: + assertArrayEquals(deque.toArray(), array("val1", "val2")); + + // when: + deque.addLast("val3"); + deque.addLast("val4"); + + // then: + assertArrayEquals(deque.toArray(), array("val1", "val2", "val3", "val4")); + + // when: + deque.addLast("val5"); + deque.addLast("val6"); + deque.addLast("val7"); + deque.addLast("val8"); + deque.addLast("val9"); + deque.addLast("val10"); + deque.addLast("val11"); + deque.addLast("val12"); + + // then: + assertArrayEquals(deque.toArray(), array("val1", "val2", "val3", "val4", "val5", + "val6", "val7", "val8", "val9", "val10", "val11", "val12")); + } + + @ParameterizedTest + @MethodSource("generateDeque") + void shouldAddFirstAndAddLastInMixMode(Deque deque) { + + // when: + deque.addFirst("val1"); + deque.addFirst("val2"); + + // then: + assertArrayEquals(deque.toArray(), array("val2", "val1")); + + // when: + deque.addLast("val3"); + deque.addLast("val4"); + + // then: + assertArrayEquals(deque.toArray(), array("val2", "val1", "val3", "val4")); + + // when: + deque.addFirst("val5"); + deque.addFirst("val6"); + deque.addFirst("val7"); + deque.addLast("val8"); + deque.addLast("val9"); + deque.addLast("val10"); + deque.addFirst("val11"); + deque.addLast("val12"); + + // then: + assertArrayEquals(deque.toArray(), array("val11", "val7", "val6", "val5", "val2", + "val1", "val3", "val4", "val8", "val9", "val10", "val12")); + } + + @ParameterizedTest + @MethodSource("generateDeque") + void shouldRemoveFirst(Deque deque) { + + // given: + deque.addAll(List.of("val1", "val2", "val3", "val4", "val5")); + + // when: + var removed1 = deque.removeFirst(); + var removed2 = deque.removeFirst(); + + // then: + assertEquals("val1", removed1); + assertEquals("val2", removed2); + assertArrayEquals(deque.toArray(), array("val3", "val4", "val5")); + + // when: + var removed3 = deque.removeFirst(); + var removed4 = deque.removeFirst(); + + // then: + assertEquals("val3", removed3); + assertEquals("val4", removed4); + assertArrayEquals(deque.toArray(), array("val5")); + + // when: + var removed5 = deque.removeFirst(); + + // then: + assertEquals("val5", removed5); + assertArrayEquals(deque.toArray(), array()); + + // when/then: + Assertions.assertThrows(NoSuchElementException.class, deque::removeFirst); + } + + @ParameterizedTest + @MethodSource("generateDeque") + void shouldRemoveLast(Deque deque) { + + // given: + deque.addAll(List.of("val1", "val2", "val3", "val4", "val5")); + + // when: + var removed1 = deque.removeLast(); + var removed2 = deque.removeLast(); + + // then: + assertEquals("val5", removed1); + assertEquals("val4", removed2); + assertArrayEquals(deque.toArray(), array("val1", "val2", "val3")); + + // when: + var removed3 = deque.removeLast(); + var removed4 = deque.removeLast(); + + // then: + assertEquals("val3", removed3); + assertEquals("val2", removed4); + assertArrayEquals(deque.toArray(), array("val1")); + + // when: + var removed5 = deque.removeLast(); + + // then: + assertEquals("val1", removed5); + assertArrayEquals(deque.toArray(), array()); + + // when/then: + Assertions.assertThrows(NoSuchElementException.class, deque::removeLast); + } + + @ParameterizedTest + @MethodSource("generateDeque") + void shouldRemoveFirstAndLast(Deque deque) { + + // given: + deque.addAll(List.of("val1", "val2", "val3", "val4", "val5", "val6", "val7", "val8")); + + // when: + var removed1 = deque.removeFirst(); + var removed2 = deque.removeLast(); + + // then: + assertEquals("val1", removed1); + assertEquals("val8", removed2); + assertArrayEquals(deque.toArray(), array("val2", "val3", "val4", "val5", "val6", "val7")); + + // when: + var removed3 = deque.removeFirst(); + var removed4 = deque.removeLast(); + + // then: + assertEquals("val2", removed3); + assertEquals("val7", removed4); + assertArrayEquals(deque.toArray(), array("val3", "val4", "val5", "val6")); + + // when: + var removed5 = deque.removeFirst(); + var removed6 = deque.removeFirst(); + var removed7 = deque.removeLast(); + var removed8 = deque.removeLast(); + + // then: + assertEquals("val3", removed5); + assertEquals("val4", removed6); + assertEquals("val6", removed7); + assertEquals("val5", removed8); + assertArrayEquals(deque.toArray(), array()); + + // when/then: + Assertions.assertThrows(NoSuchElementException.class, deque::removeFirst); + Assertions.assertThrows(NoSuchElementException.class, deque::removeLast); + } + + @ParameterizedTest + @MethodSource("generateDeque") + void shouldRemoveElement(Deque deque) { + + // given: + deque.addAll(List.of("val1", "val2", "val3", "val4", "val5", "val6", "val7", "val8", "val9", "val10")); + + // when: + deque.remove("val9"); + + // then: + assertArrayEquals(deque.toArray(), array("val1", "val2", "val3", "val4", "val5", "val6", "val7", "val8", "val10")); + + // when: + deque.remove("val2"); + + // then: + assertArrayEquals(deque.toArray(), array("val1", "val3", "val4", "val5", "val6", "val7", "val8", "val10")); + + // when: + deque.remove("val5"); + + // then: + assertArrayEquals(deque.toArray(), array("val1", "val3", "val4", "val6", "val7", "val8", "val10")); + + // when: + deque.remove("val6"); + + // then: + assertArrayEquals(deque.toArray(), array("val1", "val3", "val4", "val7", "val8", "val10")); + + // when: + deque.remove("val1"); + + // then: + assertArrayEquals(deque.toArray(), array("val3", "val4", "val7", "val8", "val10")); + + // when: + deque.remove("val10"); + + // then: + assertArrayEquals(deque.toArray(), array("val3", "val4", "val7", "val8")); + } + + @ParameterizedTest + @MethodSource("generateDeque") + void shouldCheckContains(Deque deque) { + + // given: + deque.addAll(List.of("val1", "val2", "val3", "val4", "val5", "val6", "val7", "val8", "val9", "val10")); + + // when/then: + assertTrue(deque.contains("val1")); + assertTrue(deque.contains("val10")); + assertTrue(deque.contains("val3")); + assertTrue(deque.contains("val8")); + assertFalse(deque.contains("val55")); + } + + @Test + void shouldRebalanceIndexesAddLastRemoveFirst() { + + // given: + Deque deque = DequeFactory.arrayBasedBased(String.class, 15); + Field head = ReflectionUtils.getUnsafeField(deque, "head"); + Field tail = ReflectionUtils.getUnsafeField(deque, "tail"); + + // when: + for (int i = 1; i < 12; i++) { + deque.addLast("val%s".formatted(i)); + } + for (int i = 1; i < 12; i++) { + deque.removeFirst(); + } + + int headValue = ReflectionUtils.getFieldValue(deque, head); + int tailValue = ReflectionUtils.getFieldValue(deque, tail); + + // then: + assertEquals(18, headValue); + assertEquals(18, tailValue); + assertEquals(0, deque.size()); + + // when: + for (int i = 12; i < 24; i++) { + deque.addLast("val%s".formatted(i)); + } + for (int i = 1; i < 12; i++) { + deque.removeFirst(); + } + + headValue = ReflectionUtils.getFieldValue(deque, head); + tailValue = ReflectionUtils.getFieldValue(deque, tail); + + // then: + assertEquals(29, headValue); + assertEquals(29, tailValue); + assertEquals(1, deque.size()); + + // when: + for (int i = 24; i < 36; i++) { + deque.addLast("val%s".formatted(i)); + } + for (int i = 1; i < 12; i++) { + deque.removeFirst(); + } + + headValue = ReflectionUtils.getFieldValue(deque, head); + tailValue = ReflectionUtils.getFieldValue(deque, tail); + + // then: + assertEquals(40, headValue); + assertEquals(41, tailValue); + assertEquals(2, deque.size()); + + // when: + for (int i = 36; i < 48; i++) { + deque.addLast("val%s".formatted(i)); + } + for (int i = 1; i < 12; i++) { + deque.removeFirst(); + } + + headValue = ReflectionUtils.getFieldValue(deque, head); + tailValue = ReflectionUtils.getFieldValue(deque, tail); + + // then: + assertEquals(51, headValue); + assertEquals(53, tailValue); + assertEquals(3, deque.size()); + + // when: + for (int i = 48; i < 60; i++) { + deque.addLast("val%s".formatted(i)); + } + for (int i = 1; i < 12; i++) { + deque.removeFirst(); + } + + headValue = ReflectionUtils.getFieldValue(deque, head); + tailValue = ReflectionUtils.getFieldValue(deque, tail); + + // then: + assertEquals(40, headValue); + assertEquals(43, tailValue); + assertEquals(4, deque.size()); + + // when: + for (int i = 60; i < 72; i++) { + deque.addLast("val%s".formatted(i)); + } + for (int i = 1; i < 12; i++) { + deque.removeFirst(); + } + + headValue = ReflectionUtils.getFieldValue(deque, head); + tailValue = ReflectionUtils.getFieldValue(deque, tail); + + // then: + assertEquals(51, headValue); + assertEquals(55, tailValue); + assertEquals(5, deque.size()); + + // when: + for (int i = 60; i < 72; i++) { + deque.addLast("val%s".formatted(i)); + } + for (int i = 1; i < 12; i++) { + deque.removeFirst(); + } + + headValue = ReflectionUtils.getFieldValue(deque, head); + tailValue = ReflectionUtils.getFieldValue(deque, tail); + + // then: + assertEquals(39, headValue); + assertEquals(44, tailValue); + assertEquals(6, deque.size()); + } + + @Test + void shouldRebalanceIndexesAddFirstRemoveLast() { + + // given: + Deque deque = DequeFactory.arrayBasedBased(String.class, 15); + Field head = ReflectionUtils.getUnsafeField(deque, "head"); + Field tail = ReflectionUtils.getUnsafeField(deque, "tail"); + + // when: + for (int i = 1; i < 12; i++) { + deque.addFirst("val%s".formatted(i)); + } + for (int i = 1; i < 12; i++) { + deque.removeLast(); + } + + int headValue = ReflectionUtils.getFieldValue(deque, head); + int tailValue = ReflectionUtils.getFieldValue(deque, tail); + + // then: + assertEquals(6, headValue); + assertEquals(6, tailValue); + assertEquals(0, deque.size()); + + // when: + for (int i = 12; i < 24; i++) { + deque.addFirst("val%s".formatted(i)); + } + for (int i = 1; i < 12; i++) { + deque.removeLast(); + } + + headValue = ReflectionUtils.getFieldValue(deque, head); + tailValue = ReflectionUtils.getFieldValue(deque, tail); + + // then: + assertEquals(5, headValue); + assertEquals(5, tailValue); + assertEquals(1, deque.size()); + + // when: + for (int i = 24; i < 36; i++) { + deque.addFirst("val%s".formatted(i)); + } + for (int i = 1; i < 12; i++) { + deque.removeLast(); + } + + headValue = ReflectionUtils.getFieldValue(deque, head); + tailValue = ReflectionUtils.getFieldValue(deque, tail); + + // then: + assertEquals(3, headValue); + assertEquals(4, tailValue); + assertEquals(2, deque.size()); + + // when: + for (int i = 36; i < 48; i++) { + deque.addFirst("val%s".formatted(i)); + } + for (int i = 1; i < 12; i++) { + deque.removeLast(); + } + + headValue = ReflectionUtils.getFieldValue(deque, head); + tailValue = ReflectionUtils.getFieldValue(deque, tail); + + // then: + assertEquals(1, headValue); + assertEquals(3, tailValue); + assertEquals(3, deque.size()); + + // when: + for (int i = 48; i < 60; i++) { + deque.addFirst("val%s".formatted(i)); + } + for (int i = 1; i < 12; i++) { + deque.removeLast(); + } + + headValue = ReflectionUtils.getFieldValue(deque, head); + tailValue = ReflectionUtils.getFieldValue(deque, tail); + + // then: + assertEquals(31, headValue); + assertEquals(34, tailValue); + assertEquals(4, deque.size()); + + // when: + for (int i = 60; i < 72; i++) { + deque.addFirst("val%s".formatted(i)); + } + for (int i = 1; i < 12; i++) { + deque.removeLast(); + } + + headValue = ReflectionUtils.getFieldValue(deque, head); + tailValue = ReflectionUtils.getFieldValue(deque, tail); + + // then: + assertEquals(19, headValue); + assertEquals(23, tailValue); + assertEquals(5, deque.size()); + + // when: + for (int i = 60; i < 72; i++) { + deque.addFirst("val%s".formatted(i)); + } + for (int i = 1; i < 12; i++) { + deque.removeLast(); + } + + headValue = ReflectionUtils.getFieldValue(deque, head); + tailValue = ReflectionUtils.getFieldValue(deque, tail); + + // then: + assertEquals(30, headValue); + assertEquals(35, tailValue); + assertEquals(6, deque.size()); + } + + private static Stream generateDeque() { + return Stream.of( + Arguments.of(DequeFactory.linkedListBased()), + Arguments.of(DequeFactory.arrayBasedBased(String.class, 15))); + } +} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/ArrayUtils.java b/rlib-common/src/main/java/javasabr/rlib/common/util/ArrayUtils.java index f5aba019..3fac5b6d 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/ArrayUtils.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/ArrayUtils.java @@ -44,6 +44,11 @@ public final class ArrayUtils { public static final long[] EMPTY_LONG_ARRAY = new long[0]; public static final char[] EMPTY_CHAR_ARRAY = new char[0]; + @SafeVarargs + public static T[] array(T... elements) { + return elements; + } + /** * Convert an object integer array to primitive int array. * @@ -856,17 +861,18 @@ public static String toString(Object @Nullable [] array) { return toString(array, ", ", true, true); } - /** - * Convert the array to a string presentation. - * - * @param array the array. - * @param separator the separator. - * @param needType true if need adding type of array. - * @param needBrackets true if need adding brackets. - * @return the string presentation of the array. - */ public static String toString( - Object @Nullable [] array, + @Nullable Object @Nullable [] array, + String separator, + boolean needType, + boolean needBrackets) { + return toString(array, 0, array == null ? 0 : array.length, separator, needType, needBrackets); + } + + public static String toString( + @Nullable Object @Nullable [] array, + int start, + int length, String separator, boolean needType, boolean needBrackets) { @@ -886,9 +892,9 @@ public static String toString( builder.append('['); } - for (int i = 0, length = array.length - 1; i <= length; i++) { - builder.append(String.valueOf(array[i])); - if (i == length) { + for (int i = start, limit = start + length - 1; i <= limit; i++) { + builder.append(array[i]); + if (i == limit) { break; } builder.append(separator); From dac6d4754530c6cdd06c8dd6796644bc135e30e3 Mon Sep 17 00:00:00 2001 From: javasabr Date: Sun, 14 Sep 2025 20:01:44 +0200 Subject: [PATCH 2/4] finished implementing array based deque --- .../deque/impl/AbstractArrayBasedDeque.java | 12 ++--- .../ArrayBasedDequeDescendingIterator.java | 34 ++++++++++++++ .../deque/impl/ArrayBasedDequeIterator.java | 33 +++++++++++++ .../rlib/collections/array/DequeTest.java | 47 ++++++++++++++++++- 4 files changed, 119 insertions(+), 7 deletions(-) create mode 100644 rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/ArrayBasedDequeDescendingIterator.java create mode 100644 rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/ArrayBasedDequeIterator.java diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/AbstractArrayBasedDeque.java b/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/AbstractArrayBasedDeque.java index a1f6e232..96984cfc 100644 --- a/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/AbstractArrayBasedDeque.java +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/AbstractArrayBasedDeque.java @@ -444,7 +444,12 @@ public boolean isEmpty() { @Override public Iterator iterator() { - return null; + return new ArrayBasedDequeIterator<>(this); + } + + @Override + public Iterator descendingIterator() { + return new ArrayBasedDequeDescendingIterator<>(this); } @Override @@ -485,11 +490,6 @@ public T[] toArray(T[] container) { return container; } - @Override - public Iterator descendingIterator() { - return null; - } - @Override public String toString() { return ArrayUtils.toString(items(), head(), size(), ", ", false, true); diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/ArrayBasedDequeDescendingIterator.java b/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/ArrayBasedDequeDescendingIterator.java new file mode 100644 index 00000000..8cc75b34 --- /dev/null +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/ArrayBasedDequeDescendingIterator.java @@ -0,0 +1,34 @@ +package javasabr.rlib.collections.deque.impl; + +import java.util.Iterator; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; + +@FieldDefaults(level = AccessLevel.PROTECTED) +public class ArrayBasedDequeDescendingIterator implements Iterator { + + final AbstractArrayBasedDeque deque; + int iterated; + + public ArrayBasedDequeDescendingIterator(AbstractArrayBasedDeque deque) { + this.deque = deque; + } + + @Override + public boolean hasNext() { + return iterated < deque.size(); + } + + @Override + public E next() { + int index = deque.tail() - iterated++; + return deque.items()[index]; + } + + @Override + public void remove() { + int index = deque.tail() - --iterated; + deque.remove(deque.items()[index]); + } +} + diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/ArrayBasedDequeIterator.java b/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/ArrayBasedDequeIterator.java new file mode 100644 index 00000000..894cda52 --- /dev/null +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/ArrayBasedDequeIterator.java @@ -0,0 +1,33 @@ +package javasabr.rlib.collections.deque.impl; + +import java.util.Iterator; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; + +@FieldDefaults(level = AccessLevel.PROTECTED) +public class ArrayBasedDequeIterator implements Iterator { + + final AbstractArrayBasedDeque deque; + int iterated; + + public ArrayBasedDequeIterator(AbstractArrayBasedDeque deque) { + this.deque = deque; + } + + @Override + public boolean hasNext() { + return iterated < deque.size(); + } + + @Override + public E next() { + int index = deque.head() + iterated++; + return deque.items()[index]; + } + + @Override + public void remove() { + int index = deque.head() + --iterated; + deque.remove(deque.items()[index]); + } +} diff --git a/rlib-collections/src/test/java/javasabr/rlib/collections/array/DequeTest.java b/rlib-collections/src/test/java/javasabr/rlib/collections/array/DequeTest.java index 4278f1ee..756d4dba 100644 --- a/rlib-collections/src/test/java/javasabr/rlib/collections/array/DequeTest.java +++ b/rlib-collections/src/test/java/javasabr/rlib/collections/array/DequeTest.java @@ -8,6 +8,7 @@ import java.lang.reflect.Field; import java.util.Deque; +import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.stream.Stream; @@ -536,9 +537,53 @@ void shouldRebalanceIndexesAddFirstRemoveLast() { assertEquals(6, deque.size()); } + @ParameterizedTest + @MethodSource("generateDeque") + void shouldCorrectlyIterateDeque(Deque deque) { + + // given: + deque.addAll(List.of("val1", "val2", "val3", "val4", "val5", "val6")); + var container = MutableArray.ofType(String.class); + + // when: + for (Iterator iterator = deque.iterator(); iterator.hasNext(); ) { + String value = iterator.next(); + container.add(value); + if (value.equals("val2") || value.equals("val4")) { + iterator.remove(); + } + } + + // then: + assertArrayEquals(container.toArray(), array("val1", "val2", "val3", "val4", "val5", "val6")); + assertArrayEquals(deque.toArray(), array("val1", "val3", "val5", "val6")); + } + + @ParameterizedTest + @MethodSource("generateDeque") + void shouldCorrectlyIterate2Deque(Deque deque) { + + // given: + deque.addAll(List.of("val1", "val2", "val3", "val4", "val5", "val6")); + var container = MutableArray.ofType(String.class); + + // when: + for (Iterator iterator = deque.descendingIterator(); iterator.hasNext(); ) { + String value = iterator.next(); + container.add(value); + if (value.equals("val2") || value.equals("val4")) { + iterator.remove(); + } + } + + // then: + assertArrayEquals(container.toArray(), array("val6", "val5", "val4", "val3", "val2", "val1")); + assertArrayEquals(deque.toArray(), array("val1", "val3", "val5", "val6")); + } + private static Stream generateDeque() { return Stream.of( - Arguments.of(DequeFactory.linkedListBased()), + //Arguments.of(DequeFactory.linkedListBased()), Arguments.of(DequeFactory.arrayBasedBased(String.class, 15))); } } From 656ff2ff5f84d5af022145a31e4bfc15b15c29da Mon Sep 17 00:00:00 2001 From: javasabr Date: Sun, 14 Sep 2025 21:02:11 +0200 Subject: [PATCH 3/4] implement primitive arrays --- .../rlib/collections/array/ArrayFactory.java | 11 + .../rlib/collections/array/IntArray.java | 69 ++++ .../rlib/collections/array/LongArray.java | 69 ++++ .../collections/array/MutableIntArray.java | 24 ++ .../collections/array/MutableLongArray.java | 24 ++ .../collections/array/UnsafeIntArray.java | 6 + .../collections/array/UnsafeLongArray.java | 6 + .../array/UnsafeMutableIntArray.java | 14 + .../array/UnsafeMutableLongArray.java | 14 + .../array/impl/AbstractIntArray.java | 143 ++++++++ .../array/impl/AbstractLongArray.java | 143 ++++++++ .../array/impl/AbstractMutableIntArray.java | 167 +++++++++ .../array/impl/AbstractMutableLongArray.java | 167 +++++++++ .../array/impl/DefaultIntArrayIterator.java | 42 +++ .../array/impl/DefaultLongArrayIterator.java | 42 +++ .../array/impl/DefaultMutableArray.java | 6 +- .../array/impl/DefaultMutableIntArray.java | 43 +++ .../array/impl/DefaultMutableLongArray.java | 43 +++ .../array/impl/ImmutableIntArray.java | 50 +++ .../array/impl/ImmutableLongArray.java | 50 +++ .../javasabr/rlib/common/util/ArrayUtils.java | 54 --- .../rlib/common/util/array/ArrayFactory.java | 22 -- .../util/array/ConcurrentIntegerArray.java | 24 -- .../rlib/common/util/array/IntegerArray.java | 214 ----------- .../rlib/common/util/array/LongArray.java | 345 ------------------ .../util/array/MutableIntegerArray.java | 164 --------- .../util/array/impl/DefaultIntegerArray.java | 257 ------------- .../common/util/array/impl/FastLongArray.java | 271 -------------- .../util/array/impl/ReadOnlyIntegerArray.java | 113 ------ .../dictionary/AbstractIntegerDictionary.java | 15 - .../dictionary/AbstractLongDictionary.java | 14 - .../util/dictionary/IntegerDictionary.java | 21 -- .../util/dictionary/LongDictionary.java | 20 - 33 files changed, 1128 insertions(+), 1539 deletions(-) create mode 100644 rlib-collections/src/main/java/javasabr/rlib/collections/array/IntArray.java create mode 100644 rlib-collections/src/main/java/javasabr/rlib/collections/array/LongArray.java create mode 100644 rlib-collections/src/main/java/javasabr/rlib/collections/array/MutableIntArray.java create mode 100644 rlib-collections/src/main/java/javasabr/rlib/collections/array/MutableLongArray.java create mode 100644 rlib-collections/src/main/java/javasabr/rlib/collections/array/UnsafeIntArray.java create mode 100644 rlib-collections/src/main/java/javasabr/rlib/collections/array/UnsafeLongArray.java create mode 100644 rlib-collections/src/main/java/javasabr/rlib/collections/array/UnsafeMutableIntArray.java create mode 100644 rlib-collections/src/main/java/javasabr/rlib/collections/array/UnsafeMutableLongArray.java create mode 100644 rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/AbstractIntArray.java create mode 100644 rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/AbstractLongArray.java create mode 100644 rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/AbstractMutableIntArray.java create mode 100644 rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/AbstractMutableLongArray.java create mode 100644 rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/DefaultIntArrayIterator.java create mode 100644 rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/DefaultLongArrayIterator.java create mode 100644 rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/DefaultMutableIntArray.java create mode 100644 rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/DefaultMutableLongArray.java create mode 100644 rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/ImmutableIntArray.java create mode 100644 rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/ImmutableLongArray.java delete mode 100644 rlib-common/src/main/java/javasabr/rlib/common/util/array/ConcurrentIntegerArray.java delete mode 100644 rlib-common/src/main/java/javasabr/rlib/common/util/array/IntegerArray.java delete mode 100644 rlib-common/src/main/java/javasabr/rlib/common/util/array/LongArray.java delete mode 100644 rlib-common/src/main/java/javasabr/rlib/common/util/array/MutableIntegerArray.java delete mode 100644 rlib-common/src/main/java/javasabr/rlib/common/util/array/impl/DefaultIntegerArray.java delete mode 100644 rlib-common/src/main/java/javasabr/rlib/common/util/array/impl/FastLongArray.java delete mode 100644 rlib-common/src/main/java/javasabr/rlib/common/util/array/impl/ReadOnlyIntegerArray.java diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/array/ArrayFactory.java b/rlib-collections/src/main/java/javasabr/rlib/collections/array/ArrayFactory.java index cf6ae064..1960983f 100644 --- a/rlib-collections/src/main/java/javasabr/rlib/collections/array/ArrayFactory.java +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/array/ArrayFactory.java @@ -2,6 +2,8 @@ import javasabr.rlib.collections.array.impl.CopyOnWriteMutableArray; import javasabr.rlib.collections.array.impl.DefaultMutableArray; +import javasabr.rlib.collections.array.impl.DefaultMutableIntArray; +import javasabr.rlib.collections.array.impl.DefaultMutableLongArray; import javasabr.rlib.collections.array.impl.StampedLockBasedArray; import javasabr.rlib.common.util.ClassUtils; import lombok.experimental.UtilityClass; @@ -13,10 +15,19 @@ public static MutableArray mutableArray(Class type) { return new DefaultMutableArray<>(ClassUtils.unsafeCast(type)); } + public static MutableIntArray mutableIntArray() { + return new DefaultMutableIntArray(); + } + + public static MutableLongArray mutableLongArray() { + return new DefaultMutableLongArray(); + } + public static MutableArray mutableArray(Class type, int capacity) { return new DefaultMutableArray<>(ClassUtils.unsafeCast(type), capacity); } + public static MutableArray copyOnModifyArray(Class type) { return new CopyOnWriteMutableArray<>(type); } diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/array/IntArray.java b/rlib-collections/src/main/java/javasabr/rlib/collections/array/IntArray.java new file mode 100644 index 00000000..7fdbeddf --- /dev/null +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/array/IntArray.java @@ -0,0 +1,69 @@ +package javasabr.rlib.collections.array; + +import java.io.Serializable; +import java.util.RandomAccess; +import java.util.stream.IntStream; +import javasabr.rlib.collections.array.impl.ImmutableIntArray; + +/** + * @author JavaSaBr + */ +public interface IntArray extends Iterable, Serializable, Cloneable, RandomAccess { + + static IntArray empty() { + return new ImmutableIntArray(); + } + + static IntArray of(int e1) { + return new ImmutableIntArray(e1); + } + + static IntArray of(int e1, int e2) { + return new ImmutableIntArray(e1, e2); + } + + static IntArray of(int e1, int e2, int e3) { + return new ImmutableIntArray(e1, e2, e3); + } + + static IntArray of(int e1, int e2, int e3, int e4) { + return new ImmutableIntArray(e1, e2, e3, e4); + } + + static IntArray of(int... elements) { + return new ImmutableIntArray(elements); + } + + int size(); + + boolean contains(int value); + + boolean containsAll(IntArray array); + + /** + * @return the first element or {@link java.util.NoSuchElementException} + */ + int first(); + + int get(int index); + + /** + * @return the last element or {@link java.util.NoSuchElementException} + */ + int last(); + + /** + * @return the index of the value or -1. + */ + int indexOf(int value); + + int lastIndexOf(int value); + + boolean isEmpty(); + + int[] toArray(); + + IntStream stream(); + + UnsafeIntArray asUnsafe(); +} diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/array/LongArray.java b/rlib-collections/src/main/java/javasabr/rlib/collections/array/LongArray.java new file mode 100644 index 00000000..0b6a8e36 --- /dev/null +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/array/LongArray.java @@ -0,0 +1,69 @@ +package javasabr.rlib.collections.array; + +import java.io.Serializable; +import java.util.RandomAccess; +import java.util.stream.LongStream; +import javasabr.rlib.collections.array.impl.ImmutableLongArray; + +/** + * @author JavaSaBr + */ +public interface LongArray extends Iterable, Serializable, Cloneable, RandomAccess { + + static LongArray empty() { + return new ImmutableLongArray(); + } + + static LongArray of(long e1) { + return new ImmutableLongArray(e1); + } + + static LongArray of(long e1, long e2) { + return new ImmutableLongArray(e1, e2); + } + + static LongArray of(long e1, long e2, long e3) { + return new ImmutableLongArray(e1, e2, e3); + } + + static LongArray of(long e1, long e2, long e3, long e4) { + return new ImmutableLongArray(e1, e2, e3, e4); + } + + static LongArray of(long... elements) { + return new ImmutableLongArray(elements); + } + + int size(); + + boolean contains(long value); + + boolean containsAll(LongArray array); + + /** + * @return the first element or {@link java.util.NoSuchElementException} + */ + long first(); + + long get(int index); + + /** + * @return the last element or {@link java.util.NoSuchElementException} + */ + long last(); + + /** + * @return the index of the value or -1. + */ + int indexOf(long value); + + int lastIndexOf(long value); + + boolean isEmpty(); + + long[] toArray(); + + LongStream stream(); + + UnsafeLongArray asUnsafe(); +} diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/array/MutableIntArray.java b/rlib-collections/src/main/java/javasabr/rlib/collections/array/MutableIntArray.java new file mode 100644 index 00000000..d340c4bb --- /dev/null +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/array/MutableIntArray.java @@ -0,0 +1,24 @@ +package javasabr.rlib.collections.array; + +public interface MutableIntArray extends IntArray { + + boolean add(int value); + + boolean addAll(IntArray array); + + boolean addAll(int[] array); + + /** + * @return the element previously at the specified position + */ + int removeByInex(int index); + + boolean remove(int value); + + void replace(int index, int value); + + void clear(); + + @Override + UnsafeMutableIntArray asUnsafe(); +} diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/array/MutableLongArray.java b/rlib-collections/src/main/java/javasabr/rlib/collections/array/MutableLongArray.java new file mode 100644 index 00000000..fb71df23 --- /dev/null +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/array/MutableLongArray.java @@ -0,0 +1,24 @@ +package javasabr.rlib.collections.array; + +public interface MutableLongArray extends LongArray { + + boolean add(long value); + + boolean addAll(LongArray array); + + boolean addAll(long[] array); + + /** + * @return the element previously at the specified position + */ + long removeByInex(int index); + + boolean remove(long value); + + void replace(int index, long value); + + void clear(); + + @Override + UnsafeMutableLongArray asUnsafe(); +} diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/array/UnsafeIntArray.java b/rlib-collections/src/main/java/javasabr/rlib/collections/array/UnsafeIntArray.java new file mode 100644 index 00000000..d456511c --- /dev/null +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/array/UnsafeIntArray.java @@ -0,0 +1,6 @@ +package javasabr.rlib.collections.array; + +public interface UnsafeIntArray extends IntArray { + int[] wrapped(); + int unsafeGet(int index); +} diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/array/UnsafeLongArray.java b/rlib-collections/src/main/java/javasabr/rlib/collections/array/UnsafeLongArray.java new file mode 100644 index 00000000..35668235 --- /dev/null +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/array/UnsafeLongArray.java @@ -0,0 +1,6 @@ +package javasabr.rlib.collections.array; + +public interface UnsafeLongArray extends LongArray { + long[] wrapped(); + long unsafeGet(int index); +} diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/array/UnsafeMutableIntArray.java b/rlib-collections/src/main/java/javasabr/rlib/collections/array/UnsafeMutableIntArray.java new file mode 100644 index 00000000..0274df9e --- /dev/null +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/array/UnsafeMutableIntArray.java @@ -0,0 +1,14 @@ +package javasabr.rlib.collections.array; + +public interface UnsafeMutableIntArray extends UnsafeIntArray, MutableIntArray { + + UnsafeMutableIntArray prepareForSize(int expectedSize); + + UnsafeMutableIntArray unsafeAdd(int value); + + int unsafeRemoveByInex(int index); + + UnsafeMutableIntArray unsafeSet(int index, int value); + + UnsafeMutableIntArray trimToSize(); +} diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/array/UnsafeMutableLongArray.java b/rlib-collections/src/main/java/javasabr/rlib/collections/array/UnsafeMutableLongArray.java new file mode 100644 index 00000000..a78f81d0 --- /dev/null +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/array/UnsafeMutableLongArray.java @@ -0,0 +1,14 @@ +package javasabr.rlib.collections.array; + +public interface UnsafeMutableLongArray extends UnsafeLongArray, MutableLongArray { + + UnsafeMutableLongArray prepareForSize(int expectedSize); + + UnsafeMutableLongArray unsafeAdd(long value); + + long unsafeRemoveByInex(int index); + + UnsafeMutableLongArray unsafeSet(int index, long value); + + UnsafeMutableLongArray trimToSize(); +} diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/AbstractIntArray.java b/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/AbstractIntArray.java new file mode 100644 index 00000000..ffe1fdc8 --- /dev/null +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/AbstractIntArray.java @@ -0,0 +1,143 @@ +package javasabr.rlib.collections.array.impl; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.NoSuchElementException; +import javasabr.rlib.collections.array.IntArray; +import javasabr.rlib.collections.array.UnsafeIntArray; +import lombok.AccessLevel; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; + +@Accessors(fluent = true) +@FieldDefaults(level = AccessLevel.PROTECTED) +public abstract class AbstractIntArray implements UnsafeIntArray { + + @Override + public int first() { + if (isEmpty()) { + throw new NoSuchElementException(); + } + return unsafeGet(0); + } + + @Override + public int last() { + if (isEmpty()) { + throw new NoSuchElementException(); + } + return unsafeGet(size() - 1); + } + + @Override + public int get(int index) { + checkIndex(index); + return unsafeGet(index); + } + + @Override + public int unsafeGet(int index) { + return wrapped()[index]; + } + + protected void checkIndex(int index) { + if (index < 0 || index >= size()) { + throw new ArrayIndexOutOfBoundsException(); + } + } + + @Override + public boolean contains(int value) { + int[] wrapped = wrapped(); + for (int i = 0, length = size(); i < length; i++) { + if (value == wrapped[i]) { + return true; + } + } + return false; + } + + @Override + public boolean containsAll(IntArray array) { + if (array.isEmpty()) { + return false; + } + + int[] wrapped = array + .asUnsafe() + .wrapped(); + + for (int i = 0, length = array.size(); i < length; i++) { + if (!contains(wrapped[i])) { + return false; + } + } + + return true; + } + + @Override + public int indexOf(int value) { + int[] wrapped = wrapped(); + for (int i = 0, length = size(); i < length; i++) { + if (value == wrapped[i]) { + return i; + } + } + return -1; + } + + @Override + public int lastIndexOf(int value) { + int[] wrapped = wrapped(); + for (int i = size() - 1; i >= 0; i--) { + if (value == wrapped[i]) { + return i; + } + } + return -1; + } + + @Override + public Iterator iterator() { + return new DefaultIntArrayIterator(this); + } + + @Override + public int[] toArray() { + return Arrays.copyOf(wrapped(), size()); + } + + @Override + public boolean equals(Object another) { + + if (!(another instanceof IntArray array)) { + return false; + } + + int[] wrapped = array + .asUnsafe() + .wrapped(); + + return Arrays.equals(wrapped(), 0, size(), wrapped, 0, array.size()); + } + + @Override + public int hashCode() { + + int[] wrapped = wrapped(); + + int result = 1; + + for (int i = 0, wrappedLength = size(); i < wrappedLength; i++) { + result = 31 * result + wrapped[i]; + } + + return result; + } + + @Override + public UnsafeIntArray asUnsafe() { + return this; + } +} diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/AbstractLongArray.java b/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/AbstractLongArray.java new file mode 100644 index 00000000..0c419f31 --- /dev/null +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/AbstractLongArray.java @@ -0,0 +1,143 @@ +package javasabr.rlib.collections.array.impl; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.NoSuchElementException; +import javasabr.rlib.collections.array.LongArray; +import javasabr.rlib.collections.array.UnsafeLongArray; +import lombok.AccessLevel; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; + +@Accessors(fluent = true) +@FieldDefaults(level = AccessLevel.PROTECTED) +public abstract class AbstractLongArray implements UnsafeLongArray { + + @Override + public long first() { + if (isEmpty()) { + throw new NoSuchElementException(); + } + return unsafeGet(0); + } + + @Override + public long last() { + if (isEmpty()) { + throw new NoSuchElementException(); + } + return unsafeGet(size() - 1); + } + + @Override + public long get(int index) { + checkIndex(index); + return unsafeGet(index); + } + + @Override + public long unsafeGet(int index) { + return wrapped()[index]; + } + + protected void checkIndex(int index) { + if (index < 0 || index >= size()) { + throw new ArrayIndexOutOfBoundsException(); + } + } + + @Override + public boolean contains(long value) { + long[] wrapped = wrapped(); + for (int i = 0, length = size(); i < length; i++) { + if (value == wrapped[i]) { + return true; + } + } + return false; + } + + @Override + public boolean containsAll(LongArray array) { + if (array.isEmpty()) { + return false; + } + + long[] wrapped = array + .asUnsafe() + .wrapped(); + + for (int i = 0, length = array.size(); i < length; i++) { + if (!contains(wrapped[i])) { + return false; + } + } + + return true; + } + + @Override + public int indexOf(long value) { + long[] wrapped = wrapped(); + for (int i = 0, length = size(); i < length; i++) { + if (value == wrapped[i]) { + return i; + } + } + return -1; + } + + @Override + public int lastIndexOf(long value) { + long[] wrapped = wrapped(); + for (int i = size() - 1; i >= 0; i--) { + if (value == wrapped[i]) { + return i; + } + } + return -1; + } + + @Override + public Iterator iterator() { + return new DefaultLongArrayIterator(this); + } + + @Override + public long[] toArray() { + return Arrays.copyOf(wrapped(), size()); + } + + @Override + public boolean equals(Object another) { + + if (!(another instanceof LongArray array)) { + return false; + } + + long[] wrapped = array + .asUnsafe() + .wrapped(); + + return Arrays.equals(wrapped(), 0, size(), wrapped, 0, array.size()); + } + + @Override + public int hashCode() { + + long[] wrapped = wrapped(); + + int result = 1; + + for (int i = 0, wrappedLength = size(); i < wrappedLength; i++) { + result = 31 * result + Long.hashCode(wrapped[i]); + } + + return result; + } + + @Override + public UnsafeLongArray asUnsafe() { + return this; + } +} diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/AbstractMutableIntArray.java b/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/AbstractMutableIntArray.java new file mode 100644 index 00000000..ad3f7f8a --- /dev/null +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/AbstractMutableIntArray.java @@ -0,0 +1,167 @@ +package javasabr.rlib.collections.array.impl; + +import java.util.Arrays; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.stream.IntStream; +import java.util.stream.StreamSupport; +import javasabr.rlib.collections.array.IntArray; +import javasabr.rlib.collections.array.UnsafeMutableIntArray; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; + +@FieldDefaults(level = AccessLevel.PROTECTED) +public abstract class AbstractMutableIntArray extends AbstractIntArray implements UnsafeMutableIntArray { + + @Override + public boolean add(int value) { + prepareForSize(size() + 1); + unsafeAdd(value); + return true; + } + + @Override + public boolean addAll(IntArray array) { + if (array.isEmpty()) { + return false; + } + int size = size(); + int elementsToAdd = array.size(); + prepareForSize(size + elementsToAdd); + processAdd(array, size, elementsToAdd); + return true; + } + + @Override + public boolean addAll(int[] array) { + if (array.length < 1) { + return false; + } + int size = size(); + int elementsToAdd = array.length; + prepareForSize(size + elementsToAdd); + processAdd(array, size, elementsToAdd); + return true; + } + + + @Override + public UnsafeMutableIntArray unsafeAdd(int value) { + wrapped()[getAndIncrementSize()] = value; + return this; + } + + @Override + public void replace(int index, int value) { + checkIndex(index); + unsafeSet(index, value); + } + + @Override + public UnsafeMutableIntArray unsafeSet(int index, int value) { + wrapped()[index] = value; + return this; + } + + @Override + public int removeByInex(int index) { + checkIndex(index); + return unsafeRemoveByInex(index); + } + + @Override + public boolean remove(int value) { + int index = indexOf(value); + if (index < 0) { + return false; + } + remove(index); + return true; + } + + @Override + public int unsafeRemoveByInex(int index) { + + int numMoved = size() - index - 1; + + int[] wrapped = wrapped(); + int value = wrapped[index]; + + if (numMoved > 0) { + System.arraycopy(wrapped, index + 1, wrapped, index, numMoved); + } + + wrapped[decrementAnGetSize()] = 0; + + return value; + } + + @Override + public void clear() { + int size = size(); + if (size > 0) { + Arrays.fill(wrapped(), 0, size, 0); + size(0); + } + } + + @Override + public IntStream stream() { + return StreamSupport.intStream(spliterator(), false); + } + + @Override + public Spliterator.OfInt spliterator() { + return Spliterators.spliterator(wrapped(), 0, size(), Spliterator.NONNULL); + } + + protected void processAdd(IntArray array, int currentSize, int elementsToAdd) { + System.arraycopy(array.asUnsafe().wrapped(), 0, wrapped(), currentSize, elementsToAdd); + size(currentSize + elementsToAdd); + } + + protected void processAdd(int[] array, int currentSize, int elementsToAdd) { + System.arraycopy(array, 0, wrapped(), currentSize, elementsToAdd); + size(currentSize + elementsToAdd); + } + + protected abstract void size(int size); + + protected abstract int getAndIncrementSize(); + protected abstract int decrementAnGetSize(); + + protected abstract void wrapped(int[] wrapped); + + @Override + public UnsafeMutableIntArray prepareForSize(int expectedSize) { + int[] wrapped = wrapped(); + if (expectedSize > wrapped.length) { + int newLength = Math.max((wrapped.length * 3) / 2, expectedSize); + wrapped(Arrays.copyOf(wrapped, newLength)); + } + return this; + } + + + @Override + public UnsafeMutableIntArray trimToSize() { + int[] wrapped = wrapped(); + int size = size(); + if (size == wrapped.length) { + return this; + } + wrapped(Arrays.copyOfRange(wrapped, 0, size)); + return this; + } + + @Override + public UnsafeMutableIntArray asUnsafe() { + return this; + } + + protected static void validateCapacity(int capacity) { + if (capacity < 0) { + throw new IllegalArgumentException("Capacity cannot be negative"); + } + } +} diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/AbstractMutableLongArray.java b/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/AbstractMutableLongArray.java new file mode 100644 index 00000000..85587c8c --- /dev/null +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/AbstractMutableLongArray.java @@ -0,0 +1,167 @@ +package javasabr.rlib.collections.array.impl; + +import java.util.Arrays; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.stream.LongStream; +import java.util.stream.StreamSupport; +import javasabr.rlib.collections.array.LongArray; +import javasabr.rlib.collections.array.UnsafeMutableLongArray; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; + +@FieldDefaults(level = AccessLevel.PROTECTED) +public abstract class AbstractMutableLongArray extends AbstractLongArray implements UnsafeMutableLongArray { + + @Override + public boolean add(long value) { + prepareForSize(size() + 1); + unsafeAdd(value); + return true; + } + + @Override + public boolean addAll(LongArray array) { + if (array.isEmpty()) { + return false; + } + int size = size(); + int elementsToAdd = array.size(); + prepareForSize(size + elementsToAdd); + processAdd(array, size, elementsToAdd); + return true; + } + + @Override + public boolean addAll(long[] array) { + if (array.length < 1) { + return false; + } + int size = size(); + int elementsToAdd = array.length; + prepareForSize(size + elementsToAdd); + processAdd(array, size, elementsToAdd); + return true; + } + + + @Override + public UnsafeMutableLongArray unsafeAdd(long value) { + wrapped()[getAndIncrementSize()] = value; + return this; + } + + @Override + public void replace(int index, long value) { + checkIndex(index); + unsafeSet(index, value); + } + + @Override + public UnsafeMutableLongArray unsafeSet(int index, long value) { + wrapped()[index] = value; + return this; + } + + @Override + public long removeByInex(int index) { + checkIndex(index); + return unsafeRemoveByInex(index); + } + + @Override + public boolean remove(long value) { + int index = indexOf(value); + if (index < 0) { + return false; + } + remove(index); + return true; + } + + @Override + public long unsafeRemoveByInex(int index) { + + int numMoved = size() - index - 1; + + long[] wrapped = wrapped(); + long value = wrapped[index]; + + if (numMoved > 0) { + System.arraycopy(wrapped, index + 1, wrapped, index, numMoved); + } + + wrapped[decrementAnGetSize()] = 0; + + return value; + } + + @Override + public void clear() { + int size = size(); + if (size > 0) { + Arrays.fill(wrapped(), 0, size, 0); + size(0); + } + } + + @Override + public LongStream stream() { + return StreamSupport.longStream(spliterator(), false); + } + + @Override + public Spliterator.OfLong spliterator() { + return Spliterators.spliterator(wrapped(), 0, size(), Spliterator.NONNULL); + } + + protected void processAdd(LongArray array, int currentSize, int elementsToAdd) { + System.arraycopy(array.asUnsafe().wrapped(), 0, wrapped(), currentSize, elementsToAdd); + size(currentSize + elementsToAdd); + } + + protected void processAdd(long[] array, int currentSize, int elementsToAdd) { + System.arraycopy(array, 0, wrapped(), currentSize, elementsToAdd); + size(currentSize + elementsToAdd); + } + + protected abstract void size(int size); + + protected abstract int getAndIncrementSize(); + protected abstract int decrementAnGetSize(); + + protected abstract void wrapped(long[] wrapped); + + @Override + public UnsafeMutableLongArray prepareForSize(int expectedSize) { + long[] wrapped = wrapped(); + if (expectedSize > wrapped.length) { + int newLength = Math.max((wrapped.length * 3) / 2, expectedSize); + wrapped(Arrays.copyOf(wrapped, newLength)); + } + return this; + } + + + @Override + public UnsafeMutableLongArray trimToSize() { + long[] wrapped = wrapped(); + int size = size(); + if (size == wrapped.length) { + return this; + } + wrapped(Arrays.copyOfRange(wrapped, 0, size)); + return this; + } + + @Override + public UnsafeMutableLongArray asUnsafe() { + return this; + } + + protected static void validateCapacity(int capacity) { + if (capacity < 0) { + throw new IllegalArgumentException("Capacity cannot be negative"); + } + } +} diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/DefaultIntArrayIterator.java b/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/DefaultIntArrayIterator.java new file mode 100644 index 00000000..947cf953 --- /dev/null +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/DefaultIntArrayIterator.java @@ -0,0 +1,42 @@ +package javasabr.rlib.collections.array.impl; + +import java.util.Iterator; +import java.util.NoSuchElementException; +import javasabr.rlib.collections.array.IntArray; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; + +/** + * @author JavaSaBr + */ +@FieldDefaults(level = AccessLevel.PROTECTED) +public class DefaultIntArrayIterator implements Iterator { + + final int[] wrapped; + final int size; + + int position; + + public DefaultIntArrayIterator(IntArray array) { + this.wrapped = array.asUnsafe().wrapped(); + this.size = array.size(); + } + + @Override + public boolean hasNext() { + return position < size; + } + + @Override + public Integer next() { + if (position >= size) { + throw new NoSuchElementException(); + } + return wrapped[position++]; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } +} diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/DefaultLongArrayIterator.java b/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/DefaultLongArrayIterator.java new file mode 100644 index 00000000..5b69b67a --- /dev/null +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/DefaultLongArrayIterator.java @@ -0,0 +1,42 @@ +package javasabr.rlib.collections.array.impl; + +import java.util.Iterator; +import java.util.NoSuchElementException; +import javasabr.rlib.collections.array.LongArray; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; + +/** + * @author JavaSaBr + */ +@FieldDefaults(level = AccessLevel.PROTECTED) +public class DefaultLongArrayIterator implements Iterator { + + final long[] wrapped; + final int size; + + int position; + + public DefaultLongArrayIterator(LongArray array) { + this.wrapped = array.asUnsafe().wrapped(); + this.size = array.size(); + } + + @Override + public boolean hasNext() { + return position < size; + } + + @Override + public Long next() { + if (position >= size) { + throw new NoSuchElementException(); + } + return wrapped[position++]; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } +} diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/DefaultMutableArray.java b/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/DefaultMutableArray.java index 6e11b68a..797b36f3 100644 --- a/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/DefaultMutableArray.java +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/DefaultMutableArray.java @@ -16,11 +16,7 @@ public class DefaultMutableArray extends AbstractMutableArray { protected static final int DEFAULT_CAPACITY = 10; - /* - It's initialized during object construction by setter #wrapped - */ - @Nullable - E[] wrapped; + @Nullable E[] wrapped; int size; public DefaultMutableArray(Class type) { diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/DefaultMutableIntArray.java b/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/DefaultMutableIntArray.java new file mode 100644 index 00000000..c7458c4e --- /dev/null +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/DefaultMutableIntArray.java @@ -0,0 +1,43 @@ +package javasabr.rlib.collections.array.impl; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; + +@Getter +@Setter(AccessLevel.PROTECTED) +@Accessors(fluent = true, chain = false) +@FieldDefaults(level = AccessLevel.PROTECTED) +public class DefaultMutableIntArray extends AbstractMutableIntArray { + + protected static final int DEFAULT_CAPACITY = 10; + + int[] wrapped; + int size; + + public DefaultMutableIntArray() { + this(DEFAULT_CAPACITY); + } + + public DefaultMutableIntArray(int capacity) { + validateCapacity(capacity); + this.wrapped = new int[capacity]; + } + + @Override + public boolean isEmpty() { + return size < 1; + } + + @Override + protected int getAndIncrementSize() { + return size++; + } + + @Override + protected int decrementAnGetSize() { + return --size; + } +} diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/DefaultMutableLongArray.java b/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/DefaultMutableLongArray.java new file mode 100644 index 00000000..50a55568 --- /dev/null +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/DefaultMutableLongArray.java @@ -0,0 +1,43 @@ +package javasabr.rlib.collections.array.impl; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; + +@Getter +@Setter(AccessLevel.PROTECTED) +@Accessors(fluent = true, chain = false) +@FieldDefaults(level = AccessLevel.PROTECTED) +public class DefaultMutableLongArray extends AbstractMutableLongArray { + + protected static final int DEFAULT_CAPACITY = 10; + + long[] wrapped; + int size; + + public DefaultMutableLongArray() { + this(DEFAULT_CAPACITY); + } + + public DefaultMutableLongArray(int capacity) { + validateCapacity(capacity); + this.wrapped = new long[capacity]; + } + + @Override + public boolean isEmpty() { + return size < 1; + } + + @Override + protected int getAndIncrementSize() { + return size++; + } + + @Override + protected int decrementAnGetSize() { + return --size; + } +} diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/ImmutableIntArray.java b/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/ImmutableIntArray.java new file mode 100644 index 00000000..c9aaf6ef --- /dev/null +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/ImmutableIntArray.java @@ -0,0 +1,50 @@ +package javasabr.rlib.collections.array.impl; + +import java.util.stream.IntStream; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; + +@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) +public class ImmutableIntArray extends AbstractIntArray { + + int[] wrapped; + + public ImmutableIntArray(int... elements) { + this.wrapped = elements; + } + + @Override + public int unsafeGet(int index) { + return wrapped[index]; + } + + @Override + public IntStream stream() { + return IntStream.of(wrapped); + } + + @Override + public int size() { + return wrapped.length; + } + + @Override + public boolean isEmpty() { + return wrapped.length < 1; + } + + @Override + public int get(int index) { + + if (index < 0 || index >= size()) { + throw new IndexOutOfBoundsException(); + } + + return wrapped[index]; + } + + @Override + public int[] wrapped() { + return wrapped; + } +} diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/ImmutableLongArray.java b/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/ImmutableLongArray.java new file mode 100644 index 00000000..f4efafef --- /dev/null +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/array/impl/ImmutableLongArray.java @@ -0,0 +1,50 @@ +package javasabr.rlib.collections.array.impl; + +import java.util.stream.LongStream; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; + +@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) +public class ImmutableLongArray extends AbstractLongArray { + + long[] wrapped; + + public ImmutableLongArray(long... elements) { + this.wrapped = elements; + } + + @Override + public long unsafeGet(int index) { + return wrapped[index]; + } + + @Override + public LongStream stream() { + return LongStream.of(wrapped); + } + + @Override + public int size() { + return wrapped.length; + } + + @Override + public boolean isEmpty() { + return wrapped.length < 1; + } + + @Override + public long get(int index) { + + if (index < 0 || index >= size()) { + throw new IndexOutOfBoundsException(); + } + + return wrapped[index]; + } + + @Override + public long[] wrapped() { + return wrapped; + } +} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/ArrayUtils.java b/rlib-common/src/main/java/javasabr/rlib/common/util/ArrayUtils.java index 3fac5b6d..177d6c38 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/ArrayUtils.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/ArrayUtils.java @@ -19,8 +19,6 @@ import javasabr.rlib.common.function.TripleFunction; import javasabr.rlib.common.function.TriplePredicate; import javasabr.rlib.common.util.array.Array; -import javasabr.rlib.common.util.array.IntegerArray; -import javasabr.rlib.common.util.array.LongArray; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; @@ -693,58 +691,6 @@ public static String toString(Array array, Function toString) return builder.toString(); } - /** - * Convert the array to a string presentation. - * - * @param array the array. - * @return the string presentation. - */ - public static String toString(IntegerArray array) { - - final String className = array - .array() - .getClass() - .getSimpleName(); - final StringBuilder builder = new StringBuilder(className.substring(0, className.length() - 1)); - - for (int i = 0, length = array.size() - 1; i <= length; i++) { - builder.append(String.valueOf(array.get(i))); - if (i == length) { - break; - } - builder.append(", "); - } - - builder.append("]"); - return builder.toString(); - } - - /** - * Convert the array to a string presentation. - * - * @param array the array. - * @return the string presentation. - */ - public static String toString(LongArray array) { - - final String className = array - .array() - .getClass() - .getSimpleName(); - final StringBuilder builder = new StringBuilder(className.substring(0, className.length() - 1)); - - for (int i = 0, length = array.size() - 1; i <= length; i++) { - builder.append(String.valueOf(array.get(i))); - if (i == length) { - break; - } - builder.append(", "); - } - - builder.append("]"); - return builder.toString(); - } - /** * Convert the array to a string presentation. * diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/array/ArrayFactory.java b/rlib-common/src/main/java/javasabr/rlib/common/util/array/ArrayFactory.java index f878d04f..3f6bd4e3 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/array/ArrayFactory.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/array/ArrayFactory.java @@ -4,15 +4,9 @@ import javasabr.rlib.common.util.ArrayUtils; import javasabr.rlib.common.util.array.impl.ConcurrentStampedLockArray; -import javasabr.rlib.common.util.array.impl.ConcurrentStampedLockArraySet; import javasabr.rlib.common.util.array.impl.CopyOnModifyArray; -import javasabr.rlib.common.util.array.impl.DefaultIntegerArray; import javasabr.rlib.common.util.array.impl.FastArray; -import javasabr.rlib.common.util.array.impl.FastArraySet; -import javasabr.rlib.common.util.array.impl.FastLongArray; import javasabr.rlib.common.util.array.impl.ReadOnlyFastArray; -import javasabr.rlib.common.util.array.impl.SortedFastArray; -import javasabr.rlib.common.util.array.impl.SynchronizedArray; import org.jspecify.annotations.NullMarked; /** @@ -70,22 +64,6 @@ public static ConcurrentArray newConcurrentStampedLockArray(E [] array) { return result; } - public static MutableIntegerArray newMutableIntegerArray() { - return new DefaultIntegerArray(); - } - - public static MutableIntegerArray newMutableIntegerArray(int capacity) { - return new DefaultIntegerArray(capacity); - } - - public static MutableIntegerArray newMutableIntegerArray(int... numbers) { - return new DefaultIntegerArray(numbers); - } - - public static LongArray newLongArray(int capacity) { - return new FastLongArray(capacity); - } - public static float[] toFloatArray(float... elements) { return elements; } diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/array/ConcurrentIntegerArray.java b/rlib-common/src/main/java/javasabr/rlib/common/util/array/ConcurrentIntegerArray.java deleted file mode 100644 index c593bc57..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/array/ConcurrentIntegerArray.java +++ /dev/null @@ -1,24 +0,0 @@ -package javasabr.rlib.common.util.array; - -public interface ConcurrentIntegerArray { - - /** - * Write lock. - */ - default void writeLock() {} - - /** - * Write unlock. - */ - default void writeUnlock() {} - - /** - * Read lock. - */ - default void readLock() {} - - /** - * Read unlock. - */ - default void readUnlock() {} -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/array/IntegerArray.java b/rlib-common/src/main/java/javasabr/rlib/common/util/array/IntegerArray.java deleted file mode 100644 index 00ce38c8..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/array/IntegerArray.java +++ /dev/null @@ -1,214 +0,0 @@ -package javasabr.rlib.common.util.array; - -import java.util.Arrays; -import java.util.function.Consumer; -import java.util.function.IntConsumer; -import java.util.stream.IntStream; -import javasabr.rlib.common.util.ArrayUtils; -import javasabr.rlib.common.util.array.impl.ReadOnlyIntegerArray; -import org.jspecify.annotations.NullMarked; - -/** - * The interface of dynamic integer array. - */ -@NullMarked -public interface IntegerArray extends Iterable { - - IntegerArray EMPTY = new ReadOnlyIntegerArray(ArrayUtils.EMPTY_INT_ARRAY); - - static IntegerArray of(int value) { - return new ReadOnlyIntegerArray(ArrayFactory.toIntArray(value)); - } - - static IntegerArray of(int v1, int v2) { - return new ReadOnlyIntegerArray(ArrayFactory.toIntArray(v1, v2)); - } - - static IntegerArray of(int v1, int v2, int v3) { - return new ReadOnlyIntegerArray(ArrayFactory.toIntArray(v1, v2, v3)); - } - - static IntegerArray of(int... values) { - return new ReadOnlyIntegerArray(ArrayFactory.toIntArray(values)); - } - - /** - * Return the wrapped int array. Don't change this array, please. - * - * @return the wrapped int array. - */ - int [] array(); - - default boolean contains(int element) { - - var array = array(); - - for (int i = 0, length = size(); i < length; i++) { - if (array[i] == element) { - return true; - } - } - - return false; - } - - default boolean containsAll(int [] array) { - - for (int val : array) { - if (!contains(val)) { - return false; - } - } - - return true; - } - - default boolean containsAll(IntegerArray array) { - - var elements = array.array(); - - for (int i = 0, length = array.size(); i < length; i++) { - if (!contains(elements[i])) { - return false; - } - } - - return true; - } - - /** - * Get the first number. - * - * @return the first number. - * @throws IllegalStateException if this array is empty. - */ - int first(); - - /** - * Get a number by the index. - * - * @param index the index. - * @return the number. - */ - int get(int index); - - /** - * Find index of the first equal number in this array. - * - * @param element the checked number. - * @return the found index or -1. - */ - default int indexOf(int element) { - - var array = array(); - - for (int i = 0, length = size(); i < length; i++) { - if (element == array[i]) { - return i; - } - } - - return -1; - } - - /** - * Return true if this array is empty. - * - * @return true if this array is empty. - */ - default boolean isEmpty() { - return size() < 1; - } - - @Override - ArrayIterator iterator(); - - @Override - default void forEach(Consumer consumer) { - - var array = array(); - - for (int i = 0, length = size(); i < length; i++) { - consumer.accept(array[i]); - } - } - - default void forEachInt(IntConsumer consumer) { - - var array = array(); - - for (int i = 0, length = size(); i < length; i++) { - consumer.accept(array[i]); - } - } - - /** - * Get the last number in this array. - * - * @return the last number. - * @throws IllegalStateException if this array is empty. - */ - int last(); - - /** - * Find index of the last equal number in this array. - * - * @param element the checked number. - * @return the found index or -1. - */ - default int lastIndexOf(int element) { - - var array = array(); - var last = -1; - - for (int i = 0, length = size(); i < length; i++) { - if (element == array[i]) { - last = i; - } - } - - return last; - } - - /** - * Get the current count of numbers in this array. - * - * @return the current count of numbers in this array. - */ - int size(); - - /** - * Create new array from this array. - * - * @return the array with data from this array. - */ - default int [] toArray() { - return ArrayUtils.copyOfRange(array(), 0, size()); - } - - /** - * Copy or create new array from this array. - * - * @param newArray the new array. - * @return the array with data from this array. - */ - default int [] toArray(int [] newArray) { - - var array = array(); - - if (newArray.length >= size()) { - - for (int i = 0, j = 0, length = array.length, newLength = newArray.length; i < length && j < newLength; i++) { - newArray[j++] = array[i]; - } - - return newArray; - } - - return ArrayUtils.copyOfRange(array(), 0, size()); - } - - default IntStream stream() { - return Arrays.stream(array(), 0, size()); - } -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/array/LongArray.java b/rlib-common/src/main/java/javasabr/rlib/common/util/array/LongArray.java deleted file mode 100644 index 854ffb60..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/array/LongArray.java +++ /dev/null @@ -1,345 +0,0 @@ -package javasabr.rlib.common.util.array; - -import javasabr.rlib.common.util.ArrayUtils; -import org.jspecify.annotations.NullMarked; - -/** - * The interface Long array. - */ -@NullMarked -public interface LongArray extends Iterable { - - /** - * Add long array. - * - * @param element the element - * @return the long array - */ - LongArray add(long element); - - /** - * Add all long array. - * - * @param array the array - * @return the long array - */ - LongArray addAll(long[] array); - - /** - * Add all long array. - * - * @param array the array - * @return the long array - */ - LongArray addAll(LongArray array); - - /** - * Array long [ ]. - * - * @return the long [ ] - */ - long[] array(); - - /** - * Clear long array. - * - * @return the long array - */ - LongArray clear(); - - /** - * Contains boolean. - * - * @param element the element - * @return the boolean - */ - default boolean contains(final long element) { - - final long[] array = array(); - - for (int i = 0, length = size(); i < length; i++) { - if (array[i] == element) { - return true; - } - } - - return false; - } - - /** - * Contains all boolean. - * - * @param array the array - * @return the boolean - */ - default boolean containsAll(final long[] array) { - - for (final long val : array) { - if (!contains(val)) { - return false; - } - } - - return true; - } - - /** - * Contains all boolean. - * - * @param array the array - * @return the boolean - */ - default boolean containsAll(final LongArray array) { - - final long[] elements = array.array(); - - for (int i = 0, length = array.size(); i < length; i++) { - if (!contains(elements[i])) { - return false; - } - } - - return true; - } - - /** - * Fast remove boolean. - * - * @param index the index - * @return the boolean - */ - boolean fastRemove(int index); - - /** - * Fast remove boolean. - * - * @param element the element - * @return the boolean - */ - default boolean fastRemove(final long element) { - - final int index = indexOf(element); - if (index > -1) { - fastRemove(index); - } - - return index > -1; - } - - /** - * First long. - * - * @return the long - */ - long first(); - - /** - * Get long. - * - * @param index the index - * @return the long - */ - long get(int index); - - /** - * Index of int. - * - * @param element the element - * @return the int - */ - default int indexOf(final long element) { - - final long[] array = array(); - - for (int i = 0, length = size(); i < length; i++) { - if (element == array[i]) { - return i; - } - } - - return -1; - } - - /** - * Is empty boolean. - * - * @return the boolean - */ - boolean isEmpty(); - - @Override - ArrayIterator iterator(); - - /** - * Last long. - * - * @return the long - */ - long last(); - - /** - * Last index of int. - * - * @param element the element - * @return the int - */ - default int lastIndexOf(final long element) { - - final long[] array = array(); - - int last = -1; - - for (int i = 0, length = size(); i < length; i++) { - if (element == array[i]) { - last = i; - } - } - - return last; - } - - /** - * Poll long. - * - * @return the long - */ - long poll(); - - /** - * Pop long. - * - * @return the long - */ - long pop(); - - /** - * Read lock. - */ - default void readLock() { - } - - /** - * Read unlock. - */ - default void readUnlock() { - } - - /** - * Remove all boolean. - * - * @param target the target - * @return the boolean - */ - default boolean removeAll(final LongArray target) { - if (target.isEmpty()) { - return true; - } - - final long[] array = target.array(); - - for (int i = 0, length = target.size(); i < length; i++) { - fastRemove(array[i]); - } - - return true; - } - - /** - * Retain all boolean. - * - * @param target the target - * @return the boolean - */ - default boolean retainAll(final LongArray target) { - - final long[] array = array(); - - for (int i = 0, length = size(); i < length; i++) { - if (!target.contains(array[i])) { - fastRemove(i--); - length--; - } - } - - return true; - } - - /** - * Size int. - * - * @return the int - */ - int size(); - - /** - * Slow remove boolean. - * - * @param index the index - * @return the boolean - */ - boolean slowRemove(int index); - - /** - * Slow remove boolean. - * - * @param element the element - * @return the boolean - */ - default boolean slowRemove(final long element) { - - final int index = indexOf(element); - if (index > -1) { - slowRemove(index); - } - - return index > -1; - } - - /** - * Sort long array. - * - * @return the long array - */ - LongArray sort(); - - /** - * To array long [ ]. - * - * @param newArray the new array - * @return the long [ ] - */ - default long[] toArray(final long[] newArray) { - - final long[] array = array(); - - if (newArray.length >= size()) { - - for (int i = 0, j = 0, length = array.length, newLength = newArray.length; i < length && j < newLength; i++) { - newArray[j++] = array[i]; - } - - return newArray; - } - - return ArrayUtils.copyOf(array, 0); - } - - /** - * Trim to size long array. - * - * @return the long array - */ - LongArray trimToSize(); - - /** - * Write lock. - */ - default void writeLock() { - } - - /** - * Write unlock. - */ - default void writeUnlock() { - } -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/array/MutableIntegerArray.java b/rlib-common/src/main/java/javasabr/rlib/common/util/array/MutableIntegerArray.java deleted file mode 100644 index d754658a..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/array/MutableIntegerArray.java +++ /dev/null @@ -1,164 +0,0 @@ -package javasabr.rlib.common.util.array; - -import org.jspecify.annotations.NullMarked; - -@NullMarked -public interface MutableIntegerArray extends IntegerArray { - - /** - * Add a new number to this array. - * - * @param number the new integer. - * @return this array. - */ - IntegerArray add(int number); - - /** - * Add new numbers to this array. - * - * @param numbers the new numbers. - * @return this array. - */ - IntegerArray addAll(int [] numbers); - - /** - * Add new numbers to this array. - * - * @param numbers the new numbers. - * @return this array. - */ - IntegerArray addAll(IntegerArray numbers); - - /** - * Clear this array. - * - * @return this array. - */ - IntegerArray clear(); - - /** - * Remove the first equal number in array with putting last number to position of removed number. - * - * @param number the number to remove. - * @return true if the number was removed. - */ - default boolean fastRemove(int number) { - - var index = indexOf(number); - - if (index > -1) { - fastRemoveByIndex(index); - } - - return index > -1; - } - - /** - * Remove a number by the index from this array with putting last number to position of removed number. - * - * @param index the index of number to remove. - * @return true if the number was removed. - */ - boolean fastRemoveByIndex(int index); - - /** - * Get and remove the first number from this array. - * - * @return the first number. - * @throws IllegalStateException if this array is empty. - */ - int poll(); - - /** - * Get and remove the last number from this array. - * - * @return the last number. - * @throws IllegalStateException if this array is empty. - */ - int pop(); - - /** - * Remove the numbers from this array. - * - * @param numbers the array of numbers to remove. - * @return true if at least one number was removed from this array. - */ - default boolean removeAll(IntegerArray numbers) { - - if (numbers.isEmpty()) { - return false; - } - - var array = numbers.array(); - var count = 0; - - for (int i = 0, length = numbers.size(); i < length; i++) { - if (fastRemove(array[i])) { - count++; - } - } - - return count > 0; - } - - /** - * Remove numbers from this array which is not exist in the target array. - * - * @param numbers the array of numbers. - * @return true if at least one number was removed from this array. - */ - default boolean retainAll(IntegerArray numbers) { - - var array = array(); - var count = 0; - - for (int i = 0, length = size(); i < length; i++) { - if (!numbers.contains(array[i])) { - removeByIndex(i--); - length--; - count++; - } - } - - return count > 0; - } - - /** - * Remove the first equal number in array. - * - * @param number the number to remove. - * @return true if the number was removed. - */ - default boolean remove(int number) { - - var index = indexOf(number); - - if (index > -1) { - removeByIndex(index); - } - - return index > -1; - } - - /** - * Remove a number by the index from this array. - * - * @param index the index. - * @return true if the number was removed. - */ - boolean removeByIndex(int index); - - /** - * Sort this array. - * - * @return this array. - */ - IntegerArray sort(); - - /** - * Resize wrapped array to the relevant size. - * - * @return this array. - */ - IntegerArray trimToSize(); -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/array/impl/DefaultIntegerArray.java b/rlib-common/src/main/java/javasabr/rlib/common/util/array/impl/DefaultIntegerArray.java deleted file mode 100644 index 4c0b577c..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/array/impl/DefaultIntegerArray.java +++ /dev/null @@ -1,257 +0,0 @@ -package javasabr.rlib.common.util.array.impl; - -import java.util.Arrays; -import java.util.Objects; -import javasabr.rlib.common.util.ArrayUtils; -import javasabr.rlib.common.util.array.ArrayIterator; -import javasabr.rlib.common.util.array.IntegerArray; -import javasabr.rlib.common.util.array.MutableIntegerArray; -import org.jspecify.annotations.NullMarked; -import org.jspecify.annotations.Nullable; - -/** - * Simple implementation of dynamic integer array. - * - * @author JavaSaBr - */ -@NullMarked -public class DefaultIntegerArray implements MutableIntegerArray { - - protected int[] array; - protected int size; - - public DefaultIntegerArray() { - this(10); - } - - public DefaultIntegerArray(int size) { - this.array = new int[size]; - this.size = 0; - } - - public DefaultIntegerArray(int [] numbers) { - this.array = numbers; - this.size = numbers.length; - } - - @Override - public DefaultIntegerArray add(int number) { - - if (size == array.length) { - array = ArrayUtils.copyOf(array, Math.max(array.length >> 1, 1)); - } - - array[size++] = number; - - return this; - } - - @Override - public DefaultIntegerArray addAll(int [] numbers) { - - if (numbers.length < 1) { - return this; - } - - var current = array.length; - var diff = size() + numbers.length - current; - - if (diff > 0) { - array = ArrayUtils.copyOf(array, Math.max(current >> 1, diff)); - } - - for (var value : numbers) { - add(value); - } - - return this; - } - - @Override - public final DefaultIntegerArray addAll(IntegerArray numbers) { - - if (numbers.isEmpty()) { - return this; - } - - var current = array.length; - var diff = size() + numbers.size() - current; - - if (diff > 0) { - array = ArrayUtils.copyOf(array, Math.max(current >> 1, diff)); - } - - var array = numbers.array(); - - for (int i = 0, length = numbers.size(); i < length; i++) { - add(array[i]); - } - - return this; - } - - @Override - public final int[] array() { - return array; - } - - @Override - public final DefaultIntegerArray clear() { - size = 0; - return this; - } - - @Override - public final boolean fastRemoveByIndex(int index) { - - if (index < 0 || size < 1 || index >= size) { - return false; - } - - var array = array(); - - size -= 1; - - array[index] = array[size]; - array[size] = 0; - - return true; - } - - @Override - public int first() { - if (isEmpty()) { - throw new IllegalStateException("Array is empty."); - } else { - return array[0]; - } - } - - @Override - public final int get(int index) { - if (index >= size) { - throw new IndexOutOfBoundsException(index); - } else { - return array[index]; - } - } - - @Override - public final ArrayIterator iterator() { - return new DefaultIterator(); - } - - @Override - public final int last() { - if (isEmpty()) { - throw new IllegalStateException("Array is empty."); - } else { - return array.length < 1 ? -1 : array[array.length - 1]; - } - } - - @Override - public final int poll() { - var val = first(); - return removeByIndex(0) ? val : -1; - } - - @Override - public final int pop() { - var last = last(); - return fastRemoveByIndex(size - 1) ? last : -1; - } - - @Override - public final int size() { - return size; - } - - @Override - public final boolean removeByIndex(int index) { - - if (index < 0 || size < 1) { - return false; - } - - var array = array(); - var numMoved = size - index - 1; - - if (numMoved > 0) { - System.arraycopy(array, index + 1, array, index, numMoved); - } - - array[--size] = 0; - return true; - } - - @Override - public final DefaultIntegerArray sort() { - ArrayUtils.sort(array, 0, size); - return this; - } - - @Override - public final DefaultIntegerArray trimToSize() { - - var array = array(); - - if (size == array.length) { - return this; - } - - this.array = ArrayUtils.copyOfRange(array, 0, size); - return this; - } - - @Override - public boolean equals(@Nullable Object another) { - - if (this == another) { - return true; - } else if (!(another instanceof IntegerArray)) { - return false; - } - - var array = (IntegerArray) another; - - return size == array.size() && Arrays.equals(this.array, 0, size, array.array(), 0, size); - } - - @Override - public int hashCode() { - var result = Objects.hash(size); - result = 31 * result + Arrays.hashCode(array); - return result; - } - - private final class DefaultIterator implements ArrayIterator { - - private int ordinal = 0; - - @Override - public void fastRemove() { - DefaultIntegerArray.this.fastRemove(--ordinal); - } - - @Override - public boolean hasNext() { - return ordinal < size; - } - - @Override - public int index() { - return ordinal - 1; - } - - @Override - public Integer next() { - return array[ordinal++]; - } - - @Override - public void remove() { - DefaultIntegerArray.this.fastRemove(--ordinal); - } - } -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/array/impl/FastLongArray.java b/rlib-common/src/main/java/javasabr/rlib/common/util/array/impl/FastLongArray.java deleted file mode 100644 index d4dbc7de..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/array/impl/FastLongArray.java +++ /dev/null @@ -1,271 +0,0 @@ -package javasabr.rlib.common.util.array.impl; - -import javasabr.rlib.common.util.ArrayUtils; -import javasabr.rlib.common.util.array.ArrayIterator; -import javasabr.rlib.common.util.array.LongArray; -import org.jspecify.annotations.NullMarked; - -/** - * Реализация не потокобезопасного динамического массива примитивов long. - * - * @author JavaSaBr - */ -@NullMarked -public class FastLongArray implements LongArray { - - /** - * Массив элементов. - */ - protected long[] array; - - /** - * Кол-во элементов в колекции. - */ - protected int size; - - /** - * Instantiates a new Fast long array. - */ - public FastLongArray() { - this(10); - } - - /** - * Instantiates a new Fast long array. - * - * @param size the size - */ - public FastLongArray(final int size) { - this.array = new long[size]; - this.size = 0; - } - - @Override - public FastLongArray add(final long element) { - - if (size == array.length) { - array = ArrayUtils.copyOf(array, Math.max(array.length >> 1, 1)); - } - - array[size++] = element; - return this; - } - - @Override - public final FastLongArray addAll(final long[] elements) { - if (elements == null || elements.length < 1) { - return this; - } - - final int current = array.length; - final int diff = size() + elements.length - current; - - if (diff > 0) { - array = ArrayUtils.copyOf(array, Math.max(current >> 1, diff)); - } - - for (final long element : elements) { - add(element); - } - - return this; - } - - @Override - public final FastLongArray addAll(final LongArray elements) { - if (elements == null || elements.isEmpty()) { - return this; - } - - final int current = array.length; - final int diff = size() + elements.size() - current; - - if (diff > 0) { - array = ArrayUtils.copyOf(array, Math.max(current >> 1, diff)); - } - - final long[] array = elements.array(); - - for (int i = 0, length = elements.size(); i < length; i++) { - add(array[i]); - } - - return this; - } - - @Override - public final long[] array() { - return array; - } - - @Override - public final FastLongArray clear() { - size = 0; - return this; - } - - @Override - public final boolean fastRemove(final int index) { - - if (index < 0 || size < 1 || index >= size) { - return false; - } - - final long[] array = array(); - - size -= 1; - - array[index] = array[size]; - array[size] = 0; - - return true; - } - - @Override - public final long first() { - return size < 1 ? -1 : array[0]; - } - - @Override - public final long get(final int index) { - return array[index]; - } - - @Override - public final int indexOf(final long element) { - - final long[] array = array(); - - for (int i = 0, length = size; i < length; i++) { - final long val = array[i]; - if (element == val) { - return i; - } - } - - return -1; - } - - @Override - public final boolean isEmpty() { - return size < 1; - } - - @Override - public final ArrayIterator iterator() { - return new FastIterator(); - } - - @Override - public final long last() { - if (size < 1) { - return 0; - } - return array[size - 1]; - } - - @Override - public final long poll() { - final long val = first(); - return slowRemove(0) ? val : -1; - } - - @Override - public final long pop() { - final long last = last(); - return fastRemove(size - 1) ? last : -1; - } - - @Override - public final int size() { - return size; - } - - @Override - public final boolean slowRemove(final int index) { - if (index < 0 || size < 1) { - return false; - } - - final long[] array = array(); - final int numMoved = size - index - 1; - - if (numMoved > 0) { - System.arraycopy(array, index + 1, array, index, numMoved); - } - - size -= 1; - array[size] = 0; - - return true; - } - - @Override - public final FastLongArray sort() { - ArrayUtils.sort(array, 0, size); - return this; - } - - @Override - public String toString() { - return ArrayUtils.toString(this); - } - - @Override - public final FastLongArray trimToSize() { - - long[] array = array(); - - if (size == array.length) { - return this; - } - - this.array = ArrayUtils.copyOfRange(array, 0, size); - return this; - } - - /** - * Быстрый итератор массива. - * - * @author JavaSaBr - */ - private final class FastIterator implements ArrayIterator { - - /** - * текущая позиция в массиве - */ - private int ordinal; - - /** - * Instantiates a new Fast iterator. - */ - public FastIterator() { - ordinal = 0; - } - - @Override - public void fastRemove() { - FastLongArray.this.fastRemove(--ordinal); - } - - @Override - public boolean hasNext() { - return ordinal < size; - } - - @Override - public int index() { - return ordinal - 1; - } - - @Override - public Long next() { - return array[ordinal++]; - } - - @Override - public void remove() { - FastLongArray.this.fastRemove(--ordinal); - } - } -} \ No newline at end of file diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/array/impl/ReadOnlyIntegerArray.java b/rlib-common/src/main/java/javasabr/rlib/common/util/array/impl/ReadOnlyIntegerArray.java deleted file mode 100644 index e2bd44b1..00000000 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/array/impl/ReadOnlyIntegerArray.java +++ /dev/null @@ -1,113 +0,0 @@ -package javasabr.rlib.common.util.array.impl; - -import java.util.Arrays; -import java.util.Objects; -import javasabr.rlib.common.util.array.ArrayIterator; -import javasabr.rlib.common.util.array.IntegerArray; -import org.jspecify.annotations.NullMarked; -import org.jspecify.annotations.Nullable; - -/** - * Simple implementation of read only integer array. - * - * @author JavaSaBr - */ -@NullMarked -public class ReadOnlyIntegerArray implements IntegerArray { - - protected final int[] array; - - public ReadOnlyIntegerArray(int [] array) { - this.array = array; - } - - @Override - public final int[] array() { - return array; - } - - @Override - public int first() { - if (isEmpty()) { - throw new IllegalStateException("Array is empty."); - } else { - return array[0]; - } - } - - @Override - public final int get(int index) { - return array[index]; - } - - @Override - public final ArrayIterator iterator() { - return new ReadOnlyIterator(); - } - - @Override - public final int last() { - if (isEmpty()) { - throw new IllegalStateException("Array is empty."); - } else { - return array.length < 1 ? -1 : array[array.length - 1]; - } - } - - @Override - public final int size() { - return array.length; - } - - @Override - public boolean equals(@Nullable Object another) { - - if (this == another) { - return true; - } else if (!(another instanceof IntegerArray)) { - return false; - } - - var array = (IntegerArray) another; - var size = this.array.length; - - return size == array.size() && Arrays.equals(this.array, 0, size, array.array(), 0, size); - } - - @Override - public int hashCode() { - var result = Objects.hash(array.length); - result = 31 * result + Arrays.hashCode(array); - return result; - } - - private final class ReadOnlyIterator implements ArrayIterator { - - private int ordinal = 0; - - @Override - public void fastRemove() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean hasNext() { - return ordinal < array.length; - } - - @Override - public int index() { - return ordinal - 1; - } - - @Override - public Integer next() { - return array[ordinal++]; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - } -} diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/dictionary/AbstractIntegerDictionary.java b/rlib-common/src/main/java/javasabr/rlib/common/util/dictionary/AbstractIntegerDictionary.java index 3439f7b6..ececceff 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/dictionary/AbstractIntegerDictionary.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/dictionary/AbstractIntegerDictionary.java @@ -6,8 +6,6 @@ import java.util.function.Supplier; import javasabr.rlib.common.function.IntBiObjectConsumer; import javasabr.rlib.common.util.ClassUtils; -import javasabr.rlib.common.util.array.IntegerArray; -import javasabr.rlib.common.util.array.MutableIntegerArray; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; @@ -157,19 +155,6 @@ public final Iterator iterator() { return new IntegerDictionaryIterator<>(this); } - @Override - public IntegerArray keyArray(MutableIntegerArray container) { - - for (var entry : entries()) { - while (entry != null) { - container.add(entry.getKey()); - entry = entry.getNext(); - } - } - - return container; - } - @Override public void copyTo(Dictionary dictionary) { diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/dictionary/AbstractLongDictionary.java b/rlib-common/src/main/java/javasabr/rlib/common/util/dictionary/AbstractLongDictionary.java index 06a4f889..99e0f3a1 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/dictionary/AbstractLongDictionary.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/dictionary/AbstractLongDictionary.java @@ -7,7 +7,6 @@ import javasabr.rlib.common.function.LongBiObjectConsumer; import javasabr.rlib.common.function.LongObjectConsumer; import javasabr.rlib.common.util.ClassUtils; -import javasabr.rlib.common.util.array.LongArray; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; @@ -157,19 +156,6 @@ public final Iterator iterator() { return new LongDictionaryIterator<>(this); } - @Override - public LongArray keyArray(LongArray container) { - - for (var entry : entries()) { - while (entry != null) { - container.add(entry.getKey()); - entry = entry.getNext(); - } - } - - return container; - } - @Override public void copyTo(Dictionary dictionary) { diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/dictionary/IntegerDictionary.java b/rlib-common/src/main/java/javasabr/rlib/common/util/dictionary/IntegerDictionary.java index 8883ea4f..807362a3 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/dictionary/IntegerDictionary.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/dictionary/IntegerDictionary.java @@ -5,8 +5,6 @@ import java.util.function.Supplier; import javasabr.rlib.common.function.IntBiObjectConsumer; import javasabr.rlib.common.util.array.ArrayFactory; -import javasabr.rlib.common.util.array.IntegerArray; -import javasabr.rlib.common.util.array.MutableIntegerArray; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; @@ -131,25 +129,6 @@ default V getOrCompute(int key, IntFunction factory) { throw new UnsupportedOperationException(); } - /** - * Create an array with all keys of this dictionary. - * - * @return the array with all keys of this dictionary. - */ - default IntegerArray keyArray() { - return keyArray(ArrayFactory.newMutableIntegerArray(size())); - } - - /** - * Put to the array all keys of this dictionary. - * - * @param container the container. - * @return the container with all keys. - */ - default IntegerArray keyArray(MutableIntegerArray container) { - throw new UnsupportedOperationException(); - } - /** * Put the value by the key. * diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/dictionary/LongDictionary.java b/rlib-common/src/main/java/javasabr/rlib/common/util/dictionary/LongDictionary.java index 0a55deae..c275f205 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/dictionary/LongDictionary.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/dictionary/LongDictionary.java @@ -7,7 +7,6 @@ import javasabr.rlib.common.function.LongObjectConsumer; import javasabr.rlib.common.util.ClassUtils; import javasabr.rlib.common.util.array.ArrayFactory; -import javasabr.rlib.common.util.array.LongArray; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; @@ -131,25 +130,6 @@ default V getOrCompute(long key, LongFunction factory) { throw new UnsupportedOperationException(); } - /** - * Create an array with all keys of this dictionary. - * - * @return the array with all keys of this dictionary. - */ - default LongArray keyArray() { - return keyArray(ArrayFactory.newLongArray(size())); - } - - /** - * Put to the array all keys of this dictionary. - * - * @param container the container. - * @return the container with all keys. - */ - default LongArray keyArray(LongArray container) { - throw new UnsupportedOperationException(); - } - /** * Put the value by the key. * From 1ca886a748e22c4642e676c5e3725ec9666cf136 Mon Sep 17 00:00:00 2001 From: javasabr Date: Sun, 14 Sep 2025 21:04:26 +0200 Subject: [PATCH 4/4] fix tests --- .../util/array/DefaultIntegerArrayTest.java | 201 ------------------ .../util/array/ReadOnlyIntegerArrayTest.java | 68 ------ 2 files changed, 269 deletions(-) delete mode 100644 rlib-common/src/test/java/javasabr/rlib/common/util/array/DefaultIntegerArrayTest.java delete mode 100644 rlib-common/src/test/java/javasabr/rlib/common/util/array/ReadOnlyIntegerArrayTest.java diff --git a/rlib-common/src/test/java/javasabr/rlib/common/util/array/DefaultIntegerArrayTest.java b/rlib-common/src/test/java/javasabr/rlib/common/util/array/DefaultIntegerArrayTest.java deleted file mode 100644 index fa1bc11d..00000000 --- a/rlib-common/src/test/java/javasabr/rlib/common/util/array/DefaultIntegerArrayTest.java +++ /dev/null @@ -1,201 +0,0 @@ -package javasabr.rlib.common.util.array; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -public class DefaultIntegerArrayTest { - - @Test - void addElementsTest() { - - var array = ArrayFactory.newMutableIntegerArray(); - - Assertions.assertEquals(0, array.size()); - - array.add(5); - - Assertions.assertEquals(1, array.size()); - Assertions.assertEquals(5, array.get(0)); - - array.add(-5); - - Assertions.assertEquals(2, array.size()); - Assertions.assertEquals(-5, array.get(1)); - - array.addAll(new int[]{ - -20, - 4 - }); - - Assertions.assertEquals(4, array.size()); - Assertions.assertEquals(-20, array.get(2)); - Assertions.assertEquals(4, array.get(3)); - - array.addAll(ArrayFactory.newMutableIntegerArray(66, -22)); - - Assertions.assertEquals(6, array.size()); - Assertions.assertEquals(66, array.get(4)); - Assertions.assertEquals(-22, array.get(5)); - } - - @Test - void removeElementsTest() { - - var array = ArrayFactory.newMutableIntegerArray(5, -4, 25, -1, 70); - - Assertions.assertEquals(5, array.size()); - Assertions.assertEquals(2, array.indexOf(25)); - - array.remove(25); - - Assertions.assertEquals(4, array.size()); - Assertions.assertEquals(-1, array.indexOf(25)); - - array.fastRemove(5); - - Assertions.assertEquals(3, array.size()); - Assertions.assertEquals(-1, array.indexOf(5)); - Assertions.assertEquals(0, array.indexOf(70)); - - array = ArrayFactory.newMutableIntegerArray(5, -4, 25, -1, 70); - array.removeByIndex(3); - - Assertions.assertEquals(4, array.size()); - Assertions.assertEquals(-1, array.indexOf(-1)); - Assertions.assertEquals(3, array.indexOf(70)); - - array = ArrayFactory.newMutableIntegerArray(5, -4, 25, -1, 70); - array.fastRemoveByIndex(1); - - Assertions.assertEquals(4, array.size()); - Assertions.assertEquals(-1, array.indexOf(-4)); - Assertions.assertEquals(1, array.indexOf(70)); - - array = ArrayFactory.newMutableIntegerArray(5, -4, 25, -1, 70); - array.removeAll(ArrayFactory.newMutableIntegerArray(-4, 70)); - - Assertions.assertEquals(3, array.size()); - Assertions.assertEquals(-1, array.indexOf(-4)); - Assertions.assertEquals(-1, array.indexOf(40)); - Assertions.assertEquals(2, array.indexOf(25)); - - array = ArrayFactory.newMutableIntegerArray(5, -4, 25, -1, 70); - array.retainAll(ArrayFactory.newMutableIntegerArray(25, -1)); - - Assertions.assertEquals(2, array.size()); - Assertions.assertEquals(-1, array.indexOf(5)); - Assertions.assertEquals(-1, array.indexOf(-4)); - Assertions.assertEquals(-1, array.indexOf(70)); - Assertions.assertEquals(0, array.indexOf(25)); - Assertions.assertEquals(1, array.indexOf(-1)); - } - - @Test - void getElementsTest() { - - var array = ArrayFactory.newMutableIntegerArray(5, -4, 25, -1, 70); - - Assertions.assertEquals(25, array.get(2)); - Assertions.assertEquals(5, array.first()); - Assertions.assertEquals(70, array.last()); - - array.clear(); - - Assertions.assertThrows(IndexOutOfBoundsException.class, () -> array.get(2)); - Assertions.assertThrows(IllegalStateException.class, array::first); - Assertions.assertThrows(IllegalStateException.class, array::last); - } - - @Test - void sortTest() { - - var array = ArrayFactory.newMutableIntegerArray(5, -4, 25, -1, 70); - array.sort(); - - Assertions.assertEquals(-4, array.first()); - Assertions.assertEquals(70, array.last()); - Assertions.assertEquals(IntegerArray.of(-4, -1, 5, 25, 70), array); - } - - @Test - void equalsTest() { - - var first = ArrayFactory.newMutableIntegerArray(5, -4, 25, -1, 70); - var second = ArrayFactory.newMutableIntegerArray(5, -4, 25, -1, 70); - - Assertions.assertEquals(first, second); - - first.add(14); - second.add(14); - - Assertions.assertEquals(first, second); - - first.add(33); - second.add(33); - - Assertions.assertEquals(first, second); - - first.add(55); - second.add(45); - - Assertions.assertNotEquals(first, second); - - first.pop(); - second.pop(); - - Assertions.assertEquals(first, second); - - first.removeByIndex(0); - second.removeByIndex(0); - - Assertions.assertEquals(first, second); - } - - @Test - void toArrayTest() { - - var array = ArrayFactory.newMutableIntegerArray(5, -4, 25, -1, 70); - - Assertions.assertArrayEquals(ArrayFactory.toIntArray(5, -4, 25, -1, 70), array.toArray()); - - Assertions.assertArrayEquals(ArrayFactory.toIntArray(5, -4, 25, -1, 70), array.toArray(new int[0])); - - Assertions.assertArrayEquals(ArrayFactory.toIntArray(5, -4, 25, -1, 70), array.toArray(new int[array.size()])); - } - - @Test - void streamTest() { - - var array = ArrayFactory.newMutableIntegerArray(5, -4, 25, -1, 70); - - Assertions.assertArrayEquals( - ArrayFactory.toIntArray(5, -4, 25, -1, 70), - array - .stream() - .toArray()); - } - - @Test - void forEachTest() { - - var array = ArrayFactory.newMutableIntegerArray(5, -4, 25, -1, 70); - var toCollect = ArrayFactory.newMutableIntegerArray(); - - array.forEachInt(toCollect::add); - - Assertions.assertEquals(toCollect, array); - - array = ArrayFactory.newMutableIntegerArray(); - array.add(5); - array.add(-4); - array.add(25); - array.add(-1); - array.add(70); - - var toCollect2 = ArrayFactory.newMutableIntegerArray(); - - array.forEachInt(toCollect2::add); - - Assertions.assertEquals(toCollect2, array); - } -} diff --git a/rlib-common/src/test/java/javasabr/rlib/common/util/array/ReadOnlyIntegerArrayTest.java b/rlib-common/src/test/java/javasabr/rlib/common/util/array/ReadOnlyIntegerArrayTest.java deleted file mode 100644 index 0601594e..00000000 --- a/rlib-common/src/test/java/javasabr/rlib/common/util/array/ReadOnlyIntegerArrayTest.java +++ /dev/null @@ -1,68 +0,0 @@ -package javasabr.rlib.common.util.array; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -public class ReadOnlyIntegerArrayTest { - - @Test - void getElementsTest() { - - var array = IntegerArray.of(5, -4, 25, -1, 70); - - Assertions.assertEquals(25, array.get(2)); - Assertions.assertEquals(5, array.first()); - Assertions.assertEquals(70, array.last()); - - var empty = IntegerArray.EMPTY; - - Assertions.assertThrows(IndexOutOfBoundsException.class, () -> empty.get(2)); - Assertions.assertThrows(IllegalStateException.class, empty::first); - Assertions.assertThrows(IllegalStateException.class, empty::last); - } - - @Test - void equalsTest() { - - var first = IntegerArray.of(5, -4, 25, -1, 70); - var second = IntegerArray.of(5, -4, 25, -1, 70); - - Assertions.assertEquals(first, second); - Assertions.assertNotEquals(IntegerArray.of(5, -4, 4, -1, 70), second); - } - - @Test - void toArrayTest() { - - var array = IntegerArray.of(5, -4, 25, -1, 70); - - Assertions.assertArrayEquals(ArrayFactory.toIntArray(5, -4, 25, -1, 70), array.toArray()); - - Assertions.assertArrayEquals(ArrayFactory.toIntArray(5, -4, 25, -1, 70), array.toArray(new int[0])); - - Assertions.assertArrayEquals(ArrayFactory.toIntArray(5, -4, 25, -1, 70), array.toArray(new int[array.size()])); - } - - @Test - void streamTest() { - - var array = IntegerArray.of(5, -4, 25, -1, 70); - - Assertions.assertArrayEquals( - ArrayFactory.toIntArray(5, -4, 25, -1, 70), - array - .stream() - .toArray()); - } - - @Test - void forEachTest() { - - var array = IntegerArray.of(5, -4, 25, -1, 70); - var toCollect = ArrayFactory.newMutableIntegerArray(); - - array.forEachInt(toCollect::add); - - Assertions.assertEquals(toCollect, array); - } -}