All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.calcite.linq4j.Linq4j Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF 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.apache.calcite.linq4j;

import org.apache.calcite.linq4j.function.Function1;

import org.checkerframework.checker.nullness.qual.Nullable;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.RandomAccess;

/**
 * Utility and factory methods for Linq4j.
 */
public abstract class Linq4j {
  private Linq4j() {}

  private static final Object DUMMY = new Object();

  public static @Nullable Method getMethod(String className, String methodName,
      Class... parameterTypes) {
    try {
      return Class.forName(className).getMethod(methodName, parameterTypes);
    } catch (NoSuchMethodException | ClassNotFoundException e) {
      return null;
    }
  }

  /**
   * Query provider that simply executes a {@link Queryable} by calling its
   * enumerator method; does not attempt optimization.
   */
  public static final QueryProvider DEFAULT_PROVIDER = new QueryProviderImpl() {
    @Override public  Enumerator executeQuery(Queryable queryable) {
      return queryable.enumerator();
    }
  };

  private static final Enumerator EMPTY_ENUMERATOR =
      new Enumerator() {
        @Override public Object current() {
          throw new NoSuchElementException();
        }

        @Override public boolean moveNext() {
          return false;
        }

        @Override public void reset() {
        }

        @Override public void close() {
        }
      };

  public static final Enumerable EMPTY_ENUMERABLE =
      new AbstractEnumerable() {
        @Override public Enumerator enumerator() {
          return EMPTY_ENUMERATOR;
        }
      };

  /**
   * Adapter that converts an enumerator into an iterator.
   *
   * 

WARNING: The iterator returned by this method does not call * {@link org.apache.calcite.linq4j.Enumerator#close()}, so it is not safe to * use with an enumerator that allocates resources. * * @param enumerator Enumerator * @param Element type * * @return Iterator */ public static Iterator enumeratorIterator(Enumerator enumerator) { return new EnumeratorIterator<>(enumerator); } /** * Adapter that converts an iterable into an enumerator. * * @param iterable Iterable * @param Element type * * @return enumerator */ public static Enumerator iterableEnumerator( final Iterable iterable) { if (iterable instanceof Enumerable) { @SuppressWarnings("unchecked") final Enumerable enumerable = (Enumerable) iterable; return enumerable.enumerator(); } return new IterableEnumerator<>(iterable); } /** * Adapter that converts an {@link List} into an {@link Enumerable}. * * @param list List * @param Element type * * @return enumerable */ public static Enumerable asEnumerable(final List list) { return new ListEnumerable<>(list); } /** * Adapter that converts an {@link Collection} into an {@link Enumerable}. * *

It uses more efficient implementations if the iterable happens to * be a {@link List}. * * @param collection Collection * @param Element type * * @return enumerable */ public static Enumerable asEnumerable(final Collection collection) { if (collection instanceof List) { //noinspection unchecked return asEnumerable((List) collection); } return new CollectionEnumerable<>(collection); } /** * Adapter that converts an {@link Iterable} into an {@link Enumerable}. * *

It uses more efficient implementations if the iterable happens to * be a {@link Collection} or a {@link List}. * * @param iterable Iterable * @param Element type * * @return enumerable */ public static Enumerable asEnumerable(final Iterable iterable) { if (iterable instanceof Collection) { //noinspection unchecked return asEnumerable((Collection) iterable); } return new IterableEnumerable<>(iterable); } /** * Adapter that converts an array into an enumerable. * * @param ts Array * @param Element type * * @return enumerable */ public static Enumerable asEnumerable(final T[] ts) { return new ListEnumerable<>(Arrays.asList(ts)); } /** * Adapter that converts a collection into an enumerator. * * @param values Collection * @param Element type * * @return Enumerator over the collection */ public static Enumerator enumerator(Collection values) { if (values instanceof List && values instanceof RandomAccess) { //noinspection unchecked return listEnumerator((List) values); } return iterableEnumerator(values); } private static Enumerator listEnumerator(List list) { return new ListEnumerator<>(list); } /** Applies a function to each element of an Enumerator. * * @param enumerator Backing enumerator * @param func Transform function * @param Backing element type * @param Element type * @return Enumerator */ public static Enumerator transform(Enumerator enumerator, final Function1 func) { return new TransformedEnumerator(enumerator) { @Override protected E transform(F from) { return func.apply(from); } }; } /** * Converts the elements of a given Iterable to the specified type. * *

This method is implemented by using deferred execution. The immediate * return value is an object that stores all the information that is * required to perform the action. The query represented by this method is * not executed until the object is enumerated either by calling its * {@link Enumerable#enumerator} method directly or by using * {@code for (... in ...)}. * *

Since standard Java {@link Collection} objects implement the * {@link Iterable} interface, the {@code cast} method enables the standard * query operators to be invoked on collections * (including {@link java.util.List} and {@link java.util.Set}) by supplying * the necessary type information. For example, {@link ArrayList} does not * implement {@link Enumerable}<F>, but you can invoke * *

Linq4j.cast(list, Integer.class)
* *

to convert the list of an enumerable that can be queried using the * standard query operators. * *

If an element cannot be cast to type <TResult>, this method will * throw a {@link ClassCastException}. To obtain only those elements that * can be cast to type TResult, use the {@link #ofType} method instead. * * @see Enumerable#cast(Class) * @see #ofType * @see #asEnumerable(Iterable) */ public static Enumerable cast( Iterable source, Class clazz) { return asEnumerable(source).cast(clazz); } /** * Returns elements of a given {@link Iterable} that are of the specified * type. * *

This method is implemented by using deferred execution. The immediate * return value is an object that stores all the information that is * required to perform the action. The query represented by this method is * not executed until the object is enumerated either by calling its * {@link Enumerable#enumerator} method directly or by using * {@code for (... in ...)}. * *

The {@code ofType} method returns only those elements in source that * can be cast to type TResult. To instead receive an exception if an * element cannot be cast to type TResult, use * {@link #cast(Iterable, Class)}. * *

Since standard Java {@link Collection} objects implement the * {@link Iterable} interface, the {@code cast} method enables the standard * query operators to be invoked on collections * (including {@link java.util.List} and {@link java.util.Set}) by supplying * the necessary type information. For example, {@link ArrayList} does not * implement {@link Enumerable}<F>, but you can invoke * *

Linq4j.ofType(list, Integer.class)
* *

to convert the list of an enumerable that can be queried using the * standard query operators. * * @see Enumerable#cast(Class) * @see #cast */ public static Enumerable ofType( Iterable source, Class clazz) { return asEnumerable(source).ofType(clazz); } /** * Returns an {@link Enumerable} that has one element. * * @param Element type * * @return Singleton enumerable */ public static Enumerable singletonEnumerable(final T element) { return new AbstractEnumerable() { @Override public Enumerator enumerator() { return singletonEnumerator(element); } }; } /** * Returns an {@link Enumerator} that has one element. * * @param Element type * * @return Singleton enumerator */ public static Enumerator singletonEnumerator(T element) { return new SingletonEnumerator<>(element); } /** * Returns an {@link Enumerator} that has one null element. * * @param Element type * * @return Singleton enumerator */ public static Enumerator singletonNullEnumerator() { return new SingletonNullEnumerator<>(); } /** * Returns an {@link Enumerable} that has no elements. * * @param Element type * * @return Empty enumerable */ public static Enumerable emptyEnumerable() { //noinspection unchecked return (Enumerable) EMPTY_ENUMERABLE; } /** * Returns an {@link Enumerator} that has no elements. * * @param Element type * * @return Empty enumerator */ public static Enumerator emptyEnumerator() { //noinspection unchecked return (Enumerator) EMPTY_ENUMERATOR; } /** * Concatenates two or more {@link Enumerable}s to form a composite * enumerable that contains the union of their elements. * * @param enumerableList List of enumerable objects * @param Element type * * @return Composite enumerator */ public static Enumerable concat( final List> enumerableList) { return new CompositeEnumerable<>(enumerableList); } /** * Returns an enumerator that is the cartesian product of the given * enumerators. * *

For example, given enumerator A that returns {"a", "b", "c"} and * enumerator B that returns {"x", "y"}, product(List(A, B)) will return * {List("a", "x"), List("a", "y"), * List("b", "x"), List("b", "y"), * List("c", "x"), List("c", "y")}. * *

Notice that the cardinality of the result is the product of the * cardinality of the inputs. The enumerators A and B have 3 and 2 * elements respectively, and the result has 3 * 2 = 6 elements. * This is always the case. In * particular, if any of the enumerators is empty, the result is empty. * * @param enumerators List of enumerators * @param Element type * * @return Enumerator over the cartesian product */ public static Enumerator> product( List> enumerators) { return new CartesianProductListEnumerator<>(enumerators); } /** Returns the cartesian product of an iterable of iterables. */ public static Iterable> product( final Iterable> iterables) { return () -> { final List> enumerators = new ArrayList<>(); for (Iterable iterable : iterables) { enumerators.add(iterableEnumerator(iterable)); } return enumeratorIterator( new CartesianProductListEnumerator<>(enumerators)); }; } /** * Returns whether the arguments are equal to each other. * *

Equivalent to {@link java.util.Objects#equals} in JDK 1.7 and above. */ @Deprecated // to be removed before 2.0 public static boolean equals(T t0, T t1) { return Objects.equals(t0, t1); } /** * Throws {@link NullPointerException} if argument is null, otherwise * returns argument. * *

Equivalent to {@link java.util.Objects#requireNonNull} in JDK 1.7 and * above. */ @Deprecated // to be removed before 2.0 public static T requireNonNull(T o) { if (o == null) { throw new NullPointerException(); } return o; } /** Closes an iterator, if it can be closed. */ private static void closeIterator(@Nullable Iterator iterator) { if (iterator instanceof AutoCloseable) { try { ((AutoCloseable) iterator).close(); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } } /** Iterable enumerator. * * @param element type */ @SuppressWarnings("unchecked") static class IterableEnumerator implements Enumerator { private final Iterable iterable; @Nullable Iterator iterator; T current; IterableEnumerator(Iterable iterable) { this.iterable = iterable; iterator = iterable.iterator(); current = (T) DUMMY; } @Override public T current() { if (current == DUMMY) { throw new NoSuchElementException(); } return current; } @Override public boolean moveNext() { if (Objects.requireNonNull(iterator, "iterator").hasNext()) { current = iterator.next(); return true; } current = (T) DUMMY; return false; } @Override public void reset() { iterator = iterable.iterator(); current = (T) DUMMY; } @Override public void close() { final Iterator iterator1 = this.iterator; this.iterator = null; closeIterator(iterator1); } } /** Composite enumerable. * * @param element type */ static class CompositeEnumerable extends AbstractEnumerable { private final List> enumerableList; CompositeEnumerable(List> enumerableList) { this.enumerableList = enumerableList; } @Override public Enumerator enumerator() { return new Enumerator() { // Never null. Enumerator current = emptyEnumerator(); final Enumerator> enumerableEnumerator = iterableEnumerator(enumerableList); @Override public E current() { return current.current(); } @Override public boolean moveNext() { for (;;) { if (current.moveNext()) { return true; } current.close(); if (!enumerableEnumerator.moveNext()) { current = emptyEnumerator(); return false; } current = enumerableEnumerator.current().enumerator(); } } @Override public void reset() { enumerableEnumerator.reset(); current = emptyEnumerator(); } @Override public void close() { current.close(); current = emptyEnumerator(); } }; } } /** Iterable enumerable. * * @param element type */ static class IterableEnumerable extends AbstractEnumerable2 { protected final Iterable iterable; IterableEnumerable(Iterable iterable) { this.iterable = iterable; } @Override public Iterator iterator() { return iterable.iterator(); } @Override public boolean any() { return iterable.iterator().hasNext(); } } /** Collection enumerable. * * @param element type */ static class CollectionEnumerable extends IterableEnumerable { CollectionEnumerable(Collection iterable) { super(iterable); } protected Collection getCollection() { return (Collection) iterable; } @Override public int count() { return getCollection().size(); } @Override public long longCount() { return getCollection().size(); } @SuppressWarnings("argument.type.incompatible") @Override public boolean contains(T element) { return getCollection().contains(element); } @Override public boolean any() { return !getCollection().isEmpty(); } } /** List enumerable. * * @param element type */ static class ListEnumerable extends CollectionEnumerable { ListEnumerable(List list) { super(list); } @Override public Enumerator enumerator() { if (iterable instanceof RandomAccess) { //noinspection unchecked return new ListEnumerator<>((List) iterable); } return super.enumerator(); } @Override public List toList() { return (List) iterable; } @Override public Enumerable skip(int count) { final List list = toList(); if (count >= list.size()) { return Linq4j.emptyEnumerable(); } return new ListEnumerable<>(list.subList(count, list.size())); } @Override public Enumerable take(int count) { final List list = toList(); if (count >= list.size()) { return this; } return new ListEnumerable<>(list.subList(0, count)); } @Override public T elementAt(int index) { return toList().get(index); } } /** Enumerator that returns one element. * * @param element type */ private static class SingletonEnumerator implements Enumerator { final E e; int i = 0; SingletonEnumerator(E e) { this.e = e; } @Override public E current() { return e; } @Override public boolean moveNext() { return i++ == 0; } @Override public void reset() { i = 0; } @Override public void close() { } } /** Enumerator that returns one null element. * * @param element type */ private static class SingletonNullEnumerator<@Nullable E> implements Enumerator { int i = 0; @Override public E current() { return null; } @Override public boolean moveNext() { return i++ == 0; } @Override public void reset() { i = 0; } @Override public void close() { } } /** Iterator that reads from an underlying {@link Enumerator}. * * @param element type */ private static class EnumeratorIterator implements Iterator, AutoCloseable { private final Enumerator enumerator; boolean hasNext; EnumeratorIterator(Enumerator enumerator) { this.enumerator = enumerator; hasNext = enumerator.moveNext(); } @Override public boolean hasNext() { return hasNext; } @Override public T next() { T t = enumerator.current(); hasNext = enumerator.moveNext(); return t; } @Override public void remove() { throw new UnsupportedOperationException(); } @Override public void close() { enumerator.close(); } } /** Enumerator optimized for random-access list. * * @param element type */ private static class ListEnumerator implements Enumerator { private final List list; int i = -1; ListEnumerator(List list) { this.list = list; } @Override public V current() { return list.get(i); } @Override public boolean moveNext() { return ++i < list.size(); } @Override public void reset() { i = -1; } @Override public void close() { } } /** Enumerates over the cartesian product of the given lists, returning * a list for each row. * * @param element type */ private static class CartesianProductListEnumerator extends CartesianProductEnumerator> { CartesianProductListEnumerator(List> enumerators) { super(enumerators); } @Override public List current() { return Arrays.asList(elements.clone()); } } }