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

org.hibernate.search.util.impl.CollectionHelper Maven / Gradle / Ivy

There is a newer version: 5.11.12.Final
Show newest version
/*
 * Hibernate Search, full-text search for your domain model
 *
 * License: GNU Lesser General Public License (LGPL), version 2.1 or later
 * See the lgpl.txt file in the root directory or .
 */

package org.hibernate.search.util.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * Provides some methods for simplified collection instantiation.
 *
 * @author Gunnar Morling
 * @author Hardy Ferentschik
 */
public final class CollectionHelper {

	private CollectionHelper() {
		// not allowed
	}

	public static  HashMap newHashMap() {
		return new HashMap();
	}

	public static  HashMap newHashMap(int size) {
		return new HashMap( size );
	}

	public static  SortedMap newSortedMap() {
		return new TreeMap();
	}

	public static  HashSet newHashSet() {
		return new HashSet();
	}

	public static  ArrayList newArrayList() {
		return new ArrayList();
	}

	public static  ArrayList newArrayList(final int size) {
		return new ArrayList( size );
	}

	public static  Set asSet(T... ts) {
		HashSet set = new HashSet( ts.length );
		Collections.addAll( set, ts );
		return set;
	}

	public static  List toImmutableList(final Collection c) {
		if ( c.isEmpty() ) {
			return Collections.emptyList();
		}
		else {
			return Collections.unmodifiableList( new ArrayList( c ) );
		}
	}

	public static Set asImmutableSet(String[] names) {
		//The intention here is to save some memory by picking the simplest safe representation,
		// as we usually require immutable sets for long living metadata:
		if ( names == null || names.length == 0 ) {
			return Collections.emptySet();
		}
		else if ( names.length == 1 ) {
			return Collections.singleton( names[0] );
		}
		else {
			HashSet hashSet = new HashSet<>( Arrays.asList( names ) );
			return Collections.unmodifiableSet( hashSet );
		}
	}

	/**
	 * Builds an {@link Iterator} for a given array. It is (un)necessarily ugly because we have to deal with array of primitives.
	 *
	 * @param object a given array
	 * @return an {@code Iterator} iterating over the array
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" }) // Reflection is used to ensure the correct types are used
	public static Iterator iteratorFromArray(Object object) {
		return new ArrayIterator( accessorFromArray( object ), object );
	}

	/**
	 * Builds an {@link Iterable} for a given array. It is (un)necessarily ugly because we have to deal with array of primitives.
	 *
	 * @param object a given array
	 * @return an {@code Iterable} providing iterators over the array
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" }) // Reflection is used to ensure the correct types are used
	public static Iterable iterableFromArray(Object object) {
		return new ArrayIterable( accessorFromArray( object ), object );
	}

	public static  Iterable flatten(Iterable> nonFlat) {
		return new Iterable() {
			@Override
			public Iterator iterator() {
				return flatten( nonFlat.iterator() );
			}
		};
	}

	public static  Iterator flatten(Iterator> nonFlat) {
		return new FlatteningIterator<>( nonFlat );
	}

	private static ArrayAccessor accessorFromArray(Object object) {
		ArrayAccessor accessor;
		if ( Object.class.isAssignableFrom( object.getClass().getComponentType() ) ) {
			accessor = ArrayAccessor.OBJECT;
		}
		else if ( object.getClass() == boolean[].class ) {
			accessor = ArrayAccessor.BOOLEAN;
		}
		else if ( object.getClass() == int[].class ) {
			accessor = ArrayAccessor.INT;
		}
		else if ( object.getClass() == long[].class ) {
			accessor = ArrayAccessor.LONG;
		}
		else if ( object.getClass() == double[].class ) {
			accessor = ArrayAccessor.DOUBLE;
		}
		else if ( object.getClass() == float[].class ) {
			accessor = ArrayAccessor.FLOAT;
		}
		else if ( object.getClass() == byte[].class ) {
			accessor = ArrayAccessor.BYTE;
		}
		else if ( object.getClass() == short[].class ) {
			accessor = ArrayAccessor.SHORT;
		}
		else if ( object.getClass() == char[].class ) {
			accessor = ArrayAccessor.CHAR;
		}
		else {
			throw new IllegalArgumentException( "Provided object " + object + " is not a supported array type" );
		}
		return accessor;
	}

	private static class ArrayIterable implements Iterable {
		private final ArrayAccessor accessor;
		private final A values;

		public ArrayIterable(ArrayAccessor accessor, A values) {
			this.accessor = accessor;
			this.values = values;
		}

		@Override
		public final Iterator iterator() {
			return new ArrayIterator<>( accessor, values );
		}
	}

	private static class ArrayIterator implements Iterator {
		private final ArrayAccessor accessor;
		private final A values;
		private int current = 0;

		public ArrayIterator(ArrayAccessor accessor, A values) {
			this.accessor = accessor;
			this.values = values;
		}

		@Override
		public boolean hasNext() {
			return current < accessor.size( values );
		}

		@Override
		public T next() {
			T result = accessor.get( values, current );
			current++;
			return result;
		}
	}

	private interface ArrayAccessor {

		int size(A array);

		T get(A array, int index);

		ArrayAccessor OBJECT = new ArrayAccessor() {
			@Override
			public int size(Object[] array) {
				return array.length;
			}

			@Override
			public Object get(Object[] array, int index) {
				return array[index];
			}
		};

		ArrayAccessor BOOLEAN = new ArrayAccessor() {
			@Override
			public int size(boolean[] array) {
				return array.length;
			}

			@Override
			public Boolean get(boolean[] array, int index) {
				return array[index];
			}
		};

		ArrayAccessor INT = new ArrayAccessor() {
			@Override
			public int size(int[] array) {
				return array.length;
			}

			@Override
			public Integer get(int[] array, int index) {
				return array[index];
			}
		};

		ArrayAccessor LONG = new ArrayAccessor() {
			@Override
			public int size(long[] array) {
				return array.length;
			}

			@Override
			public Long get(long[] array, int index) {
				return array[index];
			}
		};

		ArrayAccessor DOUBLE = new ArrayAccessor() {
			@Override
			public int size(double[] array) {
				return array.length;
			}

			@Override
			public Double get(double[] array, int index) {
				return array[index];
			}
		};

		ArrayAccessor FLOAT = new ArrayAccessor() {
			@Override
			public int size(float[] array) {
				return array.length;
			}

			@Override
			public Float get(float[] array, int index) {
				return array[index];
			}
		};

		ArrayAccessor BYTE = new ArrayAccessor() {
			@Override
			public int size(byte[] array) {
				return array.length;
			}

			@Override
			public Byte get(byte[] array, int index) {
				return array[index];
			}
		};

		ArrayAccessor SHORT = new ArrayAccessor() {
			@Override
			public int size(short[] array) {
				return array.length;
			}

			@Override
			public Short get(short[] array, int index) {
				return array[index];
			}
		};

		ArrayAccessor CHAR = new ArrayAccessor() {
			@Override
			public int size(char[] array) {
				return array.length;
			}

			@Override
			public Character get(char[] array, int index) {
				return array[index];
			}
		};
	}

	private static class FlatteningIterator implements Iterator {

		private Iterator> nonFlatIterator;
		private Iterator current = Collections.emptyIterator();

		public FlatteningIterator(Iterator> nonFlatIterator) {
			this.nonFlatIterator = nonFlatIterator;
		}

		@Override
		public boolean hasNext() {
			// Get the next iterable if we iterated through all elements of the current one
			while ( ! current.hasNext() && nonFlatIterator.hasNext() ) {
				current = nonFlatIterator.next().iterator();
			}
			return current.hasNext() || nonFlatIterator.hasNext();
		}

		@Override
		public T next() {
			// force the position to an non empty current or the end of the flow
			if ( ! hasNext() ) {
				throw new NoSuchElementException();
			}
			return current.next();
		}

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

	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy