001/*
002 * Java Genetic Algorithm Library (jenetics-8.1.0).
003 * Copyright (c) 2007-2024 Franz Wilhelmstötter
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * 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 *
017 * Author:
018 *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
019 */
020package io.jenetics.util;
021
022import static java.util.Objects.requireNonNull;
023import static java.util.stream.Collectors.joining;
024import static io.jenetics.internal.collection.Array.checkIndex;
025
026import java.util.ArrayList;
027import java.util.Arrays;
028import java.util.Comparator;
029import java.util.List;
030import java.util.Objects;
031import java.util.RandomAccess;
032import java.util.function.Function;
033import java.util.function.IntFunction;
034import java.util.function.Predicate;
035import java.util.function.Supplier;
036import java.util.stream.Collector;
037import java.util.stream.Stream;
038import java.util.stream.StreamSupport;
039
040/**
041 * General interface for a ordered, fixed sized, object sequence.
042 * <br>
043 * Use the {@link #asList()} method to work together with the
044 * <a href="https://download.java.net/java/early_access/jdk21/docs/api/java.base/java/util/Collection.html">
045 * Java Collection Framework</a>.
046 *
047 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
048 * @since 1.0
049 * @version 5.2
050 */
051public interface Seq<T> extends BaseSeq<T>, IntFunction<T> {
052
053        /**
054         * Return the value at the given {@code index}.
055         *
056         * @since 3.9
057         *
058         * @see #get(int)
059         *
060         * @param index index of the element to return.
061         * @return the value at the given {@code index}.
062         * @throws IndexOutOfBoundsException if the index is out of range
063         *         {@code index < 0 || index >= size()}.
064         */
065        @Override
066        default T apply(final int index) {
067                return get(index);
068        }
069
070        /**
071         * @see #length()
072         * @return the size of this sequence
073         */
074        default int size() {
075                return length();
076        }
077
078        /**
079         * Tests whether a predicate holds for all elements of this sequence.
080         *
081         * @param predicate the predicate to use to test the elements.
082         * @return {@code true} if the given predicate p holds for all elements of
083         *         this sequence, {@code false} otherwise.
084         * @throws NullPointerException if the given {@code predicate} is
085         *         {@code null}.
086         */
087        default boolean forAll(final Predicate<? super T> predicate) {
088                boolean valid = true;
089
090                for (int i = 0, n = length(); i < n && valid; ++i) {
091                        valid = predicate.test(get(i));
092                }
093
094                return valid;
095        }
096
097        /**
098         * Returns a possibly parallel {@code Stream} with this sequence as its
099         * source.  It is allowable for this method to return a sequential stream.
100         *
101         * @since 3.0
102         *
103         * @return a possibly parallel {@code Stream} over the elements in this
104         * collection
105         */
106        default Stream<T> parallelStream() {
107                return StreamSupport.stream(spliterator(), true);
108        }
109
110        /**
111         * Returns {@code true} if this sequence contains the specified element.
112         *
113         * @param element element whose presence in this sequence is to be tested.
114         *        The tested element can be {@code null}.
115         * @return {@code true} if this sequence contains the specified element
116         */
117        default boolean contains(final Object element) {
118                return indexOf(element) != -1;
119        }
120
121        /**
122         * Returns the index of the first occurrence of the specified element
123         * in this sequence, or -1 if this sequence does not contain the element.
124         *
125         * @param element element to search for, can be {@code null}
126         * @return the index of the first occurrence of the specified element in
127         *          this sequence, or -1 if this sequence does not contain the element
128         */
129        default int indexOf(final Object element) {
130                return indexOf(element, 0, length());
131        }
132
133        /**
134         * Returns the index of the first occurrence of the specified element
135         * in this sequence, or -1 if this sequence does not contain the element.
136         *
137         * @param element element to search for, can be {@code null}
138         * @param start the start index (inclusively) for the element search.
139         * @return the index of the first occurrence of the specified element in
140         *          this sequence, or -1 if this sequence does not contain the element
141         * @throws IndexOutOfBoundsException for an illegal end point index value
142         *          ({@code start < 0 || start > length()}).
143         */
144        default int indexOf(final Object element, final int start) {
145                return indexOf(element, start, length());
146        }
147
148        /**
149         * Returns the index of the first occurrence of the specified element
150         * in this sequence, or -1 if this sequence does not contain the element.
151         *
152         * @param element element to search for, can be {@code null}
153         * @param start the start index (inclusively) for the element search.
154         * @param end the end index (exclusively) for the element search.
155         * @return the index of the first occurrence of the specified element in
156         *          this sequence, or -1 if this sequence does not contain the element
157         * @throws IndexOutOfBoundsException for an illegal end point index value
158         *          ({@code start < 0 || end > length() || start > end}).
159         */
160        default int indexOf(final Object element, final int start, final int end) {
161                return element != null
162                        ? indexWhere(element::equals, start, end)
163                        : indexWhere(Objects::isNull, start, end);
164        }
165
166        /**
167         * <p>
168         * Returns the index of the first element on which the given predicate
169         * returns {@code true}, or -1 if the predicate returns false for every
170         * sequence element.
171         * </p>
172         * {@snippet lang="java":
173         * // Finding index of first null value.
174         * final int index = seq.indexOf(o -> o == null);
175         *
176         * // Assert of no null values.
177         * assert (sequence.indexOf(o -> o == null) == -1);
178         * }
179         *
180         * @param predicate the search predicate.
181         * @return the index of the first element on which the given predicate
182         *          returns {@code true}, or -1 if the predicate returns {@code false}
183         *          for every sequence element.
184         * @throws NullPointerException if the given {@code predicate} is {@code null}.
185         */
186        default int indexWhere(final Predicate<? super T> predicate) {
187                return indexWhere(predicate, 0, length());
188        }
189
190        /**
191         * <p>
192         * Returns the index of the first element on which the given predicate
193         * returns {@code true}, or -1 if the predicate returns false for every
194         * sequence element.
195         * </p>
196         * {@snippet lang="java":
197         * // Finding index of first null value.
198         * final int index = seq.indexOf(o -> o == null);
199         *
200         * // Assert of no null values.
201         * assert (sequence.indexOf(o -> o == null) == -1);
202         * }
203         *
204         * @param predicate the search predicate.
205         * @param start the search start index
206         * @return the index of the first element on which the given predicate
207         *          returns {@code true}, or -1 if the predicate returns {@code false}
208         *          for every sequence element.
209         * @throws NullPointerException if the given {@code predicate} is {@code null}.
210         * @throws IndexOutOfBoundsException for an illegal end point index value
211         *          ({@code start < 0 || start > length()}).
212         */
213        default int indexWhere(
214                final Predicate<? super T> predicate,
215                final int start
216        ) {
217                return indexWhere(predicate, start, length());
218        }
219
220        /**
221         * <p>
222         * Returns the index of the first element on which the given predicate
223         * returns {@code true}, or -1 if the predicate returns false for every
224         * sequence element.
225         * </p>
226         * {@snippet lang="java":
227         * // Finding index of first null value.
228         * final int index = seq.indexOf(o -> o == null);
229         *
230         * // Assert of no null values.
231         * assert (sequence.indexOf(o -> o == null) == -1);
232         * }
233         *
234         * @param predicate the search predicate.
235         * @param start the search start index
236         * @param end the search end index
237         * @return the index of the first element on which the given predicate
238         *          returns {@code true}, or -1 if the predicate returns {@code false}
239         *          for every sequence element.
240         * @throws NullPointerException if the given {@code predicate} is {@code null}.
241         * @throws IndexOutOfBoundsException for an illegal end point index value
242         *          ({@code start < 0 || end > length() || start > end}).
243         */
244        default int indexWhere(
245                final Predicate<? super T> predicate,
246                final int start,
247                final int end
248        ) {
249                requireNonNull(predicate, "Predicate");
250                checkIndex(start, end, length());
251
252                int index = -1;
253                for (int i = start; i < end && index == -1; ++i) {
254                        if (predicate.test(get(i))) {
255                                index = i;
256                        }
257                }
258                return index;
259        }
260
261        /**
262         * Returns the index of the last occurrence of the specified element
263         * in this sequence, or -1 if this sequence does not contain the element.
264         *
265         * @param element element to search for, can be {@code null}
266         * @return the index of the last occurrence of the specified element in
267         *         this sequence, or -1 if this sequence does not contain the element
268         */
269        default int lastIndexOf(final Object element) {
270                return lastIndexOf(element, 0, length());
271        }
272
273        /**
274         * Returns the index of the last occurrence of the specified element
275         * in this sequence, or -1 if this sequence does not contain the element.
276         *
277         * @param element element to search for, can be {@code null}
278         * @param end the search end index
279         * @return the index of the last occurrence of the specified element in
280         *         this sequence, or -1 if this sequence does not contain the element
281         * @throws IndexOutOfBoundsException for an illegal end point index value
282         *          ({@code end < 0 || end > length()}).
283         */
284        default int lastIndexOf(final Object element, final int end) {
285                return lastIndexOf(element, 0, end);
286        }
287
288        /**
289         * Returns the index of the last occurrence of the specified element
290         * in this sequence, or -1 if this sequence does not contain the element.
291         *
292         * @param element element to search for, can be {@code null}
293         * @param start the search start index
294         * @param end the search end index
295         * @return the index of the last occurrence of the specified element in
296         *         this sequence, or -1 if this sequence does not contain the element
297         * @throws IndexOutOfBoundsException for an illegal end point index value
298         *          ({@code start < 0 || end > length() || start > end}).
299         */
300        default int lastIndexOf(
301                final Object element,
302                final int start,
303                final int end
304        ) {
305                return element != null
306                        ? lastIndexWhere(element::equals, start, end)
307                        : lastIndexWhere(Objects::isNull, start, end);
308        }
309
310        /**
311         * Returns the index of the last element on which the given predicate
312         * returns {@code true}, or -1 if the predicate returns false for every
313         * sequence element.
314         *
315         * @param predicate the search predicate.
316         * @return the index of the last element on which the given predicate
317         *          returns {@code true}, or -1 if the predicate returns false for
318         *          every sequence element.
319         * @throws NullPointerException if the given {@code predicate} is {@code null}.
320         */
321        default int lastIndexWhere(final Predicate<? super T> predicate) {
322                return lastIndexWhere(predicate, 0, length());
323        }
324
325        /**
326         * Returns the index of the last element on which the given predicate
327         * returns {@code true}, or -1 if the predicate returns false for every
328         * sequence element.
329         *
330         * @param predicate the search predicate.
331         * @param end the search end index
332         * @return the index of the last element on which the given predicate
333         *          returns {@code true}, or -1 if the predicate returns false for
334         *          every sequence element.
335         * @throws NullPointerException if the given {@code predicate} is {@code null}.
336         * @throws IndexOutOfBoundsException for an illegal end point index value
337         *          ({@code end < 0 || end > length()}).
338         */
339        default int lastIndexWhere(
340                final Predicate<? super T> predicate,
341                final int end
342        ) {
343                return lastIndexWhere(predicate, 0, end);
344        }
345
346        /**
347         * Returns the index of the last element on which the given predicate
348         * returns {@code true}, or -1 if the predicate returns false for every
349         * sequence element.
350         *
351         * @param predicate the search predicate.
352         * @param start the search start index
353         * @param end the search end index
354         * @return the index of the last element on which the given predicate
355         *          returns {@code true}, or -1 if the predicate returns false for
356         *          every sequence element.
357         * @throws NullPointerException if the given {@code predicate} is {@code null}.
358         * @throws IndexOutOfBoundsException for an illegal end point index value
359         *          ({@code start < 0 || end > length() || start > end}).
360         */
361        default int lastIndexWhere(
362                final Predicate<? super T> predicate,
363                final int start,
364                final int end
365        ) {
366                requireNonNull(predicate, "Predicate");
367                checkIndex(start, end, length());
368
369                int index = -1;
370                for (int i = end; --i >= start && index == -1;) {
371                        if (predicate.test(get(i))) {
372                                index = i;
373                        }
374                }
375                return index;
376        }
377
378        /**
379         * Builds a new sequence by applying a function to all elements of this
380         * sequence.
381         *
382         * @param <B> the element type of the returned collection.
383         * @param mapper the function to apply to each element.
384         * @return a new sequence of type That resulting from applying the given
385         *         function f to each element of this sequence and collecting the
386         *         results.
387         * @throws NullPointerException if the element {@code mapper} is
388         *         {@code null}.
389         */
390        <B> Seq<B> map(final Function<? super T, ? extends B> mapper);
391
392        /**
393         * Return a <i>new</i> {@code Seq} with the given {@code values} appended.
394         *
395         * @since 3.4
396         *
397         * @param values the values to append
398         * @return a <i>new</i> {@code Seq} with the elements of {@code this}
399         *        sequence and the given {@code values} appended.
400         * @throws NullPointerException if the given {@code values} array is
401         *         {@code null}
402         */
403        @SuppressWarnings("unchecked")
404        default Seq<T> append(final T... values) {
405                return append(Seq.of(values));
406        }
407
408        /**
409         * Return a <i>new</i> {@code Seq} with the given {@code values} appended.
410         *
411         * @since 3.4
412         *
413         * @param values the values to append
414         * @return a <i>new</i> {@code Seq} with the elements of {@code this}
415         *        sequence and the given {@code values} appended.
416         * @throws NullPointerException if the given {@code values} iterable is
417         *         {@code null}
418         */
419        Seq<T> append(final Iterable<? extends T> values);
420
421        /**
422         * Return a <i>new</i> {@code Seq} with the given {@code values} prepended.
423         *
424         * @since 3.4
425         *
426         * @param values the values to append
427         * @return a <i>new</i> {@code Seq} with the elements of {@code this}
428         *        sequence and the given {@code values} prepended.
429         * @throws NullPointerException if the given {@code values} array is
430         *         {@code null}
431         */
432        @SuppressWarnings("unchecked")
433        default Seq<T> prepend(final T... values) {
434                return prepend(Seq.of(values));
435        }
436
437        /**
438         * Return a <i>new</i> {@code Seq} with the given {@code values} prepended.
439         *
440         * @since 3.4
441         *
442         * @param values the values to append
443         * @return a <i>new</i> {@code Seq} with the elements of {@code this}
444         *        sequence and the given {@code values} prepended.
445         * @throws NullPointerException if the given {@code values} array is
446         *         {@code null}
447         */
448        Seq<T> prepend(final Iterable<? extends T> values);
449
450        /**
451         * Returns a fixed-size list backed by the specified sequence. (Changes to
452         * the returned list "write through" to the array.) The returned list is
453         * fixed size, serializable and implements {@link RandomAccess}.
454         *
455         * @return a list view of this sequence
456         */
457        default List<T> asList() {
458                return new BaseSeqList<>(this);
459        }
460
461        /**
462         * Return an array containing all of the elements in this sequence in right
463         * order. The returned array will be "safe" in that no references to it
464         * are maintained by this sequence. (In other words, this method must allocate
465         * a new array.) The caller is thus free to modify the returned array.
466         *
467         * @see java.util.Collection#toArray()
468         *
469         * @return an array containing all of the elements in this list in the right
470         *          order
471         */
472        default Object[] toArray() {
473                final Object[] array = new Object[size()];
474                for (int i = size(); --i >= 0;) {
475                        array[i] = get(i);
476                }
477                return array;
478        }
479
480        /**
481         * Return an array containing all of the elements in this sequence in right
482         * order; the runtime type of the returned array is that of the specified
483         * array. If this sequence fits in the specified array, it is returned
484         * therein. Otherwise, a new array is allocated with the runtime type of the
485         * specified array and the length of this array.
486         * <p>
487         * If this sequence fits in the specified array with room to spare (i.e.,
488         * the array has more elements than this array); the element in the array
489         * immediately following the end of this array is set to null. (This is
490         * useful in determining the length of the array only if the caller knows
491         * that the list does not contain any null elements.)
492         *
493         * @see java.util.Collection#toArray(Object[])
494         *
495         * @param <B> the runtime type of the array to contain the sequence
496         * @param array the array into which the elements of this array are to be
497         *         stored, if it is big enough; otherwise, a new array of the same
498         *         runtime type is allocated for this purpose.
499         * @return an array containing the elements of this array
500         * @throws ArrayStoreException if the runtime type of the specified array is
501         *         not a super type of the runtime type of every element in this
502         *         array
503         * @throws NullPointerException if the given {@code array} is {@code null}.
504         */
505        @SuppressWarnings("unchecked")
506        default <B> B[] toArray(final B[] array) {
507                if (array.length < length()) {
508                        final Object[] copy = (Object[])java.lang.reflect.Array
509                                .newInstance(array.getClass().getComponentType(), length());
510
511                        for (int i = length(); --i >= 0;) {
512                                copy[i] = get(i);
513                        }
514
515                        return (B[])copy;
516                }
517
518                for (int i = 0, n = length(); i < n; ++i) {
519                        ((Object[])array)[i] = get(i);
520                }
521                if (array.length > length()) {
522                        array[length()] = null;
523                }
524
525                return array;
526        }
527
528        /**
529         * Returns an array containing the elements of this sequence, using the
530         * provided generator function to allocate the returned array.
531         *
532         * @since 4.4
533         *
534         * @param generator a function which produces a new array of the desired
535         *        type and the provided length
536         * @param <B> the element type of the resulting array
537         * @return an array containing the elements in {@code this} sequence
538         * @throws ArrayStoreException if the runtime type of the specified array is
539         *         not a super type of the runtime type of every element in this
540         *         array
541         * @throws NullPointerException if the given {@code generator} is {@code null}.
542         */
543        default <B> B[] toArray(final IntFunction<B[]> generator) {
544                return toArray(generator.apply(length()));
545        }
546
547        /**
548         * Returns a view of the portion of this sequence between the specified
549         * {@code start}, inclusive, and {@code end}, exclusive. (If {@code start}
550         * and {@code end} are equal, the returned sequence has length zero.)
551         * The returned sequence is backed by this sequence, so non-structural
552         * changes in the returned sequence are reflected in this sequence, and
553         * vice versa.
554         * <p>
555         * This method eliminates the need for explicit range operations (of the
556         * populationSort that commonly exist for arrays). Any operation that
557         * expects a sequence can be used as a range operation by passing a
558         * subsequence view instead of a whole sequence.
559         *
560         * @param start lower end point (inclusive) of the subarray.
561         * @return a view of the specified range within this array.
562         * @throws IndexOutOfBoundsException for an illegal end point index value
563         *          ({@code start < 0 || start > length()}).
564         */
565        Seq<T> subSeq(final int start);
566
567        /**
568         * Returns a view of the portion of this sequence between the specified
569         * {@code start}, inclusive, and {@code end}, exclusive. (If {@code start}
570         * and {@code end} are equal, the returned sequence has length zero.)
571         * The returned sequence is backed by this sequence, so non-structural
572         * changes in the returned sequence are reflected in this array, and
573         * vice versa.
574         * <p>
575         * This method eliminates the need for explicit range operations (of the
576         * populationSort that commonly exist for arrays). Any operation that
577         * expects an array can be used as a range operation by passing a
578         * subsequence view instead of a whole sequence.
579         *
580         * @param start low-end point (inclusive) of the subsequence.
581         * @param end high-end point (exclusive) of the subsequence.
582         * @return a view of the specified range within this sequence.
583         * @throws IndexOutOfBoundsException for an illegal end point index value
584         *          ({@code start < 0 || end > length() || start > end}).
585         */
586        Seq<T> subSeq(final int start, final int end);
587
588        /**
589         * Test whether the given array is sorted in ascending order.
590         *
591         * @return {@code true} if the given {@code array} is sorted in ascending
592         *         order, {@code false} otherwise.
593         * @throws NullPointerException if the given array or one of its element is
594         *         {@code null}.
595         */
596        @SuppressWarnings("unchecked")
597        default boolean isSorted() {
598                boolean sorted = true;
599                for (int i = 0, n = length() - 1; i < n && sorted; ++i) {
600                        sorted = ((Comparable<T>)get(i)).compareTo(get(i + 1)) <= 0;
601                }
602
603                return sorted;
604        }
605
606        /**
607         * Test whether the given array is sorted in ascending order. The order of
608         * the array elements is defined by the given comparator.
609         *
610         * @param comparator the comparator which defines the order.
611         * @return {@code true} if the given {@code array} is sorted in ascending
612         *         order, {@code false} otherwise.
613         * @throws NullPointerException if the given array or one of its elements or
614         *         the comparator is {@code null}.
615         */
616        default boolean isSorted(final Comparator<? super T> comparator) {
617                boolean sorted = true;
618                for (int i = 0, n = length() - 1; i < n && sorted; ++i) {
619                        sorted = comparator.compare(get(i), get(i + 1)) <= 0;
620                }
621
622                return sorted;
623        }
624
625        /**
626         * Return this sequence as {@code MSeq} instance. If {@code this} is not a
627         * {@code MSeq} a new seq is created.
628         *
629         * @since 3.8
630         *
631         * @return a {@code MSeq} with this values
632         */
633        default MSeq<T> asMSeq() {
634                return this instanceof MSeq ? (MSeq<T>)this : MSeq.of(this);
635        }
636
637        /**
638         * Return this sequence as {@code ISeq} instance. If {@code this} is not a
639         * {@code ISeq} a new seq is created.
640         *
641         * @since 3.8
642         *
643         * @return a {@code ISeq} with this values
644         */
645        default ISeq<T> asISeq() {
646                return this instanceof ISeq ? (ISeq<T>)this : ISeq.of(this);
647        }
648
649        /**
650         * Returns the hash code value for this sequence. The hash code is defined
651         * as followed:
652         * {@snippet lang="java":
653         * int hashCode = 1;
654         * final Iterator<E> it = seq.iterator();
655         * while (it.hasNext()) {
656         *     final E obj = it.next();
657         *     hashCode = 31*hashCode + (obj == null ? 0 : obj.hashCode());
658         * }
659         * }
660         *
661         * @see List#hashCode()
662         * @see Seq#hashCode(BaseSeq)
663         *
664         * @return the hash code value for this list
665         */
666        @Override
667        int hashCode();
668
669        /**
670         * Compares the specified object with this sequence for equality. Returns
671         * true if and only if the specified object is also a sequence, both
672         * sequences have the same size, and all corresponding pairs of elements in
673         * the two sequences are equal. (Two elements e1 and e2 are equal if
674         * (e1==null ? e2==null : e1.equals(e2)).) This definition ensures that the
675         * equals method works properly across different implementations of the Seq
676         * interface.
677         *
678         * @see List#equals(Object)
679         * @see Seq#equals(BaseSeq, Object)
680         *
681         * @param object the object to be compared for equality with this sequence.
682         * @return {@code true} if the specified object is equal to this sequence,
683         *          {@code false} otherwise.
684         */
685        @Override
686        boolean equals(final Object object);
687
688        /**
689         * Create a string representation of the given sequence.
690         *
691         * @param prefix the prefix of the string representation; e.g {@code '['}.
692         * @param separator the separator of the array elements; e.g. {@code ','}.
693         * @param suffix the suffix of the string representation; e.g. {@code ']'}.
694         * @return the string representation of this sequence.
695         */
696        default String toString(
697                final String prefix,
698                final String separator,
699                final String suffix
700        ) {
701                return stream()
702                        .map(Objects::toString)
703                        .collect(joining(separator, prefix, suffix));
704        }
705
706        /**
707         * Create a string representation of the given sequence.
708         *
709         * @param separator the separator of the array elements; e.g. {@code ','}.
710         * @return the string representation of this sequence.
711         */
712        default String toString(final String separator) {
713                return toString("", separator, "");
714        }
715
716        /**
717         * Unified method for calculating the hash code of every {@link Seq}
718         * implementation. The hash code is defined as followed:
719         * {@snippet lang="java":
720         * int hashCode = 1;
721         * final Iterator<E> it = seq.iterator();
722         * while (it.hasNext()) {
723         *     final E obj = it.next();
724         *     hashCode = 31*hashCode + (obj == null ? 0 : obj.hashCode());
725         * }
726         * }
727         *
728         * @see Seq#hashCode()
729         * @see List#hashCode()
730         *
731         * @param seq the sequence to calculate the hash code for.
732         * @return the hash code of the given sequence.
733         */
734        static int hashCode(final BaseSeq<?> seq) {
735                int hash = 1;
736                for (Object element : seq) {
737                        hash = 31*hash + (element == null ? 0: element.hashCode());
738                }
739                return hash;
740        }
741
742        /**
743         * Unified method for compare to sequences for equality.
744         *
745         * @see Seq#equals(Object)
746         *
747         * @param seq the sequence to test for equality.
748         * @param obj the object to test for equality with the sequence.
749         * @return {@code true} if the given objects are sequences and contain the
750         *          same objects in the same order, {@code false} otherwise.
751         */
752        static boolean equals(final BaseSeq<?> seq, final Object obj) {
753                if (obj == seq) {
754                        return true;
755                }
756                if (!(obj instanceof final Seq<?> other)) {
757                        return false;
758                }
759
760                boolean equals = seq.length() == other.length();
761                for (int i = seq.length(); equals && --i >= 0;) {
762                        final Object element = seq.get(i);
763                        equals = element != null
764                                ? element.equals(other.get(i))
765                                : other.get(i) == null;
766                }
767                return equals;
768        }
769
770        /* *************************************************************************
771         *  Some static helper methods.
772         * ************************************************************************/
773
774        /**
775         * Return a sequence whose elements are all the elements of the first
776         * element followed by all the elements of the sequence.
777         *
778         * @since 5.0
779         *
780         * @param a the first element
781         * @param b the appending sequence
782         * @param <T> the type of the sequence elements
783         * @return the concatenation of the two inputs
784         * @throws NullPointerException if one of the second arguments is
785         *         {@code null}
786         */
787        @SuppressWarnings("unchecked")
788        static <T> Seq<T> concat(
789                final T a,
790                final Seq<? extends T> b
791        ) {
792                return ((Seq<T>)b).prepend(a);
793        }
794
795        /**
796         * Return a sequence whose elements are all the elements of the first
797         * sequence followed by all the elements of the vararg array.
798         *
799         * @since 5.0
800         *
801         * @param a the first sequence
802         * @param b the vararg elements
803         * @param <T> the type of the sequence elements
804         * @return the concatenation of the two inputs
805         * @throws NullPointerException if one of the arguments is {@code null}
806         */
807        @SuppressWarnings("unchecked")
808        static <T> Seq<T> concat(
809                final Seq<? extends T> a,
810                final T... b
811        ) {
812                return ((Seq<T>)a).append(b);
813        }
814
815        /**
816         * Return a sequence whose elements are all the elements of the first
817         * sequence followed by all the elements of the second sequence.
818         *
819         * @since 5.0
820         *
821         * @param a the first sequence
822         * @param b the second sequence
823         * @param <T> the type of the sequence elements
824         * @return the concatenation of the two input sequences
825         * @throws NullPointerException if one of the arguments is {@code null}
826         */
827        @SuppressWarnings("unchecked")
828        static <T> Seq<T> concat(
829                final Seq<? extends T> a,
830                final Seq<? extends T> b
831        ) {
832                return ((Seq<T>)a).append(b);
833        }
834
835        /* *************************************************************************
836         *  Some static factory methods.
837         * ************************************************************************/
838
839        /**
840         * Single instance of an empty {@code Seq}.
841         *
842         * @since 3.3
843         */
844        Seq<?> EMPTY = ISeq.EMPTY;
845
846        /**
847         * Return an empty {@code Seq}.
848         *
849         * @since 3.3
850         *
851         * @param <T> the element type of the returned {@code Seq}.
852         * @return an empty {@code Seq}.
853         */
854        static <T> Seq<T> empty() {
855                return ISeq.empty();
856        }
857
858        /**
859         * Returns a {@code Collector} that accumulates the input elements into a
860         * new {@code Seq}.
861         *
862         * @param <T> the type of the input elements
863         * @return a {@code Collector} which collects all the input elements into a
864         *         {@code Seq}, in encounter order
865         */
866        static <T> Collector<T, ?, Seq<T>> toSeq() {
867                return Collector.of(
868                        (Supplier<List<T>>)ArrayList::new,
869                        List::add,
870                        (left, right) -> { left.addAll(right); return left; },
871                        Seq::of
872                );
873        }
874
875        /**
876         * Returns a {@code Collector} that accumulates the last {@code n} input
877         * elements into a new {@code Seq}.
878         *
879         * @since 5.0
880         *
881         * @param maxSize the maximal size of the collected sequence
882         * @param <T> the type of the input elements
883         * @return a {@code Collector} which collects maximal {@code maxSize} of the
884         *         input elements into an {@code ISeq}, in encounter order
885         * @throws IllegalArgumentException if the {@code maxSize} is negative
886         */
887        static <T> Collector<T, ?, Seq<T>> toSeq(final int maxSize) {
888                return Seqs.toSeq(maxSize, Buffer::toSeq);
889        }
890
891        /**
892         * Create a new {@code Seq} from the given values.
893         *
894         * @param <T> the element type
895         * @param values the array values.
896         * @return a new {@code Seq} with the given values.
897         * @throws NullPointerException if the {@code values} array is {@code null}.
898         */
899        @SafeVarargs
900        static <T> Seq<T> of(final T... values) {
901                return ISeq.of(values);
902        }
903
904        /**
905         * Create a new {@code Seq} from the given values.
906         *
907         * @param <T> the element type
908         * @param values the array values.
909         * @return a new {@code Seq} with the given values.
910         * @throws NullPointerException if the {@code values} array is {@code null}.
911         */
912        static <T> Seq<T> of(final Iterable<? extends T> values) {
913                return ISeq.of(values);
914        }
915
916        /**
917         * Creates a new sequence, which is filled with objects created be the given
918         * {@code supplier}.
919         *
920         * @since 3.3
921         *
922         * @param <T> the element type of the sequence
923         * @param supplier the {@code Supplier} which creates the elements, the
924         *        returned sequence is filled with
925         * @param length the length of the returned sequence
926         * @return a new sequence filled with elements given by the {@code supplier}
927         * @throws NegativeArraySizeException if the given {@code length} is
928         *         negative
929         * @throws NullPointerException if the given {@code supplier} is
930         *         {@code null}
931         */
932        static <T> Seq<T> of(Supplier<? extends T> supplier, final int length) {
933                return ISeq.of(supplier, length);
934        }
935
936        /**
937         * Returns a sequence backed by the specified {@code seq}. (Changes to the
938         * given sequence (if writeable) are "write through" to the returned
939         * sequence.) This method acts as a bridge between basic sequences and
940         * sequence-based APIs.
941         *
942         * @since 6.0
943         *
944         * @param seq the basic sequence containing the elements
945         * @param <T> the element type
946         * @return a sequence view of the given {@code seq}
947         * @throws NullPointerException if the given list is {@code null}
948         */
949        static <T> Seq<T> viewOf(final BaseSeq<? extends T> seq) {
950                return seq.isEmpty()
951                        ? empty()
952                        : new SeqView<>(new BaseSeqList<>(seq));
953        }
954
955        /**
956         * Returns a sequence backed by the specified list. (Changes to the given
957         * list are "write through" to the returned sequence.) This method acts
958         * as a bridge between collection-based and sequence-based APIs.
959         *
960         * @since 4.2
961         *
962         * @param list the list containing the elements
963         * @param <T> the element type
964         * @return a sequence view of the given {@code list}
965         * @throws NullPointerException if the given list is {@code null}
966         */
967        static <T> Seq<T> viewOf(final List<? extends T> list) {
968                return list.isEmpty()
969                        ? empty()
970                        : new SeqView<>(list);
971        }
972
973        /**
974         * Returns a fixed-size sequence backed by the specified array. (Changes to
975         * the given array are "write through" to the returned sequence.) This
976         * method acts as a bridge between array-based and sequence-based APIs.
977         *
978         * @since 4.2
979         *
980         * @param array the array containing the sequence elements
981         * @param <T> the element type
982         * @return a sequence view of the given {@code array}
983         * @throws NullPointerException if the given array is {@code null}
984         */
985        static <T> Seq<T> viewOf(final T[] array) {
986                return array.length == 0
987                        ? empty()
988                        : new SeqView<>(Arrays.asList(array));
989        }
990
991}