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 * Creates an empty associative array.
42 */
43 public HashAssocArray() {
44 // An AWK array starts out empty; keys are created on first access.
45 }
46
47 /**
48 * Returns the value to which the specified key is mapped, normalizing the key
49 * first. If the key does not exist, a blank ({@link io.jawk.intermediate.UninitializedObject})
50 * is inserted and returned, as required by AWK semantics.
51 *
52 * @param key the key whose associated value is to be returned
53 * @return the value associated with the key, or a blank value if not found
54 */
55 @Override
56 public Object get(Object key) {
57 key = AssocArray.normalizeKey(key);
58 Object result = super.get(key);
59 if (result != null) {
60 return result;
61 }
62 Long lKey = AssocArray.toLongKey(key);
63 if (lKey != null) {
64 result = super.get(lKey);
65 if (result != null) {
66 return result;
67 }
68 key = lKey;
69 }
70 result = UNTYPED;
71 super.put(key, result);
72 return result;
73 }
74
75 /**
76 * Associates the specified value with the specified key, normalizing the key
77 * to a {@code Long} when the key is a valid integer string.
78 *
79 * @param key the key
80 * @param value the value
81 * @return the previous value associated with the key, or {@code null}
82 */
83 @Override
84 public Object put(Object key, Object value) {
85 key = AssocArray.normalizeKey(key);
86 Long lKey = AssocArray.toLongKey(key);
87 // null has no meaning in an AWK array: store the untyped marker so
88 // callers never have to special-case it
89 return super.put(lKey != null ? lKey : key, value == null ? UNTYPED : value);
90 }
91
92 /**
93 * Removes the mapping for the specified key, trying both the original and its
94 * {@code Long} equivalent.
95 *
96 * @param key the key whose mapping is to be removed
97 * @return the previous value associated with the key, or {@code null}
98 */
99 @Override
100 public Object remove(Object key) {
101 key = AssocArray.normalizeKey(key);
102 Object result = super.remove(key);
103 if (result != null) {
104 return result;
105 }
106 Long lKey = AssocArray.toLongKey(key);
107 return lKey != null ? super.remove(lKey) : null;
108 }
109
110 /**
111 * Returns the specification version of the underlying {@link HashMap} class.
112 *
113 * @return the specification version string, or {@code null} if unavailable
114 */
115 @Override
116 public String getMapVersion() {
117 return HashMap.class.getPackage().getSpecificationVersion();
118 }
119
120 /**
121 * {@inheritDoc}
122 *
123 * @throws AwkRuntimeException always, to prevent accidental use of
124 * {@link HashMap#toString()} in an AWK evaluation
125 * context
126 */
127 @Override
128 public String toString() {
129 throw new AwkRuntimeException("Attempting to use an array in a scalar context.");
130 }
131 }