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 = UNTYPED;
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 // null has no meaning in an AWK array: store the untyped marker so
81 // callers never have to special-case it
82 return super.put(lKey != null ? lKey : key, value == null ? UNTYPED : value);
83 }
84
85 /**
86 * Removes the mapping for the specified key, trying both the original and its
87 * {@code Long} equivalent.
88 *
89 * @param key the key whose mapping is to be removed
90 * @return the previous value associated with the key, or {@code null}
91 */
92 @Override
93 public Object remove(Object key) {
94 key = AssocArray.normalizeKey(key);
95 Object result = super.remove(key);
96 if (result != null) {
97 return result;
98 }
99 Long lKey = AssocArray.toLongKey(key);
100 return lKey != null ? super.remove(lKey) : null;
101 }
102
103 /**
104 * Returns the specification version of the underlying {@link HashMap} class.
105 *
106 * @return the specification version string, or {@code null} if unavailable
107 */
108 @Override
109 public String getMapVersion() {
110 return HashMap.class.getPackage().getSpecificationVersion();
111 }
112
113 /**
114 * {@inheritDoc}
115 *
116 * @throws AwkRuntimeException always, to prevent accidental use of
117 * {@link HashMap#toString()} in an AWK evaluation
118 * context
119 */
120 @Override
121 public String toString() {
122 throw new AwkRuntimeException("Attempting to use an array in a scalar context.");
123 }
124 }