ConcatSpliterator.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-7.1.0).
003  * Copyright (c) 2007-2022 Franz Wilhelmstötter
004  *
005  * Licensed under the Apache License, Version 2.0 (the "License");
006  * you may not use this file except in compliance with the License.
007  * You may obtain a copy of the License at
008  *
009  *      http://www.apache.org/licenses/LICENSE-2.0
010  *
011  * Unless required by applicable law or agreed to in writing, software
012  * distributed under the License is distributed on an "AS IS" BASIS,
013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014  * See the License for the specific language governing permissions and
015  * limitations under the License.
016  *
017  * Author:
018  *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
019  */
020 package io.jenetics.ext.internal.util;
021 
022 import java.util.ArrayDeque;
023 import java.util.Collection;
024 import java.util.Deque;
025 import java.util.List;
026 import java.util.Objects;
027 import java.util.Spliterator;
028 import java.util.function.Consumer;
029 
030 /**
031  * This {@code Spliterator} takes a list of other spliterators which are
032  * concatenated and a limiting predicate.
033  *
034  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
035  @version 6.3
036  @since 4.1
037  */
038 public class ConcatSpliterator<T> implements Spliterator<T> {
039 
040     private final Deque<Spliterator<T>> _spliterators;
041     private final int _characteristics;
042     private final long _size;
043 
044     /**
045      * Create a new concatenating spliterator with the given arguments.
046      *
047      @param spliterators the spliterators which are concatenated
048      @throws NullPointerException if one of the arguments are {@code null}
049      */
050     public ConcatSpliterator(final Collection<Spliterator<T>> spliterators) {
051         _spliterators = new ArrayDeque<>(spliterators);
052 
053 
054         int characteristics = (ORDERED | SIZED | SUBSIZED);
055         long size = 0;
056         for (var spliterator : spliterators) {
057             characteristics &= spliterator.characteristics();
058             size += spliterator.estimateSize();
059         }
060         if (size < 0) {
061             size = Long.MAX_VALUE;
062             characteristics &= (~SIZED(~SUBSIZED);
063         }
064 
065         _characteristics = characteristics;
066         _size = size;
067     }
068 
069     @Override
070     public boolean tryAdvance(final Consumer<? super T> action) {
071         boolean advance = true;
072         if (!_spliterators.isEmpty()) {
073             final Spliterator<T> spliterator = _spliterators.peek();
074             assert spliterator != null;
075 
076             if (!spliterator.tryAdvance(action)) {
077                 _spliterators.removeFirst();
078                 advance = !_spliterators.isEmpty();
079             }
080         else {
081             advance = false;
082         }
083 
084         return advance;
085     }
086 
087     @Override
088     public Spliterator<T> trySplit() {
089         final List<Spliterator<T>> split = _spliterators.stream()
090             .map(Spliterator::trySplit)
091             .toList();
092 
093         return split.stream().noneMatch(Objects::isNull)
094             new ConcatSpliterator<>(split)
095             null;
096     }
097 
098     @Override
099     public long estimateSize() {
100         return _size;
101     }
102 
103     @Override
104     public int characteristics() {
105         return _characteristics;
106     }
107 
108 }