001/* 002 * Java Genetic Algorithm Library (jenetics-7.2.0). 003 * Copyright (c) 2007-2023 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 */ 020package io.jenetics.ext.internal.util; 021 022import java.util.ArrayDeque; 023import java.util.Collection; 024import java.util.Deque; 025import java.util.List; 026import java.util.Objects; 027import java.util.Spliterator; 028import 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 */ 038public 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}