<commit_before>/*****************************************************************************
 * ------------------------------------------------------------------------- *
 * Licensed under the Apache License, Version 2.0 (the "License");           *
 * you may not use this file except in compliance with the License.          *
 * You may obtain a copy of the License at                                   *
 *                                                                           *
 * http://www.apache.org/licenses/LICENSE-2.0                                *
 *                                                                           *
 * Unless required by applicable law or agreed to in writing, software       *
 * distributed under the License is distributed on an "AS IS" BASIS,         *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
 * See the License for the specific language governing permissions and       *
 * limitations under the License.                                            *
 *****************************************************************************/
package com.google.mu.util.patternmatch;

import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toList;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Collectors;

/**
 * Utility class to perform functional pattern matching on a list or a stream of input elements.
 *
 * <p>A {@code MatchingCollector} object can both be used as a {@link Collector} for a
 * stream, or as one of several possible patterns passed to the static {@link #match match()} method.
 * For example:
 * <pre>{@code
 *   Path path = match(
 *       pathComponents,
 *       exactly((parent, child) -> ...),
 *       exactly(directory -> ...));
 * }</pre>
 *
 * @since 5.3
 */
public abstract class MatchingCollector<T, R> implements Collector<T, List<T>, R> {
  private static final MatchingCollector<Object, ?> ONLY_ELEMENT = exactly(Function.identity());
  private static final MatchingCollector<Object, ?> FIRST_ELEMENT = atLeast(Function.identity());
  private static final MatchingCollector<Object, Object> LAST_ELEMENT = new MatchingCollector<Object, Object>() {
    @Override boolean matches(List<?> list) {
      return list.size() >= 1;
    }
    @Override Object map(List<?> list) {
      return list.get(list.size() - 1);
    }
    @Override public String toString() {
      return "at least 1 element";
    }
  };
<commit_msg>better MatchingCollector javadoc<commit_after>/*****************************************************************************
 * ------------------------------------------------------------------------- *
 * Licensed under the Apache License, Version 2.0 (the "License");           *
 * you may not use this file except in compliance with the License.          *
 * You may obtain a copy of the License at                                   *
 *                                                                           *
 * http://www.apache.org/licenses/LICENSE-2.0                                *
 *                                                                           *
 * Unless required by applicable law or agreed to in writing, software       *
 * distributed under the License is distributed on an "AS IS" BASIS,         *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
 * See the License for the specific language governing permissions and       *
 * limitations under the License.                                            *
 *****************************************************************************/
package com.google.mu.util.patternmatch;

import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toList;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Collectors;

/**
 * Utility class to perform functional pattern matching on a list or a stream of input elements.
 *
 * <p>A {@code MatchingCollector} object can be used as a {@link Collector} for a stream.
 * For example:
 *
 * <pre>{@code
 *   stream.collect(exactly((a, b, c) -> ...);
 * }</pre>
 *
 * Or as one of several possible patterns passed to the static {@link #matching matching()} method.
 * For example:
 * <pre>{@code
 *   Path path = pathComponents.stream()
 *       .filter(...)
 *       .collect(
 *           matching(
 *               exactly((parent, child) -> ...),
 *               exactly(fileName -> ...),
 *               atLeast(root -> ...),
 *               orElse(l -> ...));
 * }</pre>
 *
 * In the above example, if you have a {@link List} instead of a stream, you can use the static
 * {@link #match match()} method instead to avoid iterating through every list elements:
 * <pre>{@code
 *   Path path = match(
 *       pathComponents,
 *       exactly((parent, child) -> ...),
 *       exactly(fileName -> ...),
 *       atLeast(root -> ...),
 *       orElse(l -> ...));
 * }</pre>
 *
 * @since 5.3
 */
public abstract class MatchingCollector<T, R> implements Collector<T, List<T>, R> {
  private static final MatchingCollector<Object, ?> ONLY_ELEMENT = exactly(Function.identity());
  private static final MatchingCollector<Object, ?> FIRST_ELEMENT = atLeast(Function.identity());
  private static final MatchingCollector<Object, Object> LAST_ELEMENT = new MatchingCollector<Object, Object>() {
    @Override boolean matches(List<?> list) {
      return list.size() >= 1;
    }
    @Override Object map(List<?> list) {
      return list.get(list.size() - 1);
    }
    @Override public String toString() {
      return "at least 1 element";
    }
  };

{'fraction_non_alphanumeric': 0.17306809487375668, 'fraction_numerical': 0.0027543993879112472, 'mean_word_length': 2.372549019607843, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 44, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 18, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5013865', 'n_tokens_mistral': 1616, 'n_tokens_neox': 1594, 'n_words': 514}