1 package io.jawk.jrt;
2
3 /*-
4 * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
5 * Jawk
6 * ჻჻჻჻჻჻
7 * Copyright (C) 2006 - 2026 MetricsHub
8 * ჻჻჻჻჻჻
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as
11 * published by the Free Software Foundation, either version 3 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Lesser Public License for more details.
18 *
19 * You should have received a copy of the GNU General Lesser Public
20 * License along with this program. If not, see
21 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
22 * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
23 */
24
25 import java.util.HashMap;
26
27 /**
28 * An AWK associative array backed by a {@link HashMap}.
29 * <p>
30 * Keys are not kept in any particular order. This is the default implementation
31 * used when sorted keys are not required.
32 * </p>
33 *
34 * @author MetricsHub
35 */
36 public class HashAssocArray extends HashMap<Object, Object> implements AssocArray {
37
38 private static final long serialVersionUID = 1L;
39
40 /**
41 * Returns the value to which the specified key is mapped, normalizing the key
42 * first. If the key does not exist, a blank ({@link io.jawk.intermediate.UninitializedObject})
43 * is inserted and returned, as required by AWK semantics.
44 *
45 * @param key the key whose associated value is to be returned
46 * @return the value associated with the key, or a blank value if not found
47 */
48 @Override
49 public Object get(Object key) {
50 key = AssocArray.normalizeKey(key);
51 Object result = super.get(key);
52 if (result != null) {
53 return result;
54 }
55 Long lKey = AssocArray.toLongKey(key);
56 if (lKey != null) {
57 result = super.get(lKey);
58 if (result != null) {
59 return result;
60 }
61 key = lKey;
62 }
63 result = BLANK;
64 super.put(key, result);
65 return result;
66 }
67
68 /**
69 * Associates the specified value with the specified key, normalizing the key
70 * to a {@code Long} when the key is a valid integer string.
71 *
72 * @param key the key
73 * @param value the value
74 * @return the previous value associated with the key, or {@code null}
75 */
76 @Override
77 public Object put(Object key, Object value) {
78 key = AssocArray.normalizeKey(key);
79 Long lKey = AssocArray.toLongKey(key);
80 return super.put(lKey != null ? lKey : key, value);
81 }
82
83 /**
84 * Removes the mapping for the specified key, trying both the original and its
85 * {@code Long} equivalent.
86 *
87 * @param key the key whose mapping is to be removed
88 * @return the previous value associated with the key, or {@code null}
89 */
90 @Override
91 public Object remove(Object key) {
92 key = AssocArray.normalizeKey(key);
93 Object result = super.remove(key);
94 if (result != null) {
95 return result;
96 }
97 Long lKey = AssocArray.toLongKey(key);
98 return lKey != null ? super.remove(lKey) : null;
99 }
100
101 /**
102 * Returns the specification version of the underlying {@link HashMap} class.
103 *
104 * @return the specification version string, or {@code null} if unavailable
105 */
106 @Override
107 public String getMapVersion() {
108 return HashMap.class.getPackage().getSpecificationVersion();
109 }
110
111 /**
112 * {@inheritDoc}
113 *
114 * @throws AwkRuntimeException always, to prevent accidental use of
115 * {@link HashMap#toString()} in an AWK evaluation
116 * context
117 */
118 @Override
119 public String toString() {
120 throw new AwkRuntimeException("Cannot evaluate an unindexed array.");
121 }
122 }