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 (unittest)
87 {
88     import dshould : be, equal, not, should;
89     import unit_threaded;
90 
91     class Test
92     {
93 
94         @Tags("DoubleKeyMap")
95         @("construction DoubleKeyMap")
96         unittest
97         {
98             auto t1 = new DoubleKeyMap!(int, int, int);
99             t1.put(7, 1, 12);
100             t1.put(7, 1, 13);
101             auto x = t1.get(7, 1);
102             x.get.should.equal(13);
103             x = t1.get(7, 2);
104             x.isNull.should.equal(true);
105         }
106 
107         @Tags("DoubleKeyMap")
108         @("comparing DoubleKeyMaps")
109         unittest
110         {
111             auto t1 = new DoubleKeyMap!(int, int, int);
112             t1.put(7, 1, 13);
113             auto y = t1.get(7);
114             int[int] c;
115             c[1] = 13;
116             c.should.equal(y);
117             y = t1.get(6);
118             y.length.should.equal(0);
119             t1.put(7, 4, 71);
120             c[4] = 71;
121             y = t1.get(7);
122             c.should.equal(y);
123 
124             auto v1 = t1.values(7);
125             v1.should.equal([71, 13]);
126             v1 = t1.values(0);
127             v1.should.equal([]);
128 
129             auto kx = t1.keySet;
130             auto kk = [7];
131             kk.should.equal(kx);
132 
133             auto tx = t1.keySet(8);
134             tx.should.equal([]);
135             tx = t1.keySet(7);
136             tx.should.equal([4, 1]);
137         }
138 
139     }
140 
141 }