Ranides Atterwim пре 4 година
родитељ
комит
981690349c

+ 8 - 0
assira.core/src/main/java/net/ranides/assira/collection/query/CQuery.java

@@ -205,6 +205,14 @@ public interface CQuery<T> extends Iterable<T> {
     
     boolean matchNone(Predicate<? super T> predicate);
 
+    int indexOf(T value);
+
+    int indexOf(Predicate<? super T> predicate);
+
+    int lastIndexOf(T value);
+
+    int lastIndexOf(Predicate<? super T> predicate);
+
     <R> R apply(Function<? extends CQuery<? super T>, R> function);
 
     default <R> R applyThis(Function<? extends CQuery<T>, R> function) {

+ 45 - 0
assira.core/src/main/java/net/ranides/assira/collection/query/CQueryAbstract.java

@@ -38,6 +38,7 @@ import java.util.Collection;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
 import java.util.Spliterator;
@@ -590,6 +591,50 @@ public abstract class CQueryAbstract<T> implements CQuery<T>, CQueryFeatures {
         return !matchAny(predicate);
     }
 
+    @Override
+    public int indexOf(T value) {
+        if(hasFastList()) {
+            return list().indexOf(value);
+        } else {
+            return indexOf(v -> Objects.equals(v, value));
+        }
+    }
+
+    @Override
+    public int indexOf(Predicate<? super T> predicate) {
+        if(!hasFastStream()) {
+            if(hasFastEach()) {
+                return BaseEach.indexOf(this, predicate);
+            }
+            if(hasFastIterator()) {
+                return BaseIterable.indexOf(this, predicate);
+            }
+        }
+        return BaseStream.indexOf(this, predicate);
+    }
+
+    @Override
+    public int lastIndexOf(T value) {
+        if(hasFastList()) {
+            return list().lastIndexOf(value);
+        } else {
+            return lastIndexOf(v -> Objects.equals(v, value));
+        }
+    }
+
+    @Override
+    public int lastIndexOf(Predicate<? super T> predicate) {
+        if(!hasFastStream()) {
+            if(hasFastEach()) {
+                return BaseEach.lastIndexOf(this, predicate);
+            }
+            if(hasFastIterator()) {
+                return BaseIterable.lastIndexOf(this, predicate);
+            }
+        }
+        return BaseStream.lastIndexOf(this, predicate);
+    }
+
     @SuppressWarnings("unchecked")
     @Override
     public final <R> R apply(Function<? extends CQuery<? super T>, R> function) {

+ 36 - 12
assira.core/src/main/java/net/ranides/assira/collection/query/support/BaseEach.java

@@ -6,7 +6,6 @@ import net.ranides.assira.collection.arrays.NativeArrayBuilder;
 import net.ranides.assira.collection.maps.OpenMap;
 import net.ranides.assira.collection.query.CQuery;
 import net.ranides.assira.collection.sets.OpenSet;
-import net.ranides.assira.generic.Wrapper;
 import net.ranides.assira.text.StrBuilder;
 
 import java.util.ArrayList;
@@ -102,44 +101,69 @@ public class BaseEach {
     }
 
     public static <T> boolean matchAny(CQuery<T> that, Predicate<? super T> predicate) {
-        Wrapper<Boolean> out = Wrapper.of(false);
+        BaseState.Terminator out = BaseState.newTerminator(that);
         that.whileEach(v -> {
             if(predicate.test(v)) {
-                out.set(true);
+                out.stop();
                 return false;
             }
             return true;
         });
-        return out.get();
+        return out.stopped();
     }
 
     public static <T> T reduce(CQuery<T> that, T identity, BinaryOperator<T> accumulator) {
-        Wrapper<T> out = Wrapper.of(identity);
-        that.forEach(v -> { out.set(accumulator.apply(out.get(), v)); });
+        BaseState.Holder<T> out = BaseState.newHolder(that, identity);
+        that.forEach(v -> {
+            out.set(accumulator.apply(out.get(), v));
+        });
         return out.get();
     }
 
     public static <T> T reduce(CQuery<T> that, BinaryOperator<T> accumulator) {
-        Wrapper<T> out = Wrapper.of(null);
-        that.forEach(v -> { out.set(out.isEmpty() ? v : accumulator.apply(out.get(), v)); });
+        BaseState.Holder<T> out = BaseState.newHolder(that);
+        that.forEach(v -> {
+            out.set(out.isEmpty() ? v : accumulator.apply(out.get(), v));
+        });
         return out.get();
     }
 
     public static <T> Optional<T> first(CQuery<T> that) {
-        Wrapper<Optional<T>> out = Wrapper.of(Optional.empty());
+        BaseState.Holder<T> out = BaseState.newHolder(that);
         that.whileEach(v -> {
-            out.set(Optional.of(v));
+            out.set(v);
             return false;
         });
-        return out.get();
+        return Optional.ofNullable(out.get());
     }
 
     public static <T> Optional<T> last(CQuery<T> that) {
-        Wrapper<T> out = Wrapper.of(null);
+        BaseState.Holder<T> out = BaseState.newHolder(that);
         that.forEach(v -> {
             out.set(v);
         });
         return Optional.ofNullable(out.get());
     }
 
+    public static <T> int indexOf(CQuery<T> that, Predicate<? super T> predicate) {
+        BaseState.Holder<Integer> out = BaseState.newHolder(that, -1);
+        that.whileEach((i,v) -> {
+            if(predicate.test(v)) {
+                out.set(i);
+                return false;
+            }
+            return true;
+        });
+        return out.get();
+    }
+
+    public static <T> int lastIndexOf(CQuery<T> that, Predicate<? super T> predicate) {
+        BaseState.Holder<Integer> out = BaseState.newHolder(that, -1);
+        that.forEach((i,v) -> {
+            if(predicate.test(v)) {
+                out.set(i);
+            }
+        });
+        return out.get();
+    }
 }

+ 23 - 0
assira.core/src/main/java/net/ranides/assira/collection/query/support/BaseIterable.java

@@ -208,4 +208,27 @@ public class BaseIterable {
     public static <T> Optional<T> last(CQuery<T> that) {
         return IterableUtils.last(that);
     }
+
+    public static <T> int indexOf(CQuery<T> that, Predicate<? super T> predicate) {
+        Iterator<T> itr = that.iterator();
+
+        for (int i = 0; itr.hasNext(); i++) {
+            if(predicate.test(itr.next())) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    public static <T> int lastIndexOf(CQuery<T> that, Predicate<? super T> predicate) {
+        Iterator<T> itr = that.iterator();
+        int found = -1;
+
+        for (int i = 0; itr.hasNext(); i++) {
+            if(predicate.test(itr.next())) {
+                found = i;
+            }
+        }
+        return found;
+    }
 }

+ 66 - 0
assira.core/src/main/java/net/ranides/assira/collection/query/support/BaseState.java

@@ -6,6 +6,7 @@ import net.ranides.assira.collection.query.CQuery;
 
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
 
 @UtilityClass
 public class BaseState {
@@ -34,6 +35,21 @@ public class BaseState {
         return paralell ? new PTerminator() : new STerminator();
     }
 
+    public static <T> Holder<T> newHolder(CQuery<?> query) {
+        return newHolder(query, null);
+    }
+
+    public static <T> Holder<T> newHolder(boolean paralell) {
+        return newHolder(paralell, null);
+    }
+
+    public static <T> Holder<T> newHolder(CQuery<?> query, T value) {
+        return newHolder(query.features().isParallel(), value);
+    }
+
+    public static <T> Holder<T> newHolder(boolean paralell, T value) {
+        return paralell ? new PHolder<>(value) : new SHolder<>(value);
+    }
 
     public interface Terminator {
 
@@ -51,6 +67,18 @@ public class BaseState {
 
     }
 
+    public interface Holder<T> {
+
+        void set(T value);
+
+        T get();
+
+        default boolean isEmpty() {
+            return null == get();
+        }
+
+    }
+
     private static class SIndex implements Index {
 
         private int value;
@@ -119,5 +147,43 @@ public class BaseState {
         }
     }
 
+    private static class SHolder<T> implements Holder<T> {
+
+        private T value;
+
+        public SHolder(T value) {
+            this.value = value;
+        }
+
+        @Override
+        public void set(T value) {
+            this.value = value;
+        }
+
+        @Override
+        public T get() {
+            return value;
+        }
+    }
+
+    private static class PHolder<T> implements Holder<T> {
+
+        private final AtomicReference<T> value;
+
+        public PHolder(T value) {
+            this.value = new AtomicReference<>(value);
+        }
+
+        @Override
+        public void set(T value) {
+            this.value.set(value);
+        }
+
+        @Override
+        public T get() {
+            return value.get();
+        }
+    }
+
 
 }

+ 24 - 0
assira.core/src/main/java/net/ranides/assira/collection/query/support/BaseStream.java

@@ -82,4 +82,28 @@ public class BaseStream {
         BaseState.Index index = BaseState.newIndex(that);
         return that.stream().allMatch(v -> consumer.test(index.next(), v));
     }
+
+    public static <T> int indexOf(CQuery<T> that, Predicate<? super T> predicate) {
+        BaseState.Holder<Integer> out = BaseState.newHolder(that, -1);
+        whileEach(that, (i,v) -> {
+            if(predicate.test(v)) {
+                out.set(i);
+                return false;
+            }
+            return true;
+        });
+        return out.get();
+    }
+
+    public static <T> int lastIndexOf(CQuery<T> that, Predicate<? super T> predicate) {
+        BaseState.Holder<Integer> out = BaseState.newHolder(that, -1);
+        BaseState.Index index = BaseState.newIndex(that);
+        that.stream().forEach(v -> {
+            if(predicate.test(v)) {
+                out.set(index.value());
+            }
+            index.next();
+        });
+        return out.get();
+    }
 }

+ 25 - 0
assira.core/src/test/java/net/ranides/assira/collection/query/CQueryAbstractTest.java

@@ -588,4 +588,29 @@ public class CQueryAbstractTest {
         assertEquals(Arrays.asList(9,2,18,4,5), list2);
         assertEquals(Arrays.asList(9,2,3,19,5), list3);
     }
+
+    @Test
+    public void indexOf() {
+        List<Integer> input = Arrays.asList(7, 6, 2, 5, 4, 9, 2, 5, 1, 6, 3, 7, 8, 4);
+
+        assertIndexOf(3, input, 5);
+        assertLastIndexOf(7, input, 5);
+
+        assertIndexOf(-1, input, 15);
+        assertLastIndexOf(-1, input, 15);
+    }
+
+    private <T> void assertIndexOf(int expected, List<T> input, T value) {
+        assertEquals(expected, CQueryMockup.of("list", input).indexOf(value));
+        assertEquals(expected, CQueryMockup.of("each1", input).indexOf(value));
+        assertEquals(expected, CQueryMockup.of("iterator", input).indexOf(value));
+        assertEquals(expected, CQueryMockup.of("stream", input).indexOf(value));
+    }
+
+    private <T> void assertLastIndexOf(int expected, List<T> input, T value) {
+        assertEquals(expected, CQueryMockup.of("list", input).lastIndexOf(value));
+        assertEquals(expected, CQueryMockup.of("each1", input).lastIndexOf(value));
+        assertEquals(expected, CQueryMockup.of("iterator", input).lastIndexOf(value));
+        assertEquals(expected, CQueryMockup.of("stream", input).lastIndexOf(value));
+    }
 }