001/* 002 * Portions of this software was developed by employees of the National Institute 003 * of Standards and Technology (NIST), an agency of the Federal Government and is 004 * being made available as a public service. Pursuant to title 17 United States 005 * Code Section 105, works of NIST employees are not subject to copyright 006 * protection in the United States. This software may be subject to foreign 007 * copyright. Permission in the United States and in foreign countries, to the 008 * extent that NIST may hold copyright, to use, copy, modify, create derivative 009 * works, and distribute this software and its documentation without fee is hereby 010 * granted on a non-exclusive basis, provided that this notice and disclaimer 011 * of warranty appears in all copies. 012 * 013 * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER 014 * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY 015 * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF 016 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM 017 * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE 018 * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT 019 * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, 020 * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, 021 * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, 022 * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR 023 * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT 024 * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. 025 */ 026 027package gov.nist.secauto.metaschema.core.metapath; 028 029import gov.nist.secauto.metaschema.core.metapath.item.IItem; 030import gov.nist.secauto.metaschema.core.util.ObjectUtils; 031 032import java.util.ArrayList; 033import java.util.Collections; 034import java.util.Iterator; 035import java.util.List; 036import java.util.Set; 037import java.util.function.BiConsumer; 038import java.util.function.BinaryOperator; 039import java.util.function.Consumer; 040import java.util.function.Function; 041import java.util.function.Supplier; 042import java.util.stream.Collector; 043import java.util.stream.Stream; 044 045import edu.umd.cs.findbugs.annotations.NonNull; 046import edu.umd.cs.findbugs.annotations.Nullable; 047 048public interface ISequence<ITEM_TYPE extends IItem> extends Iterable<ITEM_TYPE> { 049 @SuppressWarnings("rawtypes") 050 ISequence EMPTY = new EmptyListImpl<>(); 051 052 /** 053 * Get an empty sequence. 054 * 055 * @param <ITEM_TYPE> 056 * the item type 057 * @return the empty sequence 058 */ 059 @SuppressWarnings({ "unchecked", "null" }) 060 @NonNull 061 static <ITEM_TYPE extends IItem> ISequence<ITEM_TYPE> empty() { 062 return EMPTY; 063 } 064 065 /** 066 * Construct a new sequence containing the provided {@code item}. 067 * <p> 068 * If the item is {@code null} and empty sequence will be created. 069 * 070 * @param <ITEM_TYPE> 071 * the type of items contained in the sequence. 072 * @param item 073 * the item to add to the sequence 074 * @return the new sequence 075 */ 076 @NonNull 077 public static <ITEM_TYPE extends IItem> ISequence<ITEM_TYPE> of( // NOPMD - intentional 078 @Nullable ITEM_TYPE item) { 079 ISequence<ITEM_TYPE> retval; 080 if (item == null) { 081 retval = empty(); 082 } else { 083 retval = new SingletonSequenceImpl<>(item); 084 } 085 return retval; 086 } 087 088 /** 089 * Construct a new sequence containing the provided {@code items}. 090 * 091 * @param <ITEM_TYPE> 092 * the type of items contained in the sequence. 093 * @param items 094 * the items to add to the sequence 095 * @return the new sequence 096 */ 097 @NonNull 098 public static <ITEM_TYPE extends IItem> ISequence<ITEM_TYPE> of( // NOPMD - intentional 099 @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}