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

com.github.tonivade.purefun.data.ImmutableTree Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2018-2024, Antonio Gabriel Muñoz Conejo 
 * Distributed under the terms of the MIT License
 */
package com.github.tonivade.purefun.data;

import static com.github.tonivade.purefun.core.Precondition.checkNonNull;
import static java.util.stream.Collectors.collectingAndThen;
import com.github.tonivade.purefun.Kind;
import com.github.tonivade.purefun.core.Equal;
import com.github.tonivade.purefun.core.Function1;
import com.github.tonivade.purefun.core.Matcher1;
import com.github.tonivade.purefun.type.Option;
import com.github.tonivade.purefun.type.Try;
import java.io.Serial;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.NavigableSet;
import java.util.Objects;
import java.util.SequencedSet;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.pcollections.PSortedSet;
import org.pcollections.TreePSet;

/**
 * Similar to a TreeSet
 * @param  the type of elements in this tree
 */
public interface ImmutableTree extends Sequence {

  Comparator comparator();

  NavigableSet toNavigableSet();

  default SequencedSet toSequencedSet() {
    return toNavigableSet();
  }

  default SortedSet toSortedSet() {
    return toNavigableSet();
  }

  @Override
  ImmutableTree append(E element);
  @Override
  ImmutableTree remove(E element);
  @Override
  ImmutableTree appendAll(Sequence other);
  @Override
  ImmutableTree removeAll(Sequence other);

  @Override
  ImmutableTree reverse();

  Option head();
  Option tail();
  ImmutableTree headTree(E value);
  ImmutableTree tailTree(E value);
  Option higher(E value);
  Option lower(E value);
  Option ceiling(E value);
  Option floor(E value);

  @Override
  default  ImmutableTree map(Function1 mapper) {
    return ImmutableTree.from(naturalOrder(), stream().map(mapper::apply));
  }

  default  ImmutableTree map(Comparator comparator, Function1 mapper) {
    return ImmutableTree.from(comparator, stream().map(mapper::apply));
  }

  @Override
  default  ImmutableTree flatMap(Function1, ? extends R>> mapper) {
    return ImmutableTree.from(naturalOrder(), stream().flatMap(mapper.andThen(SequenceOf::toSequence).andThen(Sequence::stream)::apply));
  }

  default  ImmutableTree flatMap(Comparator comparator, Function1, ? extends R>> mapper) {
    return ImmutableTree.from(comparator, stream().flatMap(mapper.andThen(SequenceOf::toSequence).andThen(Sequence::stream)::apply));
  }

  @Override
  default ImmutableTree filter(Matcher1 matcher) {
    return ImmutableTree.from(comparator(), stream().filter(matcher::match));
  }

  @Override
  default ImmutableTree filterNot(Matcher1 matcher) {
    return filter(matcher.negate());
  }

  static  ImmutableTree from(Iterable iterable) {
    return from(naturalOrder(), Sequence.asStream(iterable.iterator()));
  }

  static  ImmutableTree from(Comparator comparator, Iterable iterable) {
    return from(comparator, Sequence.asStream(iterable.iterator()));
  }

  static  ImmutableTree from(Stream stream) {
    return new PImmutableTree<>(naturalOrder(), stream.collect(Collectors.toCollection(TreeSet::new)));
  }

  static  ImmutableTree from(Comparator comparator, Stream stream) {
    return new PImmutableTree<>(comparator, stream.collect(Collectors.toCollection(TreeSet::new)));
  }

  @SafeVarargs
  static > ImmutableTree of(T... elements) {
    return new PImmutableTree<>(naturalOrder(), Arrays.asList(elements));
  }

  @SuppressWarnings("unchecked")
  static  ImmutableTree empty() {
    return (ImmutableTree) PImmutableTree.EMPTY;
  }

  static  Collector> toImmutableTree() {
    return collectingAndThen(Collectors.toCollection(TreeSet::new), PImmutableTree::new);
  }

  @SuppressWarnings("unchecked")
  private static  Comparator naturalOrder() {
    return (Comparator) Comparator.naturalOrder();
  }

  final class PImmutableTree implements ImmutableTree, Serializable {

    @Serial
    private static final long serialVersionUID = 3964148260438348347L;

    private static final ImmutableTree EMPTY = new PImmutableTree<>(TreePSet.empty(naturalOrder()));

    private static final Equal> EQUAL =
        Equal.>of().comparing(a -> a.backend);

    private final PSortedSet backend;

    private PImmutableTree(Comparator comparator, Collection backend) {
      this(TreePSet.from(comparator, backend));
    }

    private PImmutableTree(SortedSet backend) {
      this(TreePSet.fromSortedSet(backend));
    }

    private PImmutableTree(PSortedSet backend) {
      this.backend = checkNonNull(backend);
    }

    @SuppressWarnings("unchecked")
    @Override
    public Comparator comparator() {
      return (Comparator) backend.comparator();
    }

    @Override
    public int size() {
      return backend.size();
    }

    @Override
    public boolean contains(Object element) {
      return backend.contains(element);
    }

    @Override
    public ImmutableTree reverse() {
      return new PImmutableTree<>(backend.descendingSet());
    }

    @Override
    public ImmutableTree append(E element) {
      return new PImmutableTree<>(backend.plus(element));
    }

    @Override
    public ImmutableTree remove(E element) {
      return new PImmutableTree<>(backend.minus(element));
    }

    @Override
    public ImmutableTree appendAll(Sequence other) {
      return new PImmutableTree<>(backend.plusAll(other.toCollection()));
    }

    @Override
    public ImmutableTree removeAll(Sequence other) {
      return new PImmutableTree<>(backend.minusAll(other.toCollection()));
    }

    @Override
    public Option head() {
      return Try.of(backend::first).toOption();
    }

    @Override
    public Option tail() {
      return Try.of(backend::last).toOption();
    }

    @Override
    public ImmutableTree headTree(E toElement) {
      return new PImmutableTree<>(backend.headSet(toElement, false));
    }

    @Override
    public ImmutableTree tailTree(E fromElement) {
      return new PImmutableTree<>(backend.tailSet(fromElement, false));
    }

    @Override
    public Option higher(E value) {
      return Option.of(() -> backend.higher(value));
    }

    @Override
    public Option lower(E value) {
      return Option.of(() -> backend.lower(value));
    }

    @Override
    public Option ceiling(E value) {
      return Option.of(() -> backend.ceiling(value));
    }

    @Override
    public Option floor(E value) {
      return Option.of(() -> backend.floor(value));
    }

    @Override
    public Iterator iterator() {
      return backend.iterator();
    }

    @Override
    public NavigableSet toNavigableSet() {
      return new TreeSet<>(backend);
    }

    @Override
    public int hashCode() {
      return Objects.hash(backend);
    }

    @Override
    public boolean equals(Object obj) {
      return EQUAL.applyTo(this, obj);
    }

    @Override
    public String toString() {
      return "ImmutableTree(" + backend + ")";
    }

    @Serial
    private Object readResolve() {
      if (backend.isEmpty()) {
        return EMPTY;
      }
      return this;
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy