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

org.infinispan.commons.util.InfinispanCollections Maven / Gradle / Ivy

There is a newer version: 9.1.7.Final
Show newest version
package org.infinispan.commons.util;

import org.infinispan.commons.marshall.AbstractExternalizer;
import org.infinispan.commons.marshall.Ids;

import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.*;

import static java.util.Collections.singletonMap;
import static java.util.Collections.unmodifiableMap;

/**
 * Static helpers for Infinispan-specific collections
 *
 * @author Manik Surtani
 * @since 4.0
 */
public class InfinispanCollections {

   private static final Set EMPTY_SET = new EmptySet();
   private static final Map EMPTY_MAP = new EmptyMap();
   private static final List EMPTY_LIST = new EmptyList();

   public static final class EmptySet extends AbstractSet {

      private static final Iterator EMPTY_ITERATOR =
            new Iterator() {
         @Override public boolean hasNext() { return false; }
         @Override public Object next() { throw new NoSuchElementException(); }
         @Override public void remove() { throw new UnsupportedOperationException(); }
      };

      @Override
      public Iterator iterator() { return EMPTY_ITERATOR; }
      @Override
      public int size() { return 0; }
      @Override
      public boolean contains(Object obj) { return false; }

      public static final class EmptySetExternalizer
            extends AbstractExternalizer {

         @Override public Integer getId() { return Ids.EMPTY_SET; }
         @Override public void writeObject(ObjectOutput output, Set object) {}
         @Override public Set readObject(ObjectInput input) { return EMPTY_SET; }

         @Override
         @SuppressWarnings("unchecked")
         public Set> getTypeClasses() {
            return Util.>asSet(EmptySet.class);
         }
      }
   }

   public static final class EmptyMap extends java.util.AbstractMap {
      @Override public int size() { return 0; }
      @Override public boolean isEmpty() { return true; }
      @Override public boolean containsKey(Object key) { return false; }
      @Override public boolean containsValue(Object value) { return false; }
      @Override public Object get(Object key) { return null; }
      @Override public Set keySet() { return emptySet(); }
      @Override public Collection values() { return emptySet(); }
      @Override public Set> entrySet() { return emptySet(); }
      @Override public int hashCode() { return 0; }

      @Override
      public boolean equals(Object o) {
         return (o instanceof Map) && ((Map) o).size() == 0;
      }

      public static final class EmptyMapExternalizer
            extends AbstractExternalizer {

         @Override public Integer getId() { return Ids.EMPTY_MAP; }
         @Override public void writeObject(ObjectOutput output, Map object) {}
         @Override public Map readObject(ObjectInput input) { return EMPTY_MAP; }

         @Override
         @SuppressWarnings("unchecked")
         public Set> getTypeClasses() {
            return Util.>asSet(EmptyMap.class);
         }
      }
   }

   public static final class EmptyList
         extends AbstractList implements RandomAccess {

      private static final Iterator EMPTY_ITERATOR =
            new Iterator() {
               @Override public boolean hasNext() { return false; }
               @Override public Object next() { throw new NoSuchElementException(); }
               @Override public void remove() { throw new UnsupportedOperationException(); }
            };

      @Override public int size() { return 0; }
      @Override public boolean contains(Object obj) { return false; }
      @Override public Iterator iterator() { return EMPTY_ITERATOR; }

      @Override public Object get(int index) {
         throw new IndexOutOfBoundsException("Index: " + index);
      }

      public static final class EmptyListExternalizer
            extends AbstractExternalizer {

         @Override public Integer getId() { return Ids.EMPTY_LIST; }
         @Override public void writeObject(ObjectOutput output, List object) {}
         @Override public List readObject(ObjectInput input) { return EMPTY_LIST; }

         @Override
         @SuppressWarnings("unchecked")
         public Set> getTypeClasses() {
            return Util.>asSet(EmptyList.class);
         }

      }

   }

   private static final ReversibleOrderedSet EMPTY_ROS = new EmptyReversibleOrderedSet();

   @SuppressWarnings("unchecked")
   private static final class EmptyReversibleOrderedSet extends AbstractSet implements ReversibleOrderedSet {

      Iterator it = new Iterator() {

         @Override
         public boolean hasNext() {
            return false;
         }

         @Override
         public E next() {
            throw new NoSuchElementException();
         }

         @Override
         public void remove() {
            throw new UnsupportedOperationException();
         }
      };

      @Override
      public Iterator iterator() {
         return it;
      }

      @Override
      public int size() {
         return 0;
      }

      @Override
      public Iterator reverseIterator() {
         return it;
      }
   }

   /**
    * A function that converts a type into another one.
    *
    * @param  Input type.
    * @param  Output type.
    */
   public static interface Function {

      /**
       * Transforms an instance of the given input into an instace of the
       * type to be returned.
       *
       * @param input Instance of the input type.
       * @return Instance of the output type.
       */
      T transform(E input);
   }

   /**
    * A function that converts an entry into a key/value pair for use in a map.
    * @param  generated key
    * @param  generated value
    * @param  entry input
    */
   public static interface MapMakerFunction {
      /**
       * Transforms the given input into a key/value pair for use in a map
       * @param input instance of the input type
       * @return a Map.Entry parameterized with K and V
       */
      Map.Entry transform(E input);
   }

   /**
    * Given a map of well known key/value types, it makes a shallow copy of it
    * while at the same time transforming it's value type to a desired output
    * type. The transformation of the value type is done using a given a
    * function.
    *
    * @param input contains the input key/value pair map
    * @param f function instance to use to transform the value part of the map
    * @param  input map's key type
    * @param  desired output type of the map's value
    * @param  input map's value type
    * @return a shallow copy of the input Map with all its values transformed.
    */
   public static  Map transformMapValue(Map input, Function f) {
      // This screams for a map function! Gimme functional programming pleasee...
      if (input.isEmpty()) return InfinispanCollections.emptyMap();
      if (input.size() == 1) {
         Map.Entry single = input.entrySet().iterator().next();
         return singletonMap(single.getKey(), f.transform(single.getValue()));
      } else {
         Map copy = new HashMap(input.size());
         for (Map.Entry entry : input.entrySet())
            copy.put(entry.getKey(), f.transform(entry.getValue()));
         return unmodifiableMap(copy);
      }
   }

   /**
    * Given a collection, transforms the collection to a map given a {@link MapMakerFunction}
    *
    * @param input contains a collection of type E
    * @param f MapMakerFunction instance to use to transform the collection to a key/value pair
    * @param  output map's key type
    * @param  output type of the map's value
    * @param  input collection's entry type
    * @return a Map with keys and values generated from the input collection
    */
   public static  Map transformCollectionToMap(Collection input, MapMakerFunction f) {
      // This screams for a map function! Gimme functional programming pleasee...
      if (input.isEmpty()) return InfinispanCollections.emptyMap();
      if (input.size() == 1) {
         E single = input.iterator().next();
         Map.Entry entry = f.transform(single);
         return singletonMap(entry.getKey(), entry.getValue());
      } else {
         Map map = new HashMap(input.size());
         for (E e : input) {
            Map.Entry entry = f.transform(e);
            map.put(entry.getKey(), entry.getValue());
         }
         return unmodifiableMap(map);
      }
   }

   /**
    * Returns the elements that are present in s1 but which are not present
    * in s2, without changing the contents of neither s1, nor s2.
    *
    * @param s1 first set
    * @param s2 second set
    * @param  type of objects in Set
    * @return the elements in s1 that are not in s2
    */
   public static  Set difference(Set s1, Set s2) {
      Set copy1 = new HashSet(s1);
      copy1.removeAll(new HashSet(s2));
      return copy1;
   }

   /**
    * Returns the empty set (immutable). Contrary to {@link Collections#emptySet},
    * the set returned returns a constant Iterator, rather than create a
    * brand new one in each iterator call.
    *
    * This set is marshallable using Infinispan's
    * {@link org.jboss.marshalling.Externalizer} framework.
    *
    * @see #EMPTY_SET
    */
   @SuppressWarnings("unchecked")
   public static final  Set emptySet() {
      return EMPTY_SET;
   }

   /**
    * Returns the empty map (immutable). Contrary to {@link Collections#emptyMap()},
    * the map returned returns a constant Iterator, rather than create a
    * brand new one in each iterator call.
    *
    * This set is marshallable using Infinispan's
    * {@link org.jboss.marshalling.Externalizer} framework.
    *
    * @see #EMPTY_MAP
    */
   @SuppressWarnings("unchecked")
   public static final  Map emptyMap() {
      return EMPTY_MAP;
   }

   /**
    * Returns the empty list (immutable). Contrary to {@link Collections#emptyList()}},
    * the list returned returns a constant Iterator, rather than create a
    * brand new one in each iterator call.
    *
    * This set is marshallable using Infinispan's
    * {@link org.jboss.marshalling.Externalizer} framework.
    *
    * @see #EMPTY_LIST
    */
   @SuppressWarnings("unchecked")
   public static final  List emptyList() {
      return EMPTY_LIST;
   }

   public static final  boolean containsAny(Collection haystack, Collection needle) {
      for (T element : needle) {
         if (haystack.contains(element))
            return true;
      }
      return false;
   }
}