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             return v; // null
32         }
33         v = data[k1][k2];
34         return v;
35     }
36 
37     public V[K2] get(K1 k1)
38     {
39         if (k1 !in data) {
40             V[K2] v;
41             return v;
42         }
43         return data[k1];
44     }
45 
46     /**
47      * Get all values associated with a primary key.
48      */
49     public V[] values(K1 k1)
50     {
51         V[] va;
52         if (k1 !in data) {
53                 return va; // []
54             }
55         V[K2] data2 = data[k1];
56         return data2.values;
57     }
58 
59     /**
60      * get all primary keys
61      */
62     public K1[] keySet()
63     {
64         return data.keys;
65     }
66 
67     /**
68      * Get all secondary keys associated with a primary key.
69      */
70     public K2[] keySet(K1 k1)
71     {
72         if (k1 !in data) {
73             K2[] v;
74             return v;
75         }
76         V[K2] data2 = data[k1];
77         return data2.keys;
78     }
79 
80 }
81 
82 version(unittest) {
83     import dshould : be, equal, not, should;
84     import unit_threaded;
85 
86     class Test {
87 
88         @Tags("DoubleKeyMap")
89         @("construction DoubleKeyMap")
90         unittest {
91             auto t1 = new DoubleKeyMap!(int, int, int);
92             t1.put(7,1,12);
93             t1.put(7,1,13);
94             auto x = t1.get(7,1);
95             x.get.should.equal(13);
96             x = t1.get(7,2);
97             x.isNull.should.equal(true);
98         }
99 
100         @Tags("DoubleKeyMap")
101         @("comparing DoubleKeyMaps")
102         unittest {
103             auto t1 = new DoubleKeyMap!(int, int, int);
104             t1.put(7,1,13);
105             auto y = t1.get(7);
106             int[int] c;
107             c[1] = 13;
108             c.should.equal(y);
109             y = t1.get(6);
110             y.length.should.equal(0);
111             t1.put(7,4,71);
112             c[4] = 71;
113             y = t1.get(7);
114             c.should.equal(y);
115 
116             auto v1 = t1.values(7);
117             v1.should.equal([71, 13]);
118             v1 = t1.values(0);
119             v1.should.equal([]);
120 
121             auto kx = t1.keySet;
122             auto kk = [7];
123             kk.should.equal(kx);
124 
125             auto tx = t1.keySet(8);
126             tx.should.equal([]);
127             tx = t1.keySet(7);
128             tx.should.equal([4, 1]);
129         }
130 
131     }
132 
133 }