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

com.github.tonivade.purefun.data.ImmutableSet 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 java.io.Serial;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.pcollections.HashTreePSet;
import org.pcollections.PSet;

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;

/**
 * Similar to a HashSet
 * @param  the type of elements in this set
 */
public interface ImmutableSet extends Sequence {

  Set toSet();

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

  @Override
  ImmutableSet reverse();

  ImmutableSet union(ImmutableSet other);
  ImmutableSet intersection(ImmutableSet other);
  ImmutableSet difference(ImmutableSet other);

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

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

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

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

  static  ImmutableSet from(Iterable iterable) {
    return from(Sequence.asStream(iterable.iterator()));
  }

  static  ImmutableSet from(Stream stream) {
    ArrayList collect = stream.collect(Collectors.toCollection(ArrayList::new));
    return new PImmutableSet<>(collect);
  }

  @SafeVarargs
  static  ImmutableSet of(T... elements) {
    return from(Arrays.stream(elements));
  }

  @SuppressWarnings("unchecked")
  static  ImmutableSet empty() {
    return (ImmutableSet) PImmutableSet.EMPTY;
  }

  static  Collector> toImmutableSet() {
    return collectingAndThen(Collectors.toCollection(ArrayList::new), PImmutableSet::new);
  }

  final class PImmutableSet implements ImmutableSet, Serializable {

    @Serial
    private static final long serialVersionUID = -8988192488466183450L;

    private static final ImmutableSet EMPTY = new PImmutableSet<>(HashTreePSet.empty());

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

    private final PSet backend;

    private PImmutableSet(Collection backend) {
      this(HashTreePSet.from(backend));
    }

    private PImmutableSet(PSet backend) {
      this.backend = checkNonNull(backend);
    }

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

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

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

    @Override
    public Set toSet() {
      return new HashSet<>(backend);
    }

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

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

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

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

    @Override
    public ImmutableSet reverse() {
      return this;
    }

    @Override
    public ImmutableSet union(ImmutableSet other) {
      return new PImmutableSet<>(backend.plusAll(other.toCollection()));
    }

    @Override
    public ImmutableSet intersection(ImmutableSet other) {
      // TODO: reimplement when retainingAll will be implemented
      Set copy = new HashSet<>(backend);
      copy.retainAll(other.toCollection());
      return new PImmutableSet<>(copy);
    }

    @Override
    public ImmutableSet difference(ImmutableSet other) {
      return new PImmutableSet<>(backend.minusAll(other.toCollection()));
    }

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

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

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

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




© 2015 - 2025 Weber Informatics LLC | Privacy Policy