1 /*
2 * SPDX-FileCopyrightText: none
3 * SPDX-License-Identifier: CC0-1.0
4 */
5
6 package dev.metaschema.core.metapath.item.function;
7
8 import java.util.ArrayList;
9 import java.util.Collection;
10 import java.util.Collections;
11 import java.util.List;
12 import java.util.ListIterator;
13 import java.util.Set;
14 import java.util.function.BiConsumer;
15 import java.util.function.BinaryOperator;
16 import java.util.function.Function;
17 import java.util.function.Supplier;
18 import java.util.stream.Collector;
19 import java.util.stream.Stream;
20
21 import dev.metaschema.core.metapath.function.IFunction;
22 import dev.metaschema.core.metapath.item.ICollectionValue;
23 import dev.metaschema.core.metapath.item.IItem;
24 import dev.metaschema.core.metapath.item.IItemVisitor;
25 import dev.metaschema.core.metapath.item.ISequence;
26 import dev.metaschema.core.metapath.item.atomic.IAnyAtomicItem;
27 import dev.metaschema.core.metapath.item.function.impl.AbstractArrayItem;
28 import dev.metaschema.core.metapath.item.function.impl.ArrayItemN;
29 import dev.metaschema.core.metapath.type.IItemType;
30 import dev.metaschema.core.util.ObjectUtils;
31 import edu.umd.cs.findbugs.annotations.NonNull;
32
33 /**
34 * A representation of a Metapath array item type.
35 * <p>
36 * Instances of this interface are required to enforce non-mutability for array
37 * contents.
38 *
39 * @param <ITEM>
40 * the Metapath item type of array members
41 */
42 public interface IArrayItem<ITEM extends ICollectionValue> extends IFunction, List<ITEM> {
43 /**
44 * Get the type information for this item.
45 *
46 * @return the type information
47 */
48 @NonNull
49 static IItemType type() {
50 return IItemType.array();
51 }
52
53 @Override
54 default IItemType getType() {
55 return type();
56 }
57
58 /**
59 * Get an empty, immutable array item.
60 *
61 * @param <T>
62 * the item Java type
63 * @return an immutable map item
64 */
65 @NonNull
66 static <T extends ICollectionValue> IArrayItem<T> empty() {
67 return AbstractArrayItem.empty();
68 }
69
70 @Override
71 List<ITEM> getValue();
72
73 @Override
74 default boolean hasValue() {
75 return true;
76 }
77
78 @Override
79 default ISequence<?> contentsAsSequence() {
80 return ISequence.of(ObjectUtils.notNull(stream()
81 .flatMap(ICollectionValue::normalizeAsItems)));
82 }
83
84 @Override
85 default Stream<IAnyAtomicItem> atomize() {
86 return ObjectUtils.notNull(stream().flatMap(ICollectionValue::atomize));
87 }
88
89 /**
90 * Determine if this sequence is empty.
91 *
92 * @return {@code true} if the sequence contains no items, or {@code false}
93 * otherwise
94 */
95 @Override
96 default boolean isEmpty() {
97 return getValue().isEmpty();
98 }
99
100 /**
101 * Get the count of items in this sequence.
102 *
103 * @return the count of items
104 */
105 @Override
106 default int size() {
107 return getValue().size();
108
109 }
110
111 @Override
112 default boolean contains(Object obj) {
113 return getValue().contains(obj);
114 }
115
116 @Override
117 default Object[] toArray() {
118 return getValue().toArray();
119 }
120
121 @Override
122 default <T> T[] toArray(T[] array) {
123 return getValue().toArray(array);
124 }
125
126 @Override
127 default boolean containsAll(Collection<?> collection) {
128 return getValue().containsAll(collection);
129 }
130
131 @Override
132 default ITEM get(int index) {
133 return getValue().get(index);
134 }
135
136 @Override
137 default int indexOf(Object obj) {
138 return getValue().indexOf(obj);
139 }
140
141 @Override
142 default int lastIndexOf(Object obj) {
143 return getValue().lastIndexOf(obj);
144 }
145
146 @Override
147 default ListIterator<ITEM> listIterator() {
148 return getValue().listIterator();
149 }
150
151 @Override
152 default ListIterator<ITEM> listIterator(int index) {
153 return getValue().listIterator(index);
154 }
155
156 @Override
157 default List<ITEM> subList(int fromIndex, int toIndex) {
158 return getValue().subList(fromIndex, toIndex);
159 }
160
161 /**
162 * A {@link Collector} implementation to generates a sequence from a stream of
163 * Metapath items.
164 *
165 * @param <T>
166 * the Java type of the items
167 * @return a collector that will generate a sequence
168 */
169 @NonNull
170 static <T extends ICollectionValue> Collector<T, ?, IArrayItem<T>> toArrayItem() {
171 return new Collector<T, List<T>, IArrayItem<T>>() {
172
173 @Override
174 public Supplier<List<T>> supplier() {
175 return ArrayList::new;
176 }
177
178 @Override
179 public BiConsumer<List<T>, T> accumulator() {
180 return List::add;
181 }
182
183 @Override
184 public BinaryOperator<List<T>> combiner() {
185 return (list1, list2) -> {
186 list1.addAll(list2);
187 return list1;
188 };
189 }
190
191 @Override
192 public Function<List<T>, IArrayItem<T>> finisher() {
193 return list -> ofCollection(ObjectUtils.notNull(list));
194 }
195
196 @Override
197 public Set<Characteristics> characteristics() {
198 return Collections.emptySet();
199 }
200 };
201 }
202
203 @Override
204 default ISequence<? extends IArrayItem<ITEM>> toSequence() {
205 return ISequence.of(this);
206 }
207
208 @SuppressWarnings("null")
209 @Override
210 default Stream<? extends IItem> flatten() {
211 return stream()
212 .flatMap(ICollectionValue::flatten);
213 }
214
215 /**
216 * Get a new, immutable array item that contains the items in the provided list.
217 *
218 * @param <T>
219 * the item Java type
220 * @param items
221 * the list whose items are to be added to the new array
222 * @return an array item containing the specified entries
223 */
224 @NonNull
225 static <T extends ICollectionValue> IArrayItem<T> ofCollection(
226 @NonNull List<T> items) {
227 return items.isEmpty() ? empty() : new ArrayItemN<>(items);
228 }
229
230 /**
231 * Returns an unmodifiable array item containing zero elements.
232 *
233 * @param <T>
234 * the item type
235 * @return an empty {@code IArrayItem}
236 */
237 @NonNull
238 static <T extends ICollectionValue> IArrayItem<T> of() {
239 return AbstractArrayItem.empty();
240 }
241
242 /**
243 * Returns an unmodifiable array item containing one item.
244 *
245 * @param <T>
246 * the {@code IArrayItem}'s item type
247 * @param e1
248 * the single item
249 * @return an {@code IArrayItem} containing the specified item
250 * @throws NullPointerException
251 * if the item is {@code null}
252 */
253 @NonNull
254 static <T extends ICollectionValue> IArrayItem<T> of(@NonNull T e1) {
255 return new ArrayItemN<>(e1);
256 }
257
258 /**
259 * Returns an unmodifiable array item containing two items.
260 *
261 * @param <T>
262 * the {@code IArrayItem}'s item type
263 * @param e1
264 * the first item
265 * @param e2
266 * the second item
267 * @return an {@code IArrayItem} containing the specified items
268 * @throws NullPointerException
269 * if an item is {@code null}
270 */
271 @NonNull
272 static <T extends ICollectionValue> IArrayItem<T> of(@NonNull T e1, @NonNull T e2) {
273 return new ArrayItemN<>(e1, e2);
274 }
275
276 /**
277 * Returns an unmodifiable array item containing three elements.
278 *
279 * @param <T>
280 * the {@code IArrayItem}'s item type
281 * @param e1
282 * the first item
283 * @param e2
284 * the second item
285 * @param e3
286 * the third item
287 * @return an {@code IArrayItem} containing the specified items
288 * @throws NullPointerException
289 * if an item is {@code null}
290 */
291 @NonNull
292 static <T extends ICollectionValue> IArrayItem<T> of(@NonNull T e1, @NonNull T e2, @NonNull T e3) {
293 return new ArrayItemN<>(e1, e2, e3);
294 }
295
296 /**
297 * Returns an unmodifiable array item containing four items.
298 *
299 * @param <T>
300 * the {@code IArrayItem}'s item type
301 * @param e1
302 * the first item
303 * @param e2
304 * the second item
305 * @param e3
306 * the third item
307 * @param e4
308 * the fourth item
309 * @return an {@code IArrayItem} containing the specified items
310 * @throws NullPointerException
311 * if an item is {@code null}
312 */
313 @NonNull
314 static <T extends ICollectionValue> IArrayItem<T> of(@NonNull T e1, @NonNull T e2, @NonNull T e3, @NonNull T e4) {
315 return new ArrayItemN<>(e1, e2, e3, e4);
316 }
317
318 /**
319 * Returns an unmodifiable array item containing five items.
320 *
321 * @param <T>
322 * the {@code IArrayItem}'s item type
323 * @param e1
324 * the first item
325 * @param e2
326 * the second item
327 * @param e3
328 * the third item
329 * @param e4
330 * the fourth item
331 * @param e5
332 * the fifth item
333 * @return an {@code IArrayItem} containing the specified items
334 * @throws NullPointerException
335 * if an item is {@code null}
336 */
337 @NonNull
338 static <T extends ICollectionValue> IArrayItem<T> of(@NonNull T e1, @NonNull T e2, @NonNull T e3, @NonNull T e4,
339 @NonNull T e5) {
340 return new ArrayItemN<>(e1, e2, e3, e4, e5);
341 }
342
343 /**
344 * Returns an unmodifiable array item containing six items.
345 *
346 * @param <T>
347 * the {@code IArrayItem}'s item type
348 * @param e1
349 * the first item
350 * @param e2
351 * the second item
352 * @param e3
353 * the third item
354 * @param e4
355 * the fourth item
356 * @param e5
357 * the fifth item
358 * @param e6
359 * the sixth item
360 * @return an {@code IArrayItem} containing the specified items
361 * @throws NullPointerException
362 * if an item is {@code null}
363 */
364 @NonNull
365 static <T extends ICollectionValue> IArrayItem<T> of(@NonNull T e1, @NonNull T e2, @NonNull T e3, @NonNull T e4,
366 @NonNull T e5, @NonNull T e6) {
367 return new ArrayItemN<>(e1, e2, e3, e4, e5, e6);
368 }
369
370 /**
371 * Returns an unmodifiable array item containing seven items.
372 *
373 * @param <T>
374 * the {@code IArrayItem}'s item type
375 * @param e1
376 * the first item
377 * @param e2
378 * the second item
379 * @param e3
380 * the third item
381 * @param e4
382 * the fourth item
383 * @param e5
384 * the fifth item
385 * @param e6
386 * the sixth item
387 * @param e7
388 * the seventh item
389 * @return an {@code IArrayItem} containing the specified items
390 * @throws NullPointerException
391 * if an item is {@code null}
392 */
393 @NonNull
394 static <T extends ICollectionValue> IArrayItem<T> of(@NonNull T e1, @NonNull T e2, @NonNull T e3, @NonNull T e4,
395 @NonNull T e5, @NonNull T e6, @NonNull T e7) {
396 return new ArrayItemN<>(e1, e2, e3, e4, e5, e6, e7);
397 }
398
399 /**
400 * Returns an unmodifiable array item containing eight items.
401 *
402 * @param <T>
403 * the {@code IArrayItem}'s item type
404 * @param e1
405 * the first item
406 * @param e2
407 * the second item
408 * @param e3
409 * the third item
410 * @param e4
411 * the fourth item
412 * @param e5
413 * the fifth item
414 * @param e6
415 * the sixth item
416 * @param e7
417 * the seventh item
418 * @param e8
419 * the eighth item
420 * @return an {@code IArrayItem} containing the specified items
421 * @throws NullPointerException
422 * if an item is {@code null}
423 */
424 @NonNull
425 static <T extends ICollectionValue> IArrayItem<T> of(@NonNull T e1, @NonNull T e2, @NonNull T e3, @NonNull T e4,
426 @NonNull T e5, @NonNull T e6, @NonNull T e7, @NonNull T e8) {
427 return new ArrayItemN<>(e1, e2, e3, e4, e5, e6, e7, e8);
428 }
429
430 /**
431 * Returns an unmodifiable array item containing nine items.
432 *
433 * @param <T>
434 * the {@code IArrayItem}'s item type
435 * @param e1
436 * the first item
437 * @param e2
438 * the second item
439 * @param e3
440 * the third item
441 * @param e4
442 * the fourth item
443 * @param e5
444 * the fifth item
445 * @param e6
446 * the sixth item
447 * @param e7
448 * the seventh item
449 * @param e8
450 * the eighth item
451 * @param e9
452 * the ninth item
453 * @return an {@code IArrayItem} containing the specified items
454 * @throws NullPointerException
455 * if an item is {@code null}
456 */
457 @NonNull
458 static <T extends ICollectionValue> IArrayItem<T> of(@NonNull T e1, @NonNull T e2, @NonNull T e3, @NonNull T e4,
459 @NonNull T e5, @NonNull T e6, @NonNull T e7, @NonNull T e8, @NonNull T e9) {
460 return new ArrayItemN<>(e1, e2, e3, e4, e5, e6, e7, e8, e9);
461 }
462
463 /**
464 * Returns an unmodifiable array item containing ten items.
465 *
466 * @param <T>
467 * the {@code IArrayItem}'s item type
468 * @param e1
469 * the first item
470 * @param e2
471 * the second item
472 * @param e3
473 * the third item
474 * @param e4
475 * the fourth item
476 * @param e5
477 * the fifth item
478 * @param e6
479 * the sixth item
480 * @param e7
481 * the seventh item
482 * @param e8
483 * the eighth item
484 * @param e9
485 * the ninth item
486 * @param e10
487 * the tenth item
488 * @return an {@code IArrayItem} containing the specified items
489 * @throws NullPointerException
490 * if an item is {@code null}
491 */
492 @NonNull
493 static <T extends ICollectionValue> IArrayItem<T> of(@NonNull T e1, @NonNull T e2, @NonNull T e3, @NonNull T e4,
494 @NonNull T e5, @NonNull T e6, @NonNull T e7, @NonNull T e8, @NonNull T e9, @NonNull T e10) {
495 return new ArrayItemN<>(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10);
496 }
497
498 /**
499 * Returns an unmodifiable array item containing an arbitrary number of items.
500 *
501 * @param <T>
502 * the {@code IArrayItem}'s item type
503 * @param items
504 * the items to be contained in the list
505 * @return an {@code IArrayItem} containing the specified items
506 * @throws NullPointerException
507 * if an item is {@code null} or if the array is {@code null}
508 */
509 @SafeVarargs
510 @NonNull
511 static <T extends ICollectionValue> IArrayItem<T> of(@NonNull T... items) {
512 return items.length == 0 ? empty() : new ArrayItemN<>(items);
513 }
514
515 /**
516 * Returns an unmodifiable array item containing the items of the given
517 * Collection, in its iteration order. The given Collection must not be null,
518 * and it must not contain any null items. If the given Collection is
519 * subsequently modified, the returned array item will not reflect such
520 * modifications.
521 *
522 * @param <T>
523 * the {@code IArrayItem}'s item type
524 * @param collection
525 * a {@code Collection} from which items are drawn, must be non-null
526 * @return an {@code IArrayItem} containing the items of the given
527 * {@code Collection}
528 * @throws NullPointerException
529 * if collection is null, or if it contains any nulls
530 */
531 @SuppressWarnings("unchecked")
532 @NonNull
533 static <T extends ICollectionValue> IArrayItem<T> copyOf(@NonNull Collection<? extends T> collection) {
534 return collection instanceof IArrayItem
535 ? (IArrayItem<T>) collection
536 : collection.isEmpty()
537 ? empty()
538 : new ArrayItemN<>(new ArrayList<>(collection));
539 }
540
541 @Override
542 default void accept(IItemVisitor visitor) {
543 visitor.visit(this);
544 }
545 }