001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  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 */
017package org.apache.juneau.internal;
018
019import static org.apache.juneau.internal.ConsumerUtils.*;
020
021import java.lang.reflect.*;
022import java.util.*;
023import java.util.function.*;
024
025/**
026 * Builder for arrays.
027 *
028 * <p>
029 * Designed to create arrays without array copying.
030 * Initial capacity cannot be exceeded without throwing a {@link ArrayIndexOutOfBoundsException}.
031 *
032 * <h5 class='section'>See Also:</h5><ul>
033 * </ul>
034 *
035 * @param <E> The array element type.
036 */
037public class ArrayBuilder<E> {
038
039   //-----------------------------------------------------------------------------------------------------------------
040   // Static
041   //-----------------------------------------------------------------------------------------------------------------
042
043   /**
044    * Static creator.
045    *
046    * @param <E> The element type.
047    * @param elementType The element type.
048    * @return A new builder object.
049    */
050   public static <E> ArrayBuilder<E> of(Class<E> elementType) {
051      return new ArrayBuilder<>(elementType);
052   }
053
054   //-----------------------------------------------------------------------------------------------------------------
055   // Instance
056   //-----------------------------------------------------------------------------------------------------------------
057
058   private Predicate<E> filter;
059   private final Class<E> elementType;
060   private int size = -1;
061   private int i;
062   private List<E> list;
063
064   /**
065    * Constructor.
066    *
067    * @param elementType The element type.
068    */
069   public ArrayBuilder(Class<E> elementType) {
070      this.elementType = elementType;
071   }
072
073   /**
074    * Sets the expected size for this array.
075    *
076    * @param value The new value for this setting.
077    * @return This object.
078    */
079   public ArrayBuilder<E> size(int value) {
080      size = value;
081      return this;
082   }
083
084   /**
085    * The predicate to use to filter values added to this builder.
086    *
087    * @param value The new value for this setting.
088    * @return This object.
089    */
090   public ArrayBuilder<E> filter(Predicate<E> value) {
091      filter = value;
092      return this;
093   }
094
095   /**
096    * Appends to this array if the specified value is not null.
097    *
098    * @param t The element to add.
099    * @return This object.
100    * @throws ArrayIndexOutOfBoundsException if size is exceeded.
101    */
102   public ArrayBuilder<E> add(E t) {
103      if (test(filter, t)) {
104         if (list == null)
105            list = size < 0 ? new ArrayList<>() : new ArrayList<>(size);
106         list.add(t);
107         i++;
108      }
109      return this;
110   }
111
112   /**
113    * Returns the populated array.
114    *
115    * @param def The default value if no values were added to this builder.
116    * @return A new array containing the added entries.
117    */
118   @SuppressWarnings("unchecked")
119   public E[] orElse(E[] def) {
120      if (list == null)
121         return def;
122      E[] t = (E[]) Array.newInstance(elementType, list == null ? 0 : list.size());
123      if (list != null)
124         list.toArray(t);
125      return t;
126   }
127}