OpenIntToDoubleHashMap.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      https://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. /*
  18.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */

  21. package org.hipparchus.util;

  22. import java.io.IOException;
  23. import java.io.ObjectInputStream;
  24. import java.io.Serializable;
  25. import java.util.Arrays;
  26. import java.util.ConcurrentModificationException;
  27. import java.util.NoSuchElementException;

  28. /**
  29.  * Open addressed map from int to double.
  30.  * <p>This class provides a dedicated map from integers to doubles with a
  31.  * much smaller memory overhead than standard <code>java.util.Map</code>.</p>
  32.  * <p>This class is not synchronized. The specialized iterators returned by
  33.  * {@link #iterator()} are fail-fast: they throw a
  34.  * <code>ConcurrentModificationException</code> when they detect the map has been
  35.  * modified during iteration.</p>
  36.  */
  37. public class OpenIntToDoubleHashMap extends AbstractOpenIntHashMap implements Serializable {

  38.     /** Serializable version identifier */
  39.     private static final long serialVersionUID = 20240326L;

  40.     /** Values table. */
  41.     private double[] values;

  42.     /** Return value for missing entries. */
  43.     private final double missingEntries;

  44.     /**
  45.      * Build an empty map with default size and using NaN for missing entries.
  46.      */
  47.     public OpenIntToDoubleHashMap() {
  48.         this(DEFAULT_EXPECTED_SIZE, Double.NaN);
  49.     }

  50.     /**
  51.      * Build an empty map with default size
  52.      * @param missingEntries value to return when a missing entry is fetched
  53.      */
  54.     public OpenIntToDoubleHashMap(final double missingEntries) {
  55.         this(DEFAULT_EXPECTED_SIZE, missingEntries);
  56.     }

  57.     /**
  58.      * Build an empty map with specified size and using NaN for missing entries.
  59.      * @param expectedSize expected number of elements in the map
  60.      */
  61.     public OpenIntToDoubleHashMap(final int expectedSize) {
  62.         this(expectedSize, Double.NaN);
  63.     }

  64.     /**
  65.      * Build an empty map with specified size.
  66.      * @param expectedSize expected number of elements in the map
  67.      * @param missingEntries value to return when a missing entry is fetched
  68.      */
  69.     public OpenIntToDoubleHashMap(final int expectedSize,
  70.                                   final double missingEntries) {
  71.         super(expectedSize);
  72.         values = new double[getCapacity()];
  73.         this.missingEntries = missingEntries;
  74.     }

  75.     /**
  76.      * Copy constructor.
  77.      * @param source map to copy
  78.      */
  79.     public OpenIntToDoubleHashMap(final OpenIntToDoubleHashMap source) {
  80.         super(source);
  81.         values = new double[getCapacity()];
  82.         System.arraycopy(source.values, 0, values, 0, getCapacity());
  83.         missingEntries = source.missingEntries;
  84.     }

  85.     /**
  86.      * Get the stored value associated with the given key
  87.      * @param key key associated with the data
  88.      * @return data associated with the key
  89.      */
  90.     public double get(final int key) {
  91.         final int index = locate(key);
  92.         return index < 0 ? missingEntries : values[index];
  93.     }

  94.     /**
  95.      * Get an iterator over map elements.
  96.      * <p>The specialized iterators returned are fail-fast: they throw a
  97.      * <code>ConcurrentModificationException</code> when they detect the map
  98.      * has been modified during iteration.</p>
  99.      * @return iterator over the map elements
  100.      */
  101.     public Iterator iterator() {
  102.         return new Iterator();
  103.     }

  104.     /** {@inheritDoc} */
  105.     @Override
  106.     public boolean equals(final Object o) {
  107.         if (this == o) {
  108.             return true;
  109.         }
  110.         if (o == null || getClass() != o.getClass()) {
  111.             return false;
  112.         }
  113.         final OpenIntToDoubleHashMap that = (OpenIntToDoubleHashMap) o;
  114.         return equalKeys(that) && equalStates(that) && Arrays.equals(values, that.values);
  115.     }

  116.     /** {@inheritDoc} */
  117.     @Override
  118.     public int hashCode() {
  119.         return keysStatesHashCode() + Arrays.hashCode(values);
  120.     }

  121.     /**
  122.      * Remove the value associated with a key.
  123.      * @param key key to which the value is associated
  124.      * @return removed value
  125.      */
  126.     public double remove(final int key) {
  127.         final int index = locate(key);
  128.         if (index < 0) {
  129.             return missingEntries;
  130.         } else {
  131.             final double previous = values[index];
  132.             doRemove(index);
  133.             values[index] = missingEntries;
  134.             return previous;
  135.         }
  136.     }

  137.     /**
  138.      * Put a value associated with a key in the map.
  139.      * @param key key to which value is associated
  140.      * @param value value to put in the map
  141.      * @return previous value associated with the key
  142.      */
  143.     public double put(final int key, final double value) {
  144.         final InsertionHolder ih = put(key);
  145.         final double previous = ih.isExisting() ? values[ih.getIndex()] : missingEntries;
  146.         values[ih.getIndex()] = value;
  147.         return previous;
  148.     }

  149.     /** {@inheritDoc} */
  150.     @Override
  151.     protected int growTable(final int oldIndex) {
  152.         final double[] newValues = new double[RESIZE_MULTIPLIER * values.length];
  153.         final int      newIndex  = doGrowTable(oldIndex, (src, dest) -> newValues[dest] = values[src]);
  154.         values = newValues;
  155.         return newIndex;
  156.     }

  157.     /** Iterator class for the map. */
  158.     public class Iterator extends BaseIterator {

  159.         /** Get the value of current entry.
  160.          * @return value of current entry
  161.          * @exception ConcurrentModificationException if the map is modified during iteration
  162.          * @exception NoSuchElementException if there is no element left in the map
  163.          */
  164.         public double value() throws ConcurrentModificationException, NoSuchElementException {
  165.             return values[getCurrent()];
  166.         }

  167.     }

  168.     /**
  169.      * Read a serialized object.
  170.      * @param stream input stream
  171.      * @throws IOException if object cannot be read
  172.      * @throws ClassNotFoundException if the class corresponding
  173.      * to the serialized object cannot be found
  174.      */
  175.     private void readObject(final ObjectInputStream stream)
  176.         throws IOException, ClassNotFoundException {
  177.         stream.defaultReadObject();
  178.         resetCount();
  179.     }

  180.     /**
  181.      * Replace the instance with a data transfer object for serialization.
  182.      * @return data transfer object that will be serialized
  183.      */
  184.     private Object writeReplace() {
  185.         return new DataTransferObject(missingEntries, getSize(), iterator());
  186.     }

  187.     /** Internal class used only for serialization. */
  188.     private static class DataTransferObject implements Serializable {

  189.         /** Serializable UID. */
  190.         private static final long serialVersionUID = 20240326L;

  191.         /** Return value for missing entries. */
  192.         private final double missingEntries;

  193.         /** Keys table. */
  194.         private final int[] keys;

  195.         /** Values table. */
  196.         private final double[] values;

  197.         /** Simple constructor.
  198.          * @param missingEntries return value for missing entries
  199.          * @param size number of objects in the map
  200.          * @param iterator iterator on serialized map
  201.          */
  202.         DataTransferObject(final double missingEntries, final int size, final Iterator iterator) {
  203.             this.missingEntries = missingEntries;
  204.             this.keys           = new int[size];
  205.             this.values         = new double[size];
  206.             for (int i = 0; i < size; ++i) {
  207.                 iterator.advance();
  208.                 keys[i]   = iterator.key();
  209.                 values[i] = iterator.value();
  210.             }
  211.         }

  212.         /** Replace the deserialized data transfer object with a {@link OpenIntToDoubleHashMap}.
  213.          * @return replacement {@link OpenIntToDoubleHashMap}
  214.          */
  215.         private Object readResolve() {
  216.             final OpenIntToDoubleHashMap map = new OpenIntToDoubleHashMap(missingEntries);
  217.             for (int i = 0; i < keys.length; ++i) {
  218.                 map.put(keys[i], values[i]);
  219.             }
  220.             return map;
  221.         }

  222.     }

  223. }