TextElementSequence.java
/*
* Copyright (C) 2007-2010 J��lio Vilmar Gesser.
* Copyright (C) 2011, 2013-2026 The JavaParser Team.
*
* This file is part of JavaParser.
*
* JavaParser can be used either under the terms of
* a) the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* b) the terms of the Apache License
*
* You should have received a copy of both licenses in LICENCE.LGPL and
* LICENCE.APACHE. Please refer to those files for details.
*
* JavaParser is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*/
package com.github.javaparser.printer.lexicalpreservation;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Stream;
/**
* Contract for a specialized sequence of TextElements with enhanced search
* and modification capabilities for lexical preservation operations.
*
* <p>Unlike standard {@link List}, this interface provides:
* <ul>
* <li>Index-based search with predicates (findFirst, findLast, findNext, findPrevious)</li>
* <li>Element-based search (indexOf, lastIndexOf with overloads)</li>
* <li>Controlled mutations (insert, remove) where caller manages index adjustments</li>
* </ul>
*
* <p><b>Thread safety:</b> Implementations are not required to be thread-safe.
*
* <p><b>Index management:</b> Mutation operations modify the underlying list directly.
* Callers are responsible for tracking index changes after mutations.
*
* @since 3.28.0
*/
public interface TextElementSequence {
// === SEARCH BY PREDICATE ===
/**
* Finds the first index where the predicate matches, searching forward from index 0.
*
* @param predicate the condition to test
* @return the first matching index, or -1 if no match found
* @throws NullPointerException if predicate is null
*/
int findFirst(Predicate<TextElement> predicate);
/**
* Finds the last index where the predicate matches, searching backward from the end.
*
* @param predicate the condition to test
* @return the last matching index, or -1 if no match found
* @throws NullPointerException if predicate is null
*/
int findLast(Predicate<TextElement> predicate);
/**
* Finds the next index where the predicate matches, searching forward from fromIndex (inclusive).
*
* @param fromIndex the starting index (inclusive)
* @param predicate the condition to test
* @return the next matching index, or -1 if no match found
* @throws NullPointerException if predicate is null
*/
int findNext(int fromIndex, Predicate<TextElement> predicate);
/**
* Finds the previous index where the predicate matches, searching backward from fromIndex (inclusive).
*
* @param fromIndex the starting index (inclusive)
* @param predicate the condition to test
* @return the previous matching index, or -1 if no match found
* @throws NullPointerException if predicate is null
*/
int findPrevious(int fromIndex, Predicate<TextElement> predicate);
// === MATCHING (TERMINAL OPERATIONS) ===
/**
* Tests whether any element in this sequence matches the given predicate.
*
* <p>This is a short-circuiting terminal operation: it stops as soon as
* a matching element is found and returns true immediately.
*
* <p>Examples:
* <pre>{@code
* // Check if list contains any comment
* boolean hasComment = list.anyMatch(TextElement::isComment);
*
* // Check if list contains any token with specific text
* boolean hasIdentifier = list.anyMatch(el ->
* el instanceof TokenTextElement &&
* ((TokenTextElement) el).getText().equals("myVar")
* );
* }</pre>
*
* @param predicate the predicate to test elements against
* @return true if any element matches the predicate, false otherwise
* (returns false for empty sequences)
* @throws NullPointerException if predicate is null
*/
boolean anyMatch(Predicate<TextElement> predicate);
/**
* Tests whether all elements in this sequence match the given predicate.
*
* <p>This is a short-circuiting terminal operation: it stops as soon as
* a non-matching element is found and returns false immediately.
*
* <p>Returns true for empty sequences (vacuous truth).
*
* <p>Examples:
* <pre>{@code
* // Check if all elements are whitespace
* boolean allWhitespace = list.allMatch(TextElement::isSpaceOrTab);
*
* // Check if all elements are comments
* boolean allComments = list.allMatch(TextElement::isComment);
* }</pre>
*
* @param predicate the predicate to test elements against
* @return true if all elements match the predicate (or sequence is empty),
* false otherwise
* @throws NullPointerException if predicate is null
*/
boolean allMatch(Predicate<TextElement> predicate);
/**
* Tests whether no elements in this sequence match the given predicate.
*
* <p>This is a short-circuiting terminal operation: it stops as soon as
* a matching element is found and returns false immediately.
*
* <p>Returns true for empty sequences.
*
* <p>Equivalent to {@code !anyMatch(predicate)}.
*
* <p>Examples:
* <pre>{@code
* // Check if list has no comments
* boolean noComments = list.noneMatch(TextElement::isComment);
*
* // Check if list has no newlines
* boolean noNewlines = list.noneMatch(TextElement::isNewline);
* }</pre>
*
* @param predicate the predicate to test elements against
* @return true if no elements match the predicate (or sequence is empty),
* false otherwise
* @throws NullPointerException if predicate is null
*/
boolean noneMatch(Predicate<TextElement> predicate);
// === SEARCH BY ELEMENT ===
/**
* Finds the first occurrence of the specified element.
* Equivalent to {@code findFirst(e -> Objects.equals(e, element))}.
*
* @param element the element to search for (may be null)
* @return the first occurrence index, or -1 if not found
*/
default int indexOf(TextElement element) {
return findFirst(e -> Objects.equals(e, element));
}
/**
* Finds the last occurrence of the specified element.
* Equivalent to {@code findLast(e -> Objects.equals(e, element))}.
*
* @param element the element to search for (may be null)
* @return the last occurrence index, or -1 if not found
*/
default int lastIndexOf(TextElement element) {
return findLast(e -> Objects.equals(e, element));
}
/**
* Finds the next occurrence of element starting from fromIndex (inclusive).
* Equivalent to {@code findNext(fromIndex, e -> Objects.equals(e, element))}.
*
* @param fromIndex the starting index (inclusive)
* @param element the element to search for (may be null)
* @return the next occurrence index, or -1 if not found
*/
default int indexOf(int fromIndex, TextElement element) {
return findNext(fromIndex, e -> Objects.equals(e, element));
}
/**
* Finds the previous occurrence of element before fromIndex (inclusive).
* Equivalent to {@code findPrevious(fromIndex, e -> Objects.equals(e, element))}.
*
* @param fromIndex the starting index (inclusive)
* @param element the element to search for (may be null)
* @return the previous occurrence index, or -1 if not found
*/
default int lastIndexOf(int fromIndex, TextElement element) {
return findPrevious(fromIndex, e -> Objects.equals(e, element));
}
// === FILTERING ===
/**
* Returns a new list containing elements from the start until the predicate fails.
* The returned list is independent of this sequence.
*
* @param predicate the condition to test
* @return a new list of matching elements
* @throws NullPointerException if predicate is null
*/
List<TextElement> takeWhile(Predicate<TextElement> predicate);
/**
* Returns a sublist view [fromIndex, toIndex).
* The returned list is backed by this sequence, so changes affect both.
*
* @param fromIndex low endpoint (inclusive)
* @param toIndex high endpoint (exclusive)
* @return a sublist view
* @throws IndexOutOfBoundsException if indices are out of range
*/
List<TextElement> subList(int fromIndex, int toIndex);
// === MUTATION ===
/**
* Inserts element at the specified index.
* <b>WARNING:</b> Caller must adjust subsequent indices manually.
*
* @param index position to insert at
* @param element element to insert
* @throws IndexOutOfBoundsException if index is out of range
* @throws NullPointerException if element is null
*/
void insert(int index, TextElement element);
/**
* Inserts all elements at the specified index.
* <b>WARNING:</b> Caller must adjust subsequent indices manually.
*
* @param index position to insert at
* @param elements elements to insert
* @throws IndexOutOfBoundsException if index is out of range
* @throws NullPointerException if elements is null
*/
void insertAll(int index, List<TextElement> elements);
/**
* Removes the element at the specified index.
* <b>WARNING:</b> Caller must adjust subsequent indices manually.
*
* @param index position to remove from
* @throws IndexOutOfBoundsException if index is out of range
*/
void remove(int index);
/**
* Removes elements in range [fromIndex, toIndex] (inclusive on both ends).
* <b>WARNING:</b> Caller must adjust subsequent indices manually.
*
* @param fromIndex start of range (inclusive)
* @param toIndex end of range (inclusive)
* @throws IndexOutOfBoundsException if indices are out of range or fromIndex > toIndex
*/
void removeRange(int fromIndex, int toIndex);
// === ACCESS ===
/**
* Returns the element at the specified index.
*
* @param index the index
* @return the element at that position
* @throws IndexOutOfBoundsException if index is out of range
*/
TextElement get(int index);
/**
* Checks if the index is valid (0 <= index < size).
*
* @param index the index to check
* @return true if index is valid
*/
boolean isValidIndex(int index);
/**
* Returns the number of elements in this sequence.
*
* @return the size
*/
int size();
/**
* Checks if this sequence is empty.
*
* @return true if size is 0
*/
boolean isEmpty();
/**
* Returns an unmodifiable view of the underlying list.
* Changes to the original list are visible in the returned view.
*
* @return an unmodifiable list view
*/
List<TextElement> toList();
/**
* Returns the underlying mutable list.
*
* <p><b>WARNING:</b> This exposes the internal list directly.
* Modifications will affect this sequence.
*
* @return the mutable list
*/
List<TextElement> toMutableList();
// === ITERATION ===
/**
* Returns an iterator starting at the specified index.
*
* @param fromIndex the starting position
* @return an iterator with position tracking
* @throws IndexOutOfBoundsException if fromIndex is out of range
*/
TextElementIterator iterator(int fromIndex);
/**
* Returns an iterator starting at index 0.
*
* @return an iterator from the beginning
*/
default TextElementIterator iterator() {
return iterator(0);
}
/**
* Returns a stream of elements for functional operations.
*
* @return a stream over the elements
*/
default Stream<TextElement> stream() {
return toList().stream();
}
}