All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.javagimmicks.collections8.composite.CompositeSpliterator Maven / Gradle / Ivy

There is a newer version: 0.99-alpha1
Show newest version
package net.sf.javagimmicks.collections8.composite;

import static net.sf.javagimmicks.collections8.MoreCollectors.summingLongToBigInteger;

import java.math.BigInteger;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

class CompositeSpliterator implements Spliterator
{
   protected final LinkedList> _spliterators;
   protected Integer _characteristics;

   CompositeSpliterator(final LinkedList> spliterators)
   {
      _spliterators = new LinkedList<>(spliterators);
   }

   static > CompositeSpliterator fromCollectionList(final List collections)
   {
      return new CompositeSpliterator(collections.stream().map(Collection::spliterator)
            .collect(Collectors.toCollection(LinkedList::new)));
   }

   @Override
   public boolean tryAdvance(final Consumer action)
   {
      for (final Iterator> spliteratorIter = _spliterators.iterator(); spliteratorIter.hasNext();)
      {
         final Spliterator spliterator = spliteratorIter.next();

         if (spliterator.tryAdvance(action))
         {
            return true;
         }

         spliteratorIter.remove();
      }

      return false;
   }

   @Override
   public Spliterator trySplit()
   {
      final int spliteratorsCount = _spliterators.size();
      if (spliteratorsCount == 0)
      {
         // Update characteristics
         _characteristics = 0;

         return null;
      }

      if (spliteratorsCount == 1)
      {
         final Spliterator theLastSpliterator = _spliterators.getFirst();
         final Spliterator result = theLastSpliterator.trySplit();

         // Update characteristics
         _characteristics = theLastSpliterator.characteristics();

         return result;
      }

      // Cut in the middle (not regarding sizes)
      final int middle = _spliterators.size() / 2;

      // Create new List of Spliterators simply by using and cloning a SubList
      final List> splitSpliteratorsSubList = _spliterators.subList(0, middle);
      final LinkedList> splitSpliteratorsNewList = new LinkedList>(
            splitSpliteratorsSubList);

      // Clear the SubList which effectively removes its elements from this
      // Spliterator
      splitSpliteratorsSubList.clear();

      // Reset characteristics
      _characteristics = null;

      return splitSpliteratorsNewList.size() > 1 ? new CompositeSpliterator(splitSpliteratorsNewList)
            : splitSpliteratorsNewList.getFirst();
   }

   @Override
   public long estimateSize()
   {
      // Sum up all estimations of remaining spliterator into a BigInteger
      final BigInteger sum = _spliterators.stream().collect(
            summingLongToBigInteger(Spliterator::estimateSize));

      // Return the sum with an upper limit of Long.MAX_VALUE
      return sum.min(BigInteger.valueOf(Long.MAX_VALUE)).longValue();
   }

   @Override
   public int characteristics()
   {
      if (_characteristics == null)
      {
         _characteristics = calculateCharacteristics();
      }

      return _characteristics;
   }

   private int calculateCharacteristics()
   {
      // We cannot guarantee "DISTINCT" or "SORTED", since we would have to
      // cross-check all elements

      // Walk over all Spliterators and merge the characteristics for each into a
      // Map
      final Map m = new HashMap<>();
      _spliterators.forEach(s -> characteristicsStream().forEach(
            c -> m.merge(c, s.hasCharacteristics(c), (a, b) -> a && b)));

      // Predicate/map/reduce to the final characteristics (skip all "false"
      // characteristics and merge them via "|" operator
      final Optional result = m.entrySet().stream().filter(Entry::getValue).map(Entry::getKey)
            .reduce((a, b) -> a | b);

      return result.orElse(0);
   }

   private static IntStream characteristicsStream()
   {
      return IntStream.of(ORDERED, NONNULL, SIZED, SUBSIZED, IMMUTABLE, CONCURRENT);
   }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy