1 /* Copyright 2002-2025 CS GROUP
2 * Licensed to CS GROUP (CS) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * CS 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 * http://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 package org.orekit.utils;
18
19 import java.io.Serializable;
20 import java.util.ArrayList;
21 import java.util.Arrays;
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.Iterator;
25 import java.util.List;
26 import java.util.Map;
27
28 /** String → double[] mapping, for small number of keys.
29 * <p>
30 * This class is a low overhead for a very small number of keys.
31 * It is based on simple array and string comparison. It plays
32 * the same role a {@code Map<String, double[]>} but with reduced
33 * features and not intended for large number of keys. For such
34 * needs the regular {@code Map<String, double[]>} should be preferred.
35 * </p>
36 *
37 * @see DataDictionary
38 * @since 11.1
39 */
40 public class DoubleArrayDictionary implements Serializable {
41
42 /** Serializable UID. */
43 private static final long serialVersionUID = 20211121L;
44
45 /** Default capacity. */
46 private static final int DEFAULT_INITIAL_CAPACITY = 4;
47
48 /** Data container. */
49 private final List<Entry> data;
50
51 /** Constructor with {@link #DEFAULT_INITIAL_CAPACITY default initial capacity}.
52 */
53 public DoubleArrayDictionary() {
54 this(DEFAULT_INITIAL_CAPACITY);
55 }
56
57 /** Constructor with specified capacity.
58 * @param initialCapacity initial capacity
59 */
60 public DoubleArrayDictionary(final int initialCapacity) {
61 data = new ArrayList<>(initialCapacity);
62 }
63
64 /** Constructor from another dictionary.
65 * @param dictionary dictionary to use for initializing entries
66 */
67 public DoubleArrayDictionary(final DoubleArrayDictionary dictionary) {
68 // take care to call dictionary.getData() and not use dictionary.data,
69 // otherwise we get an empty dictionary when using a DoubleArrayDictionary.view
70 this(DEFAULT_INITIAL_CAPACITY + dictionary.getData().size());
71 for (final Entry entry : dictionary.getData()) {
72 // we don't call put(key, value) to avoid the overhead of the unneeded call to remove(key)
73 data.add(new Entry(entry.getKey(), entry.getValue()));
74 }
75 }
76
77 /** Constructor from a map.
78 * @param map map to use for initializing entries
79 */
80 public DoubleArrayDictionary(final Map<String, double[]> map) {
81 this(map.size());
82 for (final Map.Entry<String, double[]> entry : map.entrySet()) {
83 // we don't call put(key, value) to avoid the overhead of the unneeded call to remove(key)
84 data.add(new Entry(entry.getKey(), entry.getValue()));
85 }
86 }
87
88 /** Get an unmodifiable view of the dictionary entries.
89 * @return unmodifiable view of the dictionary entries
90 */
91 public List<Entry> getData() {
92 return Collections.unmodifiableList(data);
93 }
94
95 /** Get the number of dictionary entries.
96 * @return number of dictionary entries
97 */
98 public int size() {
99 return data.size();
100 }
101
102 /** Create a map from the instance.
103 * <p>
104 * The map contains a copy of the instance data
105 * </p>
106 * @return copy of the dictionary, as an independent map
107 */
108 public Map<String, double[]> toMap() {
109 final Map<String, double[]> map = new HashMap<>(data.size());
110 for (final Entry entry : data) {
111 map.put(entry.getKey(), entry.getValue());
112 }
113 return map;
114 }
115
116 /** Remove all entries.
117 */
118 public void clear() {
119 data.clear();
120 }
121
122 /** Add an entry.
123 * <p>
124 * If an entry with the same key already exists, it will be removed first.
125 * </p>
126 * <p>
127 * The new entry is always put at the end.
128 * </p>
129 * @param key entry key
130 * @param value entry value
131 */
132 public void put(final String key, final double[] value) {
133 remove(key);
134 data.add(new Entry(key, value));
135 }
136
137 /** Put all the entries from the map in the dictionary.
138 * @param map map to copy into the instance
139 */
140 public void putAll(final Map<String, double[]> map) {
141 for (final Map.Entry<String, double[]> entry : map.entrySet()) {
142 put(entry.getKey(), entry.getValue());
143 }
144 }
145
146 /** Put all the entries from another dictionary.
147 * @param dictionary dictionary to copy into the instance
148 */
149 public void putAll(final DoubleArrayDictionary dictionary) {
150 for (final Entry entry : dictionary.data) {
151 put(entry.getKey(), entry.getValue());
152 }
153 }
154
155 /** Get the value corresponding to a key.
156 * @param key entry key
157 * @return copy of the value corresponding to the key or null if key not present
158 */
159 public double[] get(final String key) {
160 final Entry entry = getEntry(key);
161 return entry == null ? null : entry.getValue();
162 }
163
164 /** Get a complete entry.
165 * @param key entry key
166 * @return entry with key if it exists, null otherwise
167 */
168 public Entry getEntry(final String key) {
169 for (final Entry entry : data) {
170 if (entry.getKey().equals(key)) {
171 return entry;
172 }
173 }
174 return null;
175 }
176
177 /** Remove an entry.
178 * @param key key of the entry to remove
179 * @return true if an entry has been removed, false if the key was not present
180 */
181 public boolean remove(final String key) {
182 final Iterator<Entry> iterator = data.iterator();
183 while (iterator.hasNext()) {
184 if (iterator.next().getKey().equals(key)) {
185 iterator.remove();
186 return true;
187 }
188 }
189 return false;
190 }
191
192
193 /** Get a string representation of the dictionary.
194 * <p>
195 * This string representation is intended for improving displays in debuggers only.
196 * </p>
197 * @return string representation of the dictionary
198 */
199 @Override
200 public String toString() {
201 final StringBuilder builder = new StringBuilder();
202 builder.append('{');
203 for (int i = 0; i < data.size(); ++i) {
204 if (i > 0) {
205 builder.append(", ");
206 }
207 builder.append(data.get(i).getKey());
208 builder.append('[');
209 builder.append(data.get(i).getValue().length);
210 builder.append(']');
211 }
212 builder.append('}');
213 return builder.toString();
214 }
215
216 /** Entry in a dictionary. */
217 public static class Entry implements Serializable {
218
219 /** Serializable UID. */
220 private static final long serialVersionUID = 20211121L;
221
222 /** Key. */
223 private final String key;
224
225 /** Value. */
226 private final double[] value;
227
228 /** Simple constructor.
229 * @param key key
230 * @param value value
231 */
232 Entry(final String key, final double[] value) {
233 this.key = key;
234 this.value = value.clone();
235 }
236
237 /** Get the entry key.
238 * @return entry key
239 */
240 public String getKey() {
241 return key;
242 }
243
244 /** Get the value.
245 * @return a copy of the value (independent from internal array)
246 */
247 public double[] getValue() {
248 return value.clone();
249 }
250
251 /** Get the size of the value array.
252 * @return size of the value array
253 */
254 public int size() {
255 return value.length;
256 }
257
258 /** Increment the value.
259 * <p>
260 * For the sake of performance, no checks are done on argument.
261 * </p>
262 * @param increment increment to apply to the entry value
263 */
264 public void increment(final double[] increment) {
265 for (int i = 0; i < increment.length; ++i) {
266 value[i] += increment[i];
267 }
268 }
269
270 /** Increment the value with another scaled entry.
271 * <p>
272 * Each component {@code value[i]} will be replaced by {@code value[i] + factor * raw.value[i]}.
273 * </p>
274 * <p>
275 * For the sake of performance, no checks are done on arguments.
276 * </p>
277 * @param factor multiplicative factor for increment
278 * @param raw raw increment to be multiplied by {@code factor} and then added
279 * @since 11.1.1
280 */
281 public void scaledIncrement(final double factor, final Entry raw) {
282 for (int i = 0; i < raw.value.length; ++i) {
283 value[i] += factor * raw.value[i];
284 }
285 }
286
287 /** Reset the value to zero.
288 */
289 public void zero() {
290 Arrays.fill(value, 0.0);
291 }
292
293 }
294 }