View Javadoc
1   /*
2    * Portions of this software was developed by employees of the National Institute
3    * of Standards and Technology (NIST), an agency of the Federal Government and is
4    * being made available as a public service. Pursuant to title 17 United States
5    * Code Section 105, works of NIST employees are not subject to copyright
6    * protection in the United States. This software may be subject to foreign
7    * copyright. Permission in the United States and in foreign countries, to the
8    * extent that NIST may hold copyright, to use, copy, modify, create derivative
9    * works, and distribute this software and its documentation without fee is hereby
10   * granted on a non-exclusive basis, provided that this notice and disclaimer
11   * of warranty appears in all copies.
12   *
13   * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER
14   * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY
15   * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF
16   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM
17   * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE
18   * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE.  IN NO EVENT
19   * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT,
20   * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM,
21   * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY,
22   * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR
23   * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT
24   * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER.
25   */
26  
27  package gov.nist.secauto.metaschema.core.metapath;
28  
29  import gov.nist.secauto.metaschema.core.metapath.item.IItem;
30  import gov.nist.secauto.metaschema.core.util.ObjectUtils;
31  
32  import java.util.ArrayList;
33  import java.util.Collections;
34  import java.util.Iterator;
35  import java.util.List;
36  import java.util.Set;
37  import java.util.function.BiConsumer;
38  import java.util.function.BinaryOperator;
39  import java.util.function.Consumer;
40  import java.util.function.Function;
41  import java.util.function.Supplier;
42  import java.util.stream.Collector;
43  import java.util.stream.Stream;
44  
45  import edu.umd.cs.findbugs.annotations.NonNull;
46  import edu.umd.cs.findbugs.annotations.Nullable;
47  
48  public interface ISequence<ITEM_TYPE extends IItem> extends Iterable<ITEM_TYPE> {
49    @SuppressWarnings("rawtypes")
50    ISequence EMPTY = new EmptyListImpl<>();
51  
52    /**
53     * Get an empty sequence.
54     *
55     * @param <ITEM_TYPE>
56     *          the item type
57     * @return the empty sequence
58     */
59    @SuppressWarnings({ "unchecked", "null" })
60    @NonNull
61    static <ITEM_TYPE extends IItem> ISequence<ITEM_TYPE> empty() {
62      return EMPTY;
63    }
64  
65    /**
66     * Construct a new sequence containing the provided {@code item}.
67     * <p>
68     * If the item is {@code null} and empty sequence will be created.
69     *
70     * @param <ITEM_TYPE>
71     *          the type of items contained in the sequence.
72     * @param item
73     *          the item to add to the sequence
74     * @return the new sequence
75     */
76    @NonNull
77    public static <ITEM_TYPE extends IItem> ISequence<ITEM_TYPE> of( // NOPMD - intentional
78        @Nullable ITEM_TYPE item) {
79      ISequence<ITEM_TYPE> retval;
80      if (item == null) {
81        retval = empty();
82      } else {
83        retval = new SingletonSequenceImpl<>(item);
84      }
85      return retval;
86    }
87  
88    /**
89     * Construct a new sequence containing the provided {@code items}.
90     *
91     * @param <ITEM_TYPE>
92     *          the type of items contained in the sequence.
93     * @param items
94     *          the items to add to the sequence
95     * @return the new sequence
96     */
97    @NonNull
98    public static <ITEM_TYPE extends IItem> ISequence<ITEM_TYPE> of( // NOPMD - intentional
99        @NonNull List<ITEM_TYPE> items) {
100     ISequence<ITEM_TYPE> retval;
101     if (items.isEmpty()) {
102       retval = empty();
103     } else {
104       retval = new ListSequenceImpl<>(items);
105     }
106     return retval;
107   }
108 
109   /**
110    * Construct a new sequence containing the provided {@code items}.
111    *
112    * @param <ITEM_TYPE>
113    *          the type of items contained in the sequence.
114    * @param items
115    *          the items to add to the sequence
116    * @return the new sequence
117    */
118   // TODO: remove null check on callers
119   @NonNull
120   public static <ITEM_TYPE extends IItem> ISequence<ITEM_TYPE> of( // NOPMD - intentional
121       Stream<ITEM_TYPE> items) {
122     return items == null ? empty() : new StreamSequenceImpl<>(items);
123   }
124 
125   @Override
126   default Iterator<ITEM_TYPE> iterator() {
127     return asList().listIterator();
128   }
129 
130   /**
131    * Get the items in this sequence as a {@link List}.
132    *
133    * @return a list containing all the items of the sequence
134    */
135   @NonNull
136   List<ITEM_TYPE> asList();
137 
138   /**
139    * Get the items in this sequence as a {@link Stream}.
140    *
141    * @return a stream containing all the items of the sequence
142    */
143   // TODO: rename to "stream"
144   @NonNull
145   Stream<ITEM_TYPE> asStream();
146 
147   /**
148    * This optional operation ensures that a list is used to back this sequence.
149    * <p>
150    * If a stream is currently backing this sequence, the stream will be collected
151    * into a list. This ensures the sequence can be visited multiple times.
152    */
153   void collect();
154 
155   /**
156    * Determine if this sequence is empty.
157    *
158    * @return {@code true} if the sequence contains no items, or {@code false}
159    *         otherwise
160    */
161   boolean isEmpty();
162 
163   /**
164    * Get the count of items in this sequence.
165    *
166    * @return the count of items
167    */
168   int size();
169 
170   /**
171    * Iterate over each item in the sequence using the provided {@code action}.
172    *
173    * @param action
174    *          code to execute for each item
175    */
176   @Override
177   void forEach(Consumer<? super ITEM_TYPE> action);
178 
179   @NonNull
180   static <ITEM_TYPE extends IItem> Collector<ITEM_TYPE, ?, ISequence<ITEM_TYPE>> toSequence() {
181 
182     return new Collector<ITEM_TYPE, List<ITEM_TYPE>, ISequence<ITEM_TYPE>>() {
183 
184       @Override
185       public Supplier<List<ITEM_TYPE>> supplier() {
186         return ArrayList::new;
187       }
188 
189       @Override
190       public BiConsumer<List<ITEM_TYPE>, ITEM_TYPE> accumulator() {
191         return (list, value) -> list.add(value);
192       }
193 
194       @Override
195       public BinaryOperator<List<ITEM_TYPE>> combiner() {
196         return (list1, list2) -> {
197           list1.addAll(list2);
198           return list1;
199         };
200       }
201 
202       @Override
203       public Function<List<ITEM_TYPE>, ISequence<ITEM_TYPE>> finisher() {
204         return list -> {
205           ISequence<ITEM_TYPE> retval;
206           if (list.isEmpty()) {
207             retval = empty();
208           } else if (list.size() == 1) {
209             retval = new SingletonSequenceImpl<>(ObjectUtils.notNull(list.iterator().next()));
210           } else {
211             retval = new ListSequenceImpl<>(list, false);
212           }
213           return retval;
214         };
215       }
216 
217       @Override
218       public Set<Characteristics> characteristics() {
219         return Collections.emptySet();
220       }
221 
222     };
223   }
224 }