1 /*
2  * Copyright (c) 2012-2019 The ANTLR Project. All rights reserved.
3  * Use of this file is governed by the BSD 3-clause license that
4  * can be found in the LICENSE.txt file in the project root.
5  */
6 
7 module antlr.v4.runtime.misc.DoubleKeyMap;
8 
9 import std.typecons;
10 
11 /**
12  * Sometimes we need to map a key to a value but key is two pieces of data.
13  * This nested hash table saves creating a single key each time we access
14  * map; avoids mem creation.
15  */
16 class DoubleKeyMap(K1, K2, V)
17 {
18 
19     public V[K1][K2] data;
20 
21     public V put(K1 k1, K2 k2, V v)
22     {
23         data[k1][k2] = v;
24         return v;
25     }
26 
27     public Nullable!V get(K1 k1, K2 k2)
28     {
29         Nullable!V v;
30         if (k1 !in data || k2 !in data[k1])
31         {
32             return v; // null
33         }
34         v = data[k1][k2];
35         return v;
36     }
37 
38     public V[K2] get(K1 k1)
39     {
40         if (k1 !in data)
41         {
42             V[K2] v;
43             return v;
44         }
45         return data[k1];
46     }
47 
48     /**
49      * Get all values associated with a primary key.
50      */
51     public V[] values(K1 k1)
52     {
53         V[] va;
54         if (k1 !in data)
55         {
56             return va; // []
57         }
58         V[K2] data2 = data[k1];
59         return data2.values;
60     }
61 
62     /**
63      * get all primary keys
64      */
65     public K1[] keySet()
66     {
67         return data.keys;
68     }
69 
70     /**
71      * Get all secondary keys associated with a primary key.
72      */
73     public K2[] keySet(K1 k1)
74     {
75         if (k1 !in data)
76         {
77             K2[] v;
78             return v;
79         }
80         V[K2] data2 = data[k1];
81         return data2.keys;
82     }
83 
84 }
85 
86 version (AntlrUnittest)
87 {
88     import dshould;
89 
90     @("construction DoubleKeyMap")
91     unittest
92     {
93         auto t1 = new DoubleKeyMap!(int, int, int);
94         t1.put(7, 1, 12);
95         t1.put(7, 1, 13);
96         auto x = t1.get(7, 1);
97         x.get.should.equal(13);
98         x = t1.get(7, 2);
99         x.isNull.should.equal(true);
100     }
101 
102     @("comparing DoubleKeyMaps")
103     unittest
104     {
105         auto t1 = new DoubleKeyMap!(int, int, int);
106         t1.put(7, 1, 13);
107         auto y = t1.get(7);
108         int[int] c;
109         c[1] = 13;
110         c.should.equal(y);
111         y = t1.get(6);
112         y.length.should.equal(0);
113         t1.put(7, 4, 71);
114         c[4] = 71;
115         y = t1.get(7);
116         c.should.equal(y);
117 
118         auto v1 = t1.values(7);
119         v1.should.equal([71, 13]);
120         v1 = t1.values(0);
121         v1.should.equal([]);
122 
123         auto kx = t1.keySet;
124         auto kk = [7];
125         kk.should.equal(kx);
126 
127         auto tx = t1.keySet(8);
128         tx.should.equal([]);
129         tx = t1.keySet(7);
130         tx.should.equal([4, 1]);
131     }
132 }