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 /*
19 * This is not the original file distributed by the Apache Software Foundation
20 * It has been modified by the Hipparchus project
21 */
22 package org.hipparchus.util;
23
24 import java.io.IOException;
25 import java.io.ObjectInputStream;
26 import java.io.Serializable;
27 import java.lang.reflect.Array;
28 import java.util.Arrays;
29 import java.util.ConcurrentModificationException;
30 import java.util.NoSuchElementException;
31
32 import org.hipparchus.Field;
33 import org.hipparchus.FieldElement;
34
35 /**
36 * Open addressed map from int to FieldElement.
37 * <p>This class provides a dedicated map from integers to FieldElements with a
38 * much smaller memory overhead than standard <code>java.util.Map</code>.</p>
39 * <p>This class is not synchronized. The specialized iterators returned by
40 * {@link #iterator()} are fail-fast: they throw a
41 * <code>ConcurrentModificationException</code> when they detect the map has been
42 * modified during iteration.</p>
43 * @param <T> the type of the field elements
44 */
45 public class OpenIntToFieldHashMap<T extends FieldElement<T>> extends AbstractOpenIntHashMap implements Serializable {
46
47 /** Serializable version identifier. */
48 private static final long serialVersionUID = 20240326L;
49
50 /** Field to which the elements belong. */
51 private final Field<T> field;
52
53 /** Values table. */
54 private T[] values;
55
56 /** Return value for missing entries. */
57 private final T missingEntries;
58
59 /**
60 * Build an empty map with default size and using zero for missing entries.
61 * @param field field to which the elements belong
62 */
63 public OpenIntToFieldHashMap(final Field<T>field) {
64 this(field, DEFAULT_EXPECTED_SIZE, field.getZero());
65 }
66
67 /**
68 * Build an empty map with default size
69 * @param field field to which the elements belong
70 * @param missingEntries value to return when a missing entry is fetched
71 */
72 public OpenIntToFieldHashMap(final Field<T>field, final T missingEntries) {
73 this(field, DEFAULT_EXPECTED_SIZE, missingEntries);
74 }
75
76 /**
77 * Build an empty map with specified size and using zero for missing entries.
78 * @param field field to which the elements belong
79 * @param expectedSize expected number of elements in the map
80 */
81 public OpenIntToFieldHashMap(final Field<T> field,final int expectedSize) {
82 this(field, expectedSize, field.getZero());
83 }
84
85 /**
86 * Build an empty map with specified size.
87 * @param field field to which the elements belong
88 * @param expectedSize expected number of elements in the map
89 * @param missingEntries value to return when a missing entry is fetched
90 */
91 public OpenIntToFieldHashMap(final Field<T> field, final int expectedSize,
92 final T missingEntries) {
93 super(expectedSize);
94 this.field = field;
95 this.values = buildArray(getCapacity());
96 this.missingEntries = missingEntries;
97 }
98
99 /**
100 * Copy constructor.
101 * @param source map to copy
102 */
103 public OpenIntToFieldHashMap(final OpenIntToFieldHashMap<T> source) {
104 super(source);
105 field = source.field;
106 values = buildArray(getCapacity());
107 System.arraycopy(source.values, 0, values, 0, getCapacity());
108 missingEntries = source.missingEntries;
109 }
110
111 /**
112 * Get the stored value associated with the given key
113 * @param key key associated with the data
114 * @return data associated with the key
115 */
116 public T get(final int key) {
117 final int index = locate(key);
118 return index < 0 ? missingEntries : values[index];
119 }
120
121 /**
122 * Get an iterator over map elements.
123 * <p>The specialized iterators returned are fail-fast: they throw a
124 * <code>ConcurrentModificationException</code> when they detect the map
125 * has been modified during iteration.</p>
126 * @return iterator over the map elements
127 */
128 public Iterator iterator() {
129 return new Iterator();
130 }
131
132 /** {@inheritDoc} */
133 @Override
134 public boolean equals(final Object o) {
135 if (this == o) {
136 return true;
137 }
138 if (o == null || getClass() != o.getClass()) {
139 return false;
140 }
141 @SuppressWarnings("unchecked")
142 final OpenIntToFieldHashMap<T> that = (OpenIntToFieldHashMap<T>) o;
143 return equalKeys(that) &&
144 equalStates(that) &&
145 field.equals(that.field) &&
146 Arrays.equals(values, that.values);
147 }
148
149 /** {@inheritDoc} */
150 @Override
151 public int hashCode() {
152 return keysStatesHashCode() + 67 * field.hashCode() + Arrays.hashCode(values);
153 }
154
155 /**
156 * Remove the value associated with a key.
157 * @param key key to which the value is associated
158 * @return removed value
159 */
160 public T remove(final int key) {
161 final int index = locate(key);
162 if (index < 0) {
163 return missingEntries;
164 } else {
165 final T previous = values[index];
166 doRemove(index);
167 values[index] = missingEntries;
168 return previous;
169 }
170 }
171
172 /**
173 * Put a value associated with a key in the map.
174 * @param key key to which value is associated
175 * @param value value to put in the map
176 * @return previous value associated with the key
177 */
178 public T put(final int key, final T value) {
179 final InsertionHolder ih = put(key);
180 final T previous = ih.isExisting() ? values[ih.getIndex()] : missingEntries;
181 values[ih.getIndex()] = value;
182 return previous;
183 }
184
185 /**
186 * Grow the tables.
187 */
188 @Override
189 protected int growTable(final int oldIndex) {
190 final T[] newValues = buildArray(RESIZE_MULTIPLIER * values.length);
191 final int newIndex = doGrowTable(oldIndex, (src, dest) -> newValues[dest] = values[src]);
192 values = newValues;
193 return newIndex;
194 }
195
196 /** Iterator class for the map. */
197 public class Iterator extends BaseIterator {
198
199 /** Get the value of current entry.
200 * @return value of current entry
201 * @exception ConcurrentModificationException if the map is modified during iteration
202 * @exception NoSuchElementException if there is no element left in the map
203 */
204 public T value() throws ConcurrentModificationException, NoSuchElementException {
205 return values[getCurrent()];
206 }
207
208 }
209
210 /**
211 * Read a serialized object.
212 * @param stream input stream
213 * @throws IOException if object cannot be read
214 * @throws ClassNotFoundException if the class corresponding
215 * to the serialized object cannot be found
216 */
217 private void readObject(final ObjectInputStream stream)
218 throws IOException, ClassNotFoundException {
219 stream.defaultReadObject();
220 resetCount();
221 }
222
223 /** Build an array of elements.
224 * @param length size of the array to build
225 * @return a new array
226 */
227 @SuppressWarnings("unchecked") // field is of type T
228 private T[] buildArray(final int length) {
229 return (T[]) Array.newInstance(field.getRuntimeClass(), length);
230 }
231
232 }