TypeSafeHashMultiMap.java

  1. /*
  2.  * *************************************************************************************************************************************************************
  3.  *
  4.  * TheseFoolishThings: Miscellaneous utilities
  5.  * http://tidalwave.it/projects/thesefoolishthings
  6.  *
  7.  * Copyright (C) 2009 - 2025 by Tidalwave s.a.s. (http://tidalwave.it)
  8.  *
  9.  * *************************************************************************************************************************************************************
  10.  *
  11.  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
  12.  * You may obtain a copy of the License at
  13.  *
  14.  *     http://www.apache.org/licenses/LICENSE-2.0
  15.  *
  16.  * 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
  17.  * CONDITIONS OF ANY KIND, either express or implied.  See the License for the specific language governing permissions and limitations under the License.
  18.  *
  19.  * *************************************************************************************************************************************************************
  20.  *
  21.  * git clone https://bitbucket.org/tidalwave/thesefoolishthings-src
  22.  * git clone https://github.com/tidalwave-it/thesefoolishthings-src
  23.  *
  24.  * *************************************************************************************************************************************************************
  25.  */
  26. package it.tidalwave.util.impl;

  27. import javax.annotation.Nonnegative;
  28. import javax.annotation.Nonnull;
  29. import javax.annotation.concurrent.Immutable;
  30. import java.util.ArrayList;
  31. import java.util.Collection;
  32. import java.util.HashMap;
  33. import java.util.Iterator;
  34. import java.util.Map;
  35. import java.util.Set;
  36. import java.util.concurrent.CopyOnWriteArrayList;
  37. import java.util.concurrent.CopyOnWriteArraySet;
  38. import java.util.function.BiConsumer;
  39. import java.io.Serializable;
  40. import it.tidalwave.util.Key;
  41. import it.tidalwave.util.TypeSafeMultiMap;
  42. import lombok.EqualsAndHashCode;

  43. /***************************************************************************************************************************************************************
  44.  *
  45.  * @author  Fabrizio Giudici
  46.  *
  47.  **************************************************************************************************************************************************************/
  48. @Immutable @EqualsAndHashCode
  49. public class TypeSafeHashMultiMap implements TypeSafeMultiMap, Serializable
  50.   {
  51.     private static final long serialVersionUID = 759233572056L;

  52.     @Nonnull
  53.     private final Map<Key<?>, Collection<?>> map;

  54.     /***********************************************************************************************************************************************************
  55.      * Creates a new instance from the given contents.
  56.      *
  57.      * @param   map   the contents
  58.      **********************************************************************************************************************************************************/
  59.     public TypeSafeHashMultiMap (@Nonnull final Map<? extends Key<?>, ? extends Collection<?>> map)
  60.       {
  61.         this(new HashMap<>(), true);
  62.         this.map.putAll(map);
  63.       }

  64.     /***********************************************************************************************************************************************************
  65.      **********************************************************************************************************************************************************/
  66.     /* package */ TypeSafeHashMultiMap (@Nonnull final Map<Key<?>, Collection<?>> map, final boolean ignored)
  67.       {
  68.         this.map = map;
  69.       }

  70.     /***********************************************************************************************************************************************************
  71.      * {@inheritDoc}
  72.      **********************************************************************************************************************************************************/
  73.     @Override @Nonnull @SuppressWarnings("unchecked")
  74.     public <T> Collection<T> get (@Nonnull final Key<T> key)
  75.       {
  76.         return containsKey(key) ? new CopyOnWriteArrayList<>((Collection<T>)map.get(key))
  77.                                 : new ArrayList<>();
  78.       }

  79.     /***********************************************************************************************************************************************************
  80.      * {@inheritDoc}
  81.      **********************************************************************************************************************************************************/
  82.     @Override
  83.     public boolean containsKey (@Nonnull final Key<?> key)
  84.       {
  85.         return map.containsKey(key);
  86.       }

  87.     /***********************************************************************************************************************************************************
  88.      * {@inheritDoc}
  89.      **********************************************************************************************************************************************************/
  90.     @Override @Nonnull
  91.     public <T> TypeSafeHashMultiMap with (@Nonnull final Key<T> key, @Nonnull final T value)
  92.       {
  93.         final var map = asMap();
  94.         final var values = get(key);
  95.         values.add(value);
  96.         map.put(key, values);
  97.         return new TypeSafeHashMultiMap(map);
  98.       }

  99.     /***********************************************************************************************************************************************************
  100.      * {@inheritDoc}
  101.      **********************************************************************************************************************************************************/
  102.     @Override @Nonnull
  103.     public Set<Key<?>> keySet()
  104.       {
  105.         return new CopyOnWriteArraySet<>(map.keySet());
  106.       }

  107.     /***********************************************************************************************************************************************************
  108.      * {@inheritDoc}
  109.      **********************************************************************************************************************************************************/
  110.     @Override @Nonnull
  111.     public Collection<Collection<?>> values()
  112.       {
  113.         return map.values();
  114.       }

  115.     /***********************************************************************************************************************************************************
  116.      * {@inheritDoc}
  117.      **********************************************************************************************************************************************************/
  118.     @Override @Nonnull
  119.     public Set<Map.Entry<Key<?>, Collection<?>>> entrySet()
  120.       {
  121.         return map.entrySet();
  122.       }

  123.     /***********************************************************************************************************************************************************
  124.      * {@inheritDoc}
  125.      **********************************************************************************************************************************************************/
  126.     @Override @Nonnull
  127.     public Iterator<Map.Entry<Key<?>, Collection<?>>> iterator()
  128.       {
  129.         return map.entrySet().iterator();
  130.       }

  131.     /***********************************************************************************************************************************************************
  132.      * {@inheritDoc}
  133.      **********************************************************************************************************************************************************/
  134.     @Override @Nonnegative
  135.     public int size()
  136.       {
  137.         return map.size();
  138.       }

  139.     /***********************************************************************************************************************************************************
  140.      * {@inheritDoc}
  141.      **********************************************************************************************************************************************************/
  142.     @Override @Nonnull
  143.     public Map<Key<?>, Collection<?>> asMap()
  144.       {
  145.         return new HashMap<>(map);
  146.       }

  147.     /***********************************************************************************************************************************************************
  148.      * {@inheritDoc}
  149.      **********************************************************************************************************************************************************/
  150.     @Override @SuppressWarnings("unchecked")
  151.     public <T> void forEach (@Nonnull final BiConsumer<? super Key<T>, ? super Collection<T>> action)
  152.       {
  153.         map.forEach((BiConsumer<? super Key<?>, ? super Collection<?>>)action);
  154.       }

  155.     /***********************************************************************************************************************************************************
  156.      * {@inheritDoc}
  157.      **********************************************************************************************************************************************************/
  158.     @Override @Nonnull
  159.     public String toString()
  160.       {
  161.         return map.toString();
  162.       }
  163.   }