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

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

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

import static java.util.Collections.emptyMap;
import static java.util.Objects.requireNonNull;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.github.tonivade.purefun.Consumer2;
import com.github.tonivade.purefun.Equal;
import com.github.tonivade.purefun.Function1;
import com.github.tonivade.purefun.Matcher1;
import com.github.tonivade.purefun.Operator2;
import com.github.tonivade.purefun.Producer;
import com.github.tonivade.purefun.Tuple;
import com.github.tonivade.purefun.Tuple2;
import com.github.tonivade.purefun.type.Option;

public interface ImmutableMap {

  Map toMap();

  ImmutableMap put(K key, V value);
  ImmutableMap putAll(ImmutableSet> other);
  ImmutableMap remove(K key);
  Option get(K key);

  Sequence values();
  ImmutableSet keys();
  ImmutableSet> entries();

  ImmutableMap merge(K key, V value, Operator2 merger);

  int size();

  default void forEach(Consumer2 consumer) {
    entries().forEach(tuple -> consumer.accept(tuple.get1(), tuple.get2()));
  }

  default  ImmutableMap map(Function1 keyMapper, Function1 valueMapper) {
    return ImmutableMap.from(entries().map(tuple -> tuple.map(keyMapper, valueMapper)));
  }

  default  ImmutableMap mapKeys(Function1 mapper) {
    return ImmutableMap.from(entries().map(tuple -> tuple.map1(mapper)));
  }

  default  ImmutableMap mapValues(Function1 mapper) {
    return ImmutableMap.from(entries().map(tuple -> tuple.map2(mapper)));
  }

  default ImmutableMap filterKeys(Matcher1 filter) {
    return ImmutableMap.from(entries().filter(tuple -> filter.match(tuple.get1())));
  }

  default ImmutableMap filterValues(Matcher1 filter) {
    return ImmutableMap.from(entries().filter(tuple -> filter.match(tuple.get2())));
  }

  default boolean containsKey(K key) {
    return get(key).isPresent();
  }

  default ImmutableMap putIfAbsent(K key, V value) {
    if (containsKey(key)) {
      return this;
    }
    return put(key, value);
  }

  default V getOrDefault(K key, Producer supplier) {
    return get(key).getOrElse(supplier);
  }

  default boolean isEmpty() {
    return size() == 0;
  }

  @SafeVarargs
  static  ImmutableMap of(Tuple2 ... entries) {
    return from(ImmutableSet.of(entries));
  }

  static  Tuple2 entry(K key, V value) {
    return Tuple2.of(key, value);
  }

  static  ImmutableMap from(Map map) {
    return new JavaBasedImmutableMap<>(map);
  }

  static  ImmutableMap empty() {
    return new JavaBasedImmutableMap<>(emptyMap());
  }

  static  ImmutableMap from(Stream> entries) {
    return from(ImmutableSet.from(entries));
  }

  static  ImmutableMap from(ImmutableSet> entries) {
    return new JavaBasedImmutableMap<>(entries.stream()
        .collect(Collectors.toMap(Tuple2::get1, Tuple2::get2)));
  }

  static  Builder builder() {
    return new Builder<>();
  }

  final class Builder {

    private final Map map = new HashMap<>();

    private Builder() { }

    public Builder put(K key, V value) {
      map.put(key, value);
      return this;
    }

    public ImmutableMap build() {
      return ImmutableMap.from(map);
    }
  }

  final class JavaBasedImmutableMap implements ImmutableMap, Serializable {

    private static final long serialVersionUID = -1236334562860351635L;

    private final Map backend;

    private JavaBasedImmutableMap(Map backend) {
      this.backend = requireNonNull(backend);
    }

    @Override
    public Map toMap() {
      return new HashMap<>(backend);
    }

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

    @Override
    public ImmutableMap put(K key, V value) {
      Map newMap = toMap();
      newMap.put(key, value);
      return new JavaBasedImmutableMap<>(newMap);
    }

    @Override
    public ImmutableMap putAll(ImmutableSet> other) {
      Map newMap = toMap();
      newMap.putAll(ImmutableMap.from(other).toMap());
      return new JavaBasedImmutableMap<>(newMap);
    }

    @Override
    public ImmutableMap remove(K key) {
      Map newMap = toMap();
      newMap.remove(key);
      return new JavaBasedImmutableMap<>(newMap);
    }

    @Override
    public Option get(K key) {
      return Option.of(() -> backend.get(key));
    }

    @Override
    public ImmutableMap merge(K key, V value, Operator2 merger) {
      Map newMap = toMap();
      newMap.merge(key, value, merger::apply);
      return new JavaBasedImmutableMap<>(newMap);
    }

    @Override
    public Sequence values() {
      return ImmutableList.from(backend.values());
    }

    @Override
    public ImmutableSet keys() {
      return ImmutableSet.from(backend.keySet());
    }

    @Override
    public ImmutableSet> entries() {
      return ImmutableSet.from(backend.entrySet()).map(Tuple::from);
    }

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

    @Override
    public boolean equals(Object obj) {
      return Equal.of(this)
          .append((a, b) -> Objects.equals(a.backend, b.backend))
          .applyTo(obj);
    }

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




© 2015 - 2025 Weber Informatics LLC | Privacy Policy