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

abs.api.Functional Maven / Gradle / Ivy

package abs.api;

import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * ABS Functional layer as Java 8 API.
 */
public final class Functional {

  private static final Random RANDOM = new Random(Clock.systemUTC().millis());

  /**
   * A pattern matching abstraction in Java 8.
   * 
   * @param 
   * @param 
   */
  public static interface Match extends Function> {

    static  Function> F(Predicate cond, Function what) {
      Function> f =
          (x) -> cond.test(x) ? Optional.ofNullable(what.apply(x)) : Optional.empty();
      return f;
    }

    static  Match of(Predicate cond, Function what) {
      Match m = input -> F(cond, what).apply(input);
      return m;
    }

    static  Match of(Y origin) {
      Predicate cond = ignored -> true;
      Function what = x -> origin;
      return of(cond, what);
    }

    static  Match ofNull(Function what) {
      return of(x -> x == null, what);
    }

    default Match orDefault(Function what) {
      return or(ignored -> true, what);
    }

    default Match or(Predicate cond, Function what) {
      Match orM = input -> {
        Optional thisMatch = apply(input);
        return thisMatch.isPresent() ? thisMatch : of(cond, what).apply(input);
      };
      return orM;
    }

  }

  // --- Arithmetic

  public static  X max(X x, X y) {
    if (x instanceof Comparable == false) {
      return null;
    }
    Comparable cx = (Comparable) x;
    final int c = cx.compareTo(y);
    return c == 0 || c > 1 ? x : y;
  }

  public static  X min(X x, X y) {
    X max = max(x, y);
    return max == null ? null : max == x ? y : x;
  }

  public static int random(int bound) {
    return RANDOM.nextInt(bound);
  }

  // --- Logical

  public static boolean and(boolean a, boolean b) {
    return a && b;
  }

  public static boolean not(boolean a) {
    return !a;
  }

  public static boolean or(boolean a, boolean b) {
    return a || b;
  }

  // --- List

  public static  List emptyList() {
    return new ArrayList<>();
  }

  public static  List insert(E e, List list) {
    return (List) insertCollection(e, list);
  }

  public static  List remove(E e, List list) {
    return (List) removeCollection(e, list);
  }

  public static  List list(Set set) {
    final List list = emptyList();
    if (set == null) {
      return list;
    }
    list.addAll(set);
    return list;
  }

  public static  boolean contains(List list, E e) {
    return containsCollection(e, list);
  }

  public static  int size(List list) {
    return sizeCollection(list);
  }

  public static  boolean isEmpty(List list) {
    return isEmptyCollection(list);
  }

  public static  E get(List list, int index) {
    if (index >= size(list)) {
      throw new IllegalArgumentException("Index is beyond list size: " + index);
    }
    return list.get(index);
  }

  public static  List without(E e, List list) {
    return remove(e, list);
  }

  public static  List concatenate(List list1, List list2) {
    final List result = emptyList();
    result.addAll(list1);
    result.addAll(list2);
    return result;
  }

  public static  List appendRight(E e, List list) {
    list.add(e);
    return list;
  }

  public static  List reverse(List list) {
    Collections.reverse(list);
    return list;
  }

  public static  List copy(final E value, final int n) {
    return IntStream.range(0, n).mapToObj(i -> value).collect(Collectors.toList());
  }

  // --- Set

  public static  Set emptySet() {
    return new HashSet<>();
  }

  public static  Set insert(E e, Set set) {
    return (Set) insertCollection(e, set);
  }

  public static  Set remove(E e, Set set) {
    return (Set) removeCollection(e, set);
  }

  public static  Set set(List list) {
    return set_java(list);
  }

  public static  boolean contains(E e, Set set) {
    return containsCollection(e, set);
  }

  public static  int size(Set set) {
    return sizeCollection(set);
  }

  public static  boolean isEmpty(Set set) {
    return isEmptyCollection(set);
  }

  public static  E take(Set set) {
    return next(set);
  }

  public static  boolean hasNext(Set set) {
    return hastNext(set);
  }

  public static  Set union(Set set1, Set set2) {
    final Set union = emptySet();
    union.addAll(set1);
    union.addAll(set2);
    return union;
  }

  public static  Set intersection(Set set1, Set set2) {
    final Set inter = emptySet();
    inter.addAll(set1);
    inter.retainAll(set2);
    return inter;
  }

  public static  Set difference(Set set1, Set set2) {
    final Set diff = emptySet();
    diff.addAll(set1);
    diff.removeAll(set2);
    return diff;
  }

  // --- Map

  public static  Map emptyMap() {
    return new ConcurrentHashMap<>();
  }

  public static  Map insert(K key, V value, Map map) {
    if (map == null) {
      map = emptyMap();
    }
    map.put(key, value);
    return map;
  }

  public static  Map.Entry pair(K key, V value) {
    return new AbstractMap.SimpleEntry(key, value);
  }

  public static  Map map(List keys, List values) {
    if (keys == null || values == null || keys.size() != values.size()) {
      throw new IllegalArgumentException(
          "Keys and values do not match for map construction: " + keys + " -> " + values);
    }
    ConcurrentMap map = IntStream.range(0, keys.size()).boxed()
        .collect(Collectors.toConcurrentMap(index -> keys.get(index), index -> values.get(index)));
    return map;
  }

  public static  Map map(Collection> entries) {
    return new ArrayList<>(entries).stream().collect(
        Collectors.toConcurrentMap((Entry e) -> e.getKey(), (Entry e) -> e.getValue()));
  }

  public static  Map removeKey(K key, Map map) {
    map.remove(key);
    return map;
  }

  public static  Collection keys(Map map) {
    return map.keySet();
  }

  public static  Collection values(Map map) {
    return map.values();
  }

  public static  Optional lookup(K key, Map map) {
    return Optional.ofNullable(map.get(key));
  }

  public static  V lookupDefault(K key, V defaultValue, Map map) {
    return lookup(key, map).orElse(defaultValue);
  }

  public static  Map insert(Entry pair, Map map) {
    return insert(pair.getKey(), pair.getValue(), map);
  }

  // --- Strings

  public static String substr(String s, int beginIndex, int length) {
    return s.substring(beginIndex, beginIndex + length);
  }

  public static int strlen(String s) {
    return s.length();
  }

  public static  String toString(X x) {
    return Objects.toString(x, "null");
  }

  // --- I/O

  public static void println(String format, Object... args) {
    System.out.println(String.format(format, args));
  }

  public static void println(Object o) {
    System.out.println(o);
  }

  public static void print(Object o) {
    System.out.print(o);
  }

  public static String readln() {
    return System.console().readLine();
  }

  // --- Time

  public static Duration duration(long duration, TimeUnit unit) {
    return Duration.ofMillis(unit.toMillis(duration));
  }

  public static Duration duration(long millis) {
    return Duration.ofMillis(millis);
  }

  public static boolean durationLessThan(Duration d1, Duration d2) {
    return d1.compareTo(d2) < 0;
  }

  public static Duration subtractFromDuration(Duration d, long v) {
    if (isDurationInfinite(d)) {
      return d;
    }
    Duration d2 = d.minusMillis(v);
    return d2.isNegative() || d2.isZero() ? d : d2;
  }

  public static Duration infinity() {
    return ChronoUnit.FOREVER.getDuration();
  }

  public static boolean isDurationInfinite(Duration d) {
    return d == null || infinity().equals(d);
  }

  public static long currentms() {
    return ContextClock.CLOCK.millis();
  }

  public static Instant now() {
    return ContextClock.CLOCK.instant();
  }

  public static long timeDifference(Instant t1, Instant t2) {
    return Duration.between(t1, t2).abs().toMillis();
  }

  public static Instant addDuration(Instant t, Duration d) {
    return t.plus(d);
  }

  public static Instant subtractDuration(Instant t, Duration d) {
    return t.minus(d);
  }

  public static Duration lowlevelDeadline(Long millis) {
    return millis == null || millis <= 0 ? infinity() : duration(millis);
  }

  public static Duration deadline(Duration d) {
    return d;
  }

  public static Duration deadline(Long millis) {
    return lowlevelDeadline(millis);
  }

  // --- Internal

  protected static  Collection insertCollection(E e, Collection col) {
    col.add(e);
    return col;
  }

  protected static  Collection removeCollection(E e, Collection col) {
    col.remove(e);
    return col;
  }

  protected static  boolean containsCollection(E e, Collection col) {
    return col.contains(e);
  }

  protected static  int sizeCollection(Collection col) {
    return col.size();
  }

  protected static  boolean isEmptyCollection(Collection col) {
    return col.isEmpty();
  }

  protected static  E next(Iterable it) {
    return it == null || it.iterator().hasNext() ? null : it.iterator().next();
  }

  protected static  boolean hastNext(Iterable it) {
    return it == null ? false : it.iterator().hasNext();
  }

  protected static  Set set_java(List list) {
    Set set = emptySet();
    if (list == null) {
      return set;
    }
    set.addAll(list);
    return set;
  }

  protected static  Set set_func(List list) {
    Match, Set> m = Match.ofNull((List ignored) -> (Set) emptySet())
        .or(l -> l.isEmpty(), ignored -> emptySet())
        .orDefault((List l) -> insert(l.get(0), set_func(l.subList(1, l.size()))));
    return m.apply(list).get();
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy