/*
* JBoss, Home of Professional Open Source
* Copyright 2014, Red Hat, Inc., and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.weld.util.collections;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
import org.jboss.weld.util.Preconditions;
/**
* Weld's immutable {@link List} implementations. Based on the size of the data, methods of this class may return {@link List} instances using various storage
* strategies in order to achieve the best performance / memory consumption balance.
*
* @author Jozef Hartinger
* @see WELD-1753
*
* @param <E> the element type
*/
public abstract class ImmutableList<E> extends AbstractImmutableList<E> {
ImmutableList() {
}
/**
* Creates an immutable list that consists of the given elements. This method should only be used in the varargs form. If there is a need to create
* an immutable list of an array of elements, {@link #copyOf(Object[])} should be used instead.
*
* @param elements the given elements
* @return an immutable list
*/
@SafeVarargs
public static <T> List<T> of(T... elements) {
Preconditions.checkNotNull(elements);
return ofInternal(elements);
}
/**
* Creates an immutable list that consists of the elements in the given array. A copy of the given array is used which means
* that any modifications to the given array will not affect the immutable list.
*
* @param elements the given array of elements
* @return an immutable list
*/
public static <T> List<T> copyOf(T[] elements) {
Preconditions.checkNotNull(elements);
return ofInternal(elements.clone());
}
/**
* Creates an immutable list that consists of the elements in the given collection. If the given collection is already an immutable list,
* it is returned directly.
*
* @param source the given collection
* @return an immutable list
*/
public static <T> List<T> copyOf(Collection<T> source) {
Preconditions.checkNotNull(source);
if (source instanceof ImmutableList<?>) {
return (ImmutableList<T>) source;
}
if (source.isEmpty()) {
return Collections.emptyList();
}
return ofInternal(source.toArray());
}
public static <T> List<T> copyOf(Iterable<T> source) {
Preconditions.checkNotNull(source);
if (source instanceof Collection<?>) {
return copyOf((Collection<T>) source);
}
return ImmutableList.<T>builder().addAll(source).build();
}
@SuppressWarnings("unchecked")
private static <T> List<T> ofInternal(Object[] elements) {
switch (elements.length) {
case 0:
return Collections.emptyList();
case 1:
return new ImmutableTinyList.Singleton<T>((T) elements[0]);
default:
return new ImmutableArrayList<T>(checkElementsNotNull(elements));
}
}
private static Object[] checkElementsNotNull(Object[] objects) {
for (Object object : objects) {
Preconditions.checkNotNull(object);
}
return objects;
}
/**
* Returns a collector that can be used to collect items of a stream into an immutable list.
*
* @return collector
*/
@SuppressWarnings("unchecked")
public static <T> ImmutableListCollector<T> collector() {
return (ImmutableListCollector<T>) ImmutableListCollector.INSTANCE;
}
/**
* Creates a new empty builder for building immutable lists.
*
* @return a new empty builder
*/
public static <T> Builder<T> builder() {
return new BuilderImpl<T>();
}
public interface Builder<T> {
Builder<T> add(T item);
Builder<T> addAll(Iterable<? extends T> items);
Builder<T> addAll(@SuppressWarnings("unchecked") T... items);
List<T> build();
}
private static class BuilderImpl<T> implements Builder<T> {
private static final int DEFAULT_CAPACITY = 10;
private List<T> list;
private BuilderImpl() {
this.list = new ArrayList<>(DEFAULT_CAPACITY);
}
@Override
public Builder<T> add(T item) {
if (item == null) {
throw new IllegalArgumentException("This collection does not support null values");
}
list.add(item);
return this;
}
@Override
public Builder<T> addAll(@SuppressWarnings("unchecked") T... items) {
for (T item : items) {
add(item);
}
return this;
}
@Override
public Builder<T> addAll(Iterable<? extends T> items) {
for (T item : items) {
add(item);
}
return this;
}
BuilderImpl<T> addAll(BuilderImpl<T> items) {
addAll(items.list);
return this;
}
@Override
public List<T> build() {
return ImmutableList.ofInternal(list.toArray());
}
}
private static class ImmutableListCollector<T> implements Collector<T, BuilderImpl<T>, List<T>> {
private static final ImmutableListCollector<Object> INSTANCE = new ImmutableListCollector<>();
private static final Set<Characteristics> CHARACTERISTICS = ImmutableSet.of();
@Override
public Supplier<BuilderImpl<T>> supplier() {
return BuilderImpl::new;
}
@Override
public BiConsumer<BuilderImpl<T>, T> accumulator() {
return BuilderImpl::add;
}
@Override
public BinaryOperator<BuilderImpl<T>> combiner() {
return (builder1, builder2) -> builder1.addAll(builder2);
}
@Override
public Function<BuilderImpl<T>, List<T>> finisher() {
return BuilderImpl::build;
}
@Override
public Set<java.util.stream.Collector.Characteristics> characteristics() {
return CHARACTERISTICS;
}
}
}