
org.elasticsearch.painless.Augmentation Maven / Gradle / Ivy
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you 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 org.elasticsearch.painless;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.ObjIntConsumer;
import java.util.function.Predicate;
import java.util.function.ToDoubleFunction;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** Additional methods added to classes. These must be static methods with receiver as first argument */
public class Augmentation {
// static methods only!
private Augmentation() {}
/** Exposes List.size() as getLength(), so that .length shortcut works on lists */
public static int getLength(List receiver) {
return receiver.size();
}
/** Exposes Matcher.group(String) as namedGroup(String), so it doesn't conflict with group(int) */
public static String namedGroup(Matcher receiver, String name) {
return receiver.group(name);
}
// some groovy methods on iterable
// see http://docs.groovy-lang.org/latest/html/groovy-jdk/java/lang/Iterable.html
/** Iterates over the contents of an iterable, and checks whether a predicate is valid for at least one element. */
public static boolean any(Iterable receiver, Predicate predicate) {
for (T t : receiver) {
if (predicate.test(t)) {
return true;
}
}
return false;
}
/** Converts this Iterable to a Collection. Returns the original Iterable if it is already a Collection. */
public static Collection asCollection(Iterable receiver) {
if (receiver instanceof Collection) {
return (Collection)receiver;
}
List list = new ArrayList<>();
for (T t : receiver) {
list.add(t);
}
return list;
}
/** Converts this Iterable to a List. Returns the original Iterable if it is already a List. */
public static List asList(Iterable receiver) {
if (receiver instanceof List) {
return (List)receiver;
}
List list = new ArrayList<>();
for (T t : receiver) {
list.add(t);
}
return list;
}
/** Counts the number of occurrences which satisfy the given predicate from inside this Iterable. */
public static int count(Iterable receiver, Predicate predicate) {
int count = 0;
for (T t : receiver) {
if (predicate.test(t)) {
count++;
}
}
return count;
}
// instead of covariant overrides for every possibility, we just return receiver as 'def' for now
// that way if someone chains the calls, everything works.
/** Iterates through an Iterable, passing each item to the given consumer. */
public static Object each(Iterable receiver, Consumer consumer) {
receiver.forEach(consumer);
return receiver;
}
/**
* Iterates through an iterable type, passing each item and the item's index
* (a counter starting at zero) to the given consumer.
*/
public static Object eachWithIndex(Iterable receiver, ObjIntConsumer consumer) {
int count = 0;
for (T t : receiver) {
consumer.accept(t, count++);
}
return receiver;
}
/**
* Used to determine if the given predicate is valid (i.e. returns true for all items in this iterable).
*/
public static boolean every(Iterable receiver, Predicate predicate) {
for (T t : receiver) {
if (predicate.test(t) == false) {
return false;
}
}
return true;
}
/**
* Iterates through the Iterable transforming items using the supplied function and
* collecting any non-null results.
*/
public static List findResults(Iterable receiver, Function filter) {
List list = new ArrayList<>();
for (T t: receiver) {
U result = filter.apply(t);
if (result != null) {
list.add(result);
}
}
return list;
}
/**
* Sorts all Iterable members into groups determined by the supplied mapping function.
*/
public static Map> groupBy(Iterable receiver, Function mapper) {
Map> map = new LinkedHashMap<>();
for (T t : receiver) {
U mapped = mapper.apply(t);
List results = map.get(mapped);
if (results == null) {
results = new ArrayList<>();
map.put(mapped, results);
}
results.add(t);
}
return map;
}
/**
* Concatenates the toString() representation of each item in this Iterable,
* with the given String as a separator between each item.
*/
public static String join(Iterable receiver, String separator) {
StringBuilder sb = new StringBuilder();
for (T t : receiver) {
if (sb.length() > 0) {
sb.append(separator);
}
sb.append(t);
}
return sb.toString();
}
/**
* Sums the result of an Iterable
*/
public static double sum(Iterable receiver) {
double sum = 0;
for (T t : receiver) {
sum += t.doubleValue();
}
return sum;
}
/**
* Sums the result of applying a function to each item of an Iterable.
*/
public static double sum(Iterable receiver, ToDoubleFunction function) {
double sum = 0;
for (T t : receiver) {
sum += function.applyAsDouble(t);
}
return sum;
}
// some groovy methods on collection
// see http://docs.groovy-lang.org/latest/html/groovy-jdk/java/util/Collection.html
/**
* Iterates through this collection transforming each entry into a new value using
* the function, returning a list of transformed values.
*/
public static List collect(Collection receiver, Function function) {
List list = new ArrayList<>();
for (T t : receiver) {
list.add(function.apply(t));
}
return list;
}
/**
* Iterates through this collection transforming each entry into a new value using
* the function, adding the values to the specified collection.
*/
public static Object collect(Collection receiver, Collection collection, Function function) {
for (T t : receiver) {
collection.add(function.apply(t));
}
return collection;
}
/**
* Finds the first value matching the predicate, or returns null.
*/
public static T find(Collection receiver, Predicate predicate) {
for (T t : receiver) {
if (predicate.test(t)) {
return t;
}
}
return null;
}
/**
* Finds all values matching the predicate, returns as a list
*/
public static List findAll(Collection receiver, Predicate predicate) {
List list = new ArrayList<>();
for (T t : receiver) {
if (predicate.test(t)) {
list.add(t);
}
}
return list;
}
/**
* Iterates through the collection calling the given function for each item
* but stopping once the first non-null result is found and returning that result.
* If all results are null, null is returned.
*/
public static Object findResult(Collection receiver, Function function) {
return findResult(receiver, null, function);
}
/**
* Iterates through the collection calling the given function for each item
* but stopping once the first non-null result is found and returning that result.
* If all results are null, defaultResult is returned.
*/
public static Object findResult(Collection receiver, Object defaultResult, Function function) {
for (T t : receiver) {
U value = function.apply(t);
if (value != null) {
return value;
}
}
return defaultResult;
}
/**
* Splits all items into two collections based on the predicate.
* The first list contains all items which match the closure expression. The second list all those that don't.
*/
public static List> split(Collection receiver, Predicate predicate) {
List matched = new ArrayList<>();
List unmatched = new ArrayList<>();
List> result = new ArrayList<>(2);
result.add(matched);
result.add(unmatched);
for (T t : receiver) {
if (predicate.test(t)) {
matched.add(t);
} else {
unmatched.add(t);
}
}
return result;
}
// some groovy methods on map
// see http://docs.groovy-lang.org/latest/html/groovy-jdk/java/util/Map.html
/**
* Iterates through this map transforming each entry into a new value using
* the function, returning a list of transformed values.
*/
public static List collect(Map receiver, BiFunction function) {
List list = new ArrayList<>();
for (Map.Entry kvPair : receiver.entrySet()) {
list.add(function.apply(kvPair.getKey(), kvPair.getValue()));
}
return list;
}
/**
* Iterates through this map transforming each entry into a new value using
* the function, adding the values to the specified collection.
*/
public static Object collect(Map receiver, Collection collection, BiFunction function) {
for (Map.Entry kvPair : receiver.entrySet()) {
collection.add(function.apply(kvPair.getKey(), kvPair.getValue()));
}
return collection;
}
/** Counts the number of occurrences which satisfy the given predicate from inside this Map */
public static int count(Map receiver, BiPredicate predicate) {
int count = 0;
for (Map.Entry kvPair : receiver.entrySet()) {
if (predicate.test(kvPair.getKey(), kvPair.getValue())) {
count++;
}
}
return count;
}
/** Iterates through a Map, passing each item to the given consumer. */
public static Object each(Map receiver, BiConsumer consumer) {
receiver.forEach(consumer);
return receiver;
}
/**
* Used to determine if the given predicate is valid (i.e. returns true for all items in this map).
*/
public static boolean every(Map receiver, BiPredicate predicate) {
for (Map.Entry kvPair : receiver.entrySet()) {
if (predicate.test(kvPair.getKey(), kvPair.getValue()) == false) {
return false;
}
}
return true;
}
/**
* Finds the first entry matching the predicate, or returns null.
*/
public static Map.Entry find(Map receiver, BiPredicate predicate) {
for (Map.Entry kvPair : receiver.entrySet()) {
if (predicate.test(kvPair.getKey(), kvPair.getValue())) {
return kvPair;
}
}
return null;
}
/**
* Finds all values matching the predicate, returns as a map.
*/
public static Map findAll(Map receiver, BiPredicate predicate) {
// try to preserve some properties of the receiver (see the groovy javadocs)
final Map map;
if (receiver instanceof TreeMap) {
map = new TreeMap<>();
} else {
map = new LinkedHashMap<>();
}
for (Map.Entry kvPair : receiver.entrySet()) {
if (predicate.test(kvPair.getKey(), kvPair.getValue())) {
map.put(kvPair.getKey(), kvPair.getValue());
}
}
return map;
}
/**
* Iterates through the map calling the given function for each item
* but stopping once the first non-null result is found and returning that result.
* If all results are null, null is returned.
*/
public static Object findResult(Map receiver, BiFunction function) {
return findResult(receiver, null, function);
}
/**
* Iterates through the map calling the given function for each item
* but stopping once the first non-null result is found and returning that result.
* If all results are null, defaultResult is returned.
*/
public static Object findResult(Map receiver, Object defaultResult, BiFunction function) {
for (Map.Entry kvPair : receiver.entrySet()) {
T value = function.apply(kvPair.getKey(), kvPair.getValue());
if (value != null) {
return value;
}
}
return defaultResult;
}
/**
* Iterates through the map transforming items using the supplied function and
* collecting any non-null results.
*/
public static List findResults(Map receiver, BiFunction filter) {
List list = new ArrayList<>();
for (Map.Entry kvPair : receiver.entrySet()) {
T result = filter.apply(kvPair.getKey(), kvPair.getValue());
if (result != null) {
list.add(result);
}
}
return list;
}
/**
* Sorts all Map members into groups determined by the supplied mapping function.
*/
public static Map> groupBy(Map receiver, BiFunction mapper) {
Map> map = new LinkedHashMap<>();
for (Map.Entry kvPair : receiver.entrySet()) {
T mapped = mapper.apply(kvPair.getKey(), kvPair.getValue());
Map results = map.get(mapped);
if (results == null) {
// try to preserve some properties of the receiver (see the groovy javadocs)
if (receiver instanceof TreeMap) {
results = new TreeMap<>();
} else {
results = new LinkedHashMap<>();
}
map.put(mapped, results);
}
results.put(kvPair.getKey(), kvPair.getValue());
}
return map;
}
// CharSequence augmentation
/**
* Replace all matches. Similar to {@link Matcher#replaceAll(String)} but allows you to customize the replacement based on the match.
*/
public static String replaceAll(CharSequence receiver, Pattern pattern, Function replacementBuilder) {
Matcher m = pattern.matcher(receiver);
if (false == m.find()) {
// CharSequqence's toString is *supposed* to always return the characters in the sequence as a String
return receiver.toString();
}
StringBuffer result = new StringBuffer(initialBufferForReplaceWith(receiver));
do {
m.appendReplacement(result, Matcher.quoteReplacement(replacementBuilder.apply(m)));
} while (m.find());
m.appendTail(result);
return result.toString();
}
/**
* Replace the first match. Similar to {@link Matcher#replaceFirst(String)} but allows you to customize the replacement based on the
* match.
*/
public static String replaceFirst(CharSequence receiver, Pattern pattern, Function replacementBuilder) {
Matcher m = pattern.matcher(receiver);
if (false == m.find()) {
// CharSequqence's toString is *supposed* to always return the characters in the sequence as a String
return receiver.toString();
}
StringBuffer result = new StringBuffer(initialBufferForReplaceWith(receiver));
m.appendReplacement(result, Matcher.quoteReplacement(replacementBuilder.apply(m)));
m.appendTail(result);
return result.toString();
}
/**
* The initial size of the {@link StringBuilder} used for {@link #replaceFirst(CharSequence, Pattern, Function)} and
* {@link #replaceAll(CharSequence, Pattern, Function)} for a particular sequence. We ape
* {{@link StringBuilder#StringBuilder(CharSequence)} here and add 16 extra chars to the buffer to have a little room for growth.
*/
private static int initialBufferForReplaceWith(CharSequence seq) {
return seq.length() + 16;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy