1 
2 //          Copyright Tim Schendekehl 2023.
3 // Distributed under the Boost Software License, Version 1.0.
4 //    (See accompanying file LICENSE_1_0.txt or copy at
5 //          https://www.boost.org/LICENSE_1_0.txt)
6 
7 module dparsergen.generator.ids;
8 import std.algorithm;
9 import std.bitmanip;
10 import std.conv;
11 import std.range;
12 
13 struct IDMap(I, T, string idMember = "name")
14 {
15     T[] vals;
16     alias IdType = typeof(__traits(getMember, T, idMember));
17     typeof(I.init.id)[IdType] ids;
18 
19     I id(IdType val)
20     {
21         if (val in ids)
22             return I(ids[val]);
23         typeof(I.init.id) newID = vals.length.to!(typeof(I.init.id));
24         T x;
25         __traits(getMember, x, idMember) = val;
26         vals ~= x;
27         ids[val] = newID;
28         return I(newID);
29     }
30 
31     I getID(IdType val) const
32     {
33         assert(val in ids);
34         return I(ids[val]);
35     }
36 
37     const(T) opIndex(I i) const
38     {
39         return vals[i.id];
40     }
41 
42     ref T opIndex(I i)
43     {
44         return vals[i.id];
45     }
46 
47     const(T) get(IdType val) const
48     {
49         return vals[getID(val).id];
50     }
51 
52     auto allIDs() const
53     {
54         return iota(0, vals.length).map!(i => I(i.to!(typeof(I.init.id))));
55     }
56 
57     IDMap dup() const
58     {
59         IDMap r;
60         r.vals = vals.dup;
61         foreach (k, v; ids)
62             r.ids[k] = v;
63         return r;
64     }
65 }
66 
67 struct BitSet(I)
68 {
69     BitArray arr;
70     this(size_t l)
71     {
72         assert(l < typeof(I.init.id).max);
73         arr.length = l;
74     }
75 
76     private this(BitArray arr)
77     {
78         assert(arr.length < typeof(I.init.id).max);
79         this.arr = arr;
80     }
81 
82     bool opIndex(I i) const
83     {
84         assert(i.id < typeof(I.init.id).max);
85         if (i.id >= arr.length)
86             return false;
87         return arr[i.id];
88     }
89 
90     void opIndexAssign(bool value, I i)
91     {
92         assert(i.id < typeof(I.init.id).max);
93         if (i.id >= arr.length)
94             arr.length = i.id + 1;
95         arr[i.id] = value;
96     }
97 
98     void opOpAssign(string op)(const BitSet!I rhs)
99     {
100         static if (op == "|")
101         {
102             if (arr.length == 0)
103             {
104                 arr = rhs.arr.dup;
105                 return;
106             }
107             if (rhs.arr.length == 0)
108             {
109                 return;
110             }
111         }
112         mixin("arr " ~ op ~ "= rhs.arr;");
113     }
114 
115     BitSet!I opBinary(string op)(const BitSet!I rhs) const
116     {
117         mixin("return BitSet!I(arr " ~ op ~ " rhs.arr);");
118     }
119 
120     BitSet!I dup() const
121     {
122         BitSet!I r;
123         r.arr = arr.dup;
124         return r;
125     }
126 
127     auto bitsSet() const
128     {
129         return arr.bitsSet.map!(x => I(x.to!(typeof(I.init.id))));
130     }
131 
132     void length(size_t l)
133     {
134         arr.length = l;
135     }
136 
137     size_t length() const
138     {
139         return arr.length;
140     }
141 
142     bool addOnce(I)(BitSet!I src)
143     {
144         bool r = false;
145         foreach (s; src.bitsSet)
146         {
147             if (!this[s])
148             {
149                 this[s] = true;
150                 r = true;
151             }
152         }
153         return r;
154     }
155 
156     bool addOnce(I i)
157     {
158         assert(i.id < typeof(I.init.id).max);
159         bool r = false;
160         if (!this[i])
161         {
162             this[i] = true;
163             r = true;
164         }
165         return r;
166     }
167 }