1use std::fmt;
3use std::str::FromStr;
4use crate::vid;
5
6#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
12pub struct NID { n: u64 }
13
14#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
16pub struct NidFun { nid:NID }
17
18
19const INV:u64 = 1<<63; const VAR:u64 = 1<<62; const T:u64 = 1<<61; const RVAR:u64 = 1<<60; const F:u64 = 1<<59;
48
49const IDX_MASK:u64 = (1<<32)-1;
51
52pub const O:NID = NID{n: T};
54pub const I:NID = NID{ n:T|INV };
56
57type VidBits = usize;
61
62#[inline(always)] fn vid_bits(x:NID)->VidBits { ((x.n & !(INV|VAR)) >> 32) as VidBits}
64
65#[inline(always)] const fn nv(v:VidBits)->NID { NID { n:((v as u64) << 32)|VAR }}
69
70#[inline(always)] fn nvi(v:VidBits,i:usize)->NID { NID{n: ((v as u64) << 32) + i as u64} }
72
73const NOVAR:VidBits = (1<<26) as VidBits; const TOP:VidBits = (T>>32) as VidBits; fn vid_to_bits(v:vid::VID)->VidBits {
77 if v.is_nov() { NOVAR }
78 else if v.is_top() { TOP }
79 else if v.is_var() { v.var_ix() | (RVAR>>32) as VidBits }
80 else if v.is_vir() { v.vir_ix() as VidBits }
81 else { panic!("unknown vid::VID {:?}?", v) }}
82
83fn bits_to_vid(o:VidBits)->vid::VID {
84 if o == TOP { vid::VID::top() }
85 else if o == NOVAR { vid::VID::nov() }
86 else if o & (RVAR>>32) as VidBits > 0 { vid::VID::var((o & !(RVAR>>32) as VidBits) as u32) }
87 else { vid::VID::vir(o as u32) }}
88
89
90impl std::ops::Not for NID {
91 type Output = NID;
92 fn not(self)-> NID {NID { n: self.n^INV }}}
93
94
95impl fmt::Display for NID {
97 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
98 if self.is_const() { if self.is_inv() { write!(f, "I") } else { write!(f, "O") } }
99 else if self.is_fun() {
100 let fnid = self.to_fun().unwrap();
101 let ar:u8 = fnid.arity(); let ft:u32 = fnid.tbl();
104 if ar == 2 { write!(f, "t{:04b}", ft) }
105 else { write!(f, "f{}.{:X}", ar, ft) }}
106 else {
107 if self.is_inv() { write!(f, "!")?; }
108 if self.is_vid() { write!(f, "{}", self.vid()) }
109 else if self.is_ixn() { write!(f, "#{:X}", self.idx()) }
110 else { write!(f, "{}.{:X}", self.vid(), self.idx()) }}}}
111
112impl fmt::Debug for NID { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self) }}
115
116
117impl FromStr for NID {
118 type Err = String;
119
120 fn from_str(word: &str) -> Result<Self, Self::Err> {
121 match word {
122 "O" => Ok(O),
123 "I" => Ok(I),
124 _ => {
125 let (a, b) = if let Some(ix) = word.find('.') { word.split_at(ix) } else { (word, "") };
126 let mut ch = a.chars().peekable();
127 let mut inv: bool = false;
128 if ch.peek().unwrap() == &'!' { ch.next(); inv = true }
129 macro_rules! num_suffix {
130 ($radix:expr, $ch:expr) => { usize::from_str_radix(&$ch.collect::<String>(), $radix) }}
131 let c = ch.next().unwrap();
132 if c == 'x' || 'c'=='v' {
134 if let Ok(n) = num_suffix!(16, ch) {
135 let v = if c == 'x' { vid::VID::var(n as u32) } else { vid::VID::vir(n as u32) };
136 if b.is_empty() { Ok(NID::from_vid(v).inv_if(inv)) }
137 else if let Ok(ix) = usize::from_str_radix(&b[1..], 16) {
138 Ok(NID::from_vid_idx(v, ix).inv_if(inv) )}
139 else { Err(format!("bad index after '.': {}", word)) }}
140 else { Err(format!("malformed variable: {}", word)) }}
141 else { match c {
142 '#' => if let Ok(n) = num_suffix!(16, ch) { Ok(NID::ixn(n).inv_if(inv)) }
143 else { Err(format!("bad ixn: {}", word)) }
144 'f' =>
145 if let Some(i) = word.find('.') {
146 let (a, b) = word.split_at(i);
147 if let Ok(ar) = num_suffix!(16, a.chars().skip(1)) {
148 if let Ok(tb) = num_suffix!(16, b.chars().skip(1)) {
149 Ok(NID::fun(ar as u8, tb as u32).to_nid().inv_if(inv))}
150 else { Err(format!("bad fun arity: {}", word)) }}
151 else { Err(format!("bad fun code: {}", word)) }}
152 else if let Ok(n) = num_suffix!(16, ch) {
153 let ar: u8 = if n >= 2 << 16 { 5 }
154 else if n > 2 << 8 { 4 }
155 else if n > 2 << 4 { 3 }
156 else { 2 };
157 Ok(NID::fun(ar, n as u32).to_nid().inv_if(inv))}
158 else { Err(format!("bad fun: {}", word)) }
159 't' =>
160 if ch.clone().count() == 4 {
161 if let Ok(tb) = num_suffix!(2, ch) {
162 Ok(NID::fun(2, tb as u32).to_nid().inv_if(inv))}
163 else { Err(format!("bad table (expect 4 bits): {}", word)) }}
164 else { Err(format!("bad length for table (expect 4 bits): {}", word)) }
165 _ => Err(format!("{}?", word))}}}}}}
166
167
168#[test] fn test_nids() {
169 let new = |n| { NID{n} };
170 assert_eq!(O.n, 2305843009213693952); assert_eq!(O, new(0x2000000000000000));
171 assert_eq!(I.n, 11529215046068469760); assert_eq!(I, new(0xa000000000000000));
172 assert_eq!(NID::vir(0), new(0x4000000000000000u64));
173 assert_eq!(NID::var(0), new(0x5000000000000000u64));
174 assert_eq!(NID::vir(1), new(0x4000000100000000u64));
175 assert!(vid_bits(NID::vir(0)) < vid_bits(NID::var(0)));
176 assert_eq!(nvi(0,0), new(0x0000000000000000u64));
177 assert_eq!(nvi(1,0), new(0x0000000100000000u64)); }
178
179#[test] fn test_var() {
180 assert_eq!(vid_bits(O), 536_870_912, "var(O)");
181 assert_eq!(vid_bits(I), vid_bits(O), "INV bit shouldn't be part of variable");
182 assert_eq!(vid_bits(NID::vir(0)), 0);
183 assert_eq!(vid_bits(NID::var(0)), 268_435_456);}
184
185#[test] fn test_cmp() {
186 let v = |x:usize|->NID { nv(x) }; let x=|x:u32|->NID { NID::var(x) };
187 let o=vid_bits; let n=|x:NID|x.vid();
188 assert!(o(O) == o(I), "old:no=no"); assert!(n(O) == n(I), "new:no=no");
189 assert!(o(O) > o(v(0)), "old:no>v0"); assert!(n(O).is_below(&n(v(0))), "new:no bel v0");
190 assert!(o(O) > o(x(0)), "old:no>x0"); assert!(n(O).is_below(&n(x(0))), "new:no bel x0");
191 assert!(o(v(0)) < o(x(0)), "old:v0>x0"); assert!(n(v(0)).is_above(&n(x(0))), "new:v0 abv x0");
192 assert!(o(v(1)) < o(x(0)), "old:v1<x0"); assert!(n(v(1)).is_above(&n(x(0))), "new:v1 abv x0");}
193
194
195
196impl NID {
197 #[inline(always)] pub fn o()->Self { O }
198 #[inline(always)] pub fn i()->Self { I }
199 #[inline(always)] pub fn from_bit(b:bool)->Self { if b { I } else { O } }
200 #[inline(always)] pub fn to_bit(&self)->bool { self != &O }
201
202 #[inline(always)] pub const fn var(v:u32)->Self { nv((v | (RVAR>>32) as u32) as VidBits) }
203 #[inline(always)] pub const fn vir(v:u32)->Self { nv(v as VidBits) }
204 #[inline(always)] pub fn from_var(v:vid::VID)->Self { Self::var(v.var_ix() as u32)}
205 #[inline(always)] pub fn from_vir(v:vid::VID)->Self { Self::vir(v.vir_ix() as u32)}
206
207 #[inline(always)] pub fn from_vid(v:vid::VID)->Self { nv(vid_to_bits(v)) }
208 #[inline(always)] pub fn from_vid_idx(v:vid::VID, i:usize)->Self { nvi(vid_to_bits(v), i) }
209 #[inline(always)] pub fn vid(&self)->vid::VID { bits_to_vid(vid_bits(*self)) }
210 #[inline(always)] pub fn ixn(ix:usize)->Self { nvi(NOVAR, ix) }
212
213 #[inline(always)] pub fn is_const(&self)->bool { (self.n & T) != 0 }
215
216 #[inline(always)] pub fn is_vid(&self)->bool { (self.n & VAR) != 0 }
218
219 #[inline(always)] pub fn is_var(&self)->bool { self.is_vid() && self.vid().is_var() }
221
222 #[inline(always)] pub fn is_vir(&self)->bool { self.is_vid() && self.vid().is_vir() }
224
225 #[inline(always)] pub fn is_lit(&self)->bool { self.is_vid() | self.is_const()}
227
228 #[inline(always)] pub fn is_inv(&self)->bool { (self.n & INV) != 0 }
230
231 #[inline(always)] pub fn inv_if(&self, cond:bool)->NID {
233 if cond { NID { n: self.n ^ INV }} else { *self }}
234
235 #[inline(always)] pub fn is_ixn(self)->bool { (self.n & (F|T|VAR) == 0) && vid_bits(self)==NOVAR }
237
238 #[inline(always)] pub fn idx(self)->usize { (self.n & IDX_MASK) as usize }
240
241 #[inline(always)] pub fn raw(self)->NID { NID{ n: self.n & !INV }}
244
245 #[inline(always)] pub const fn fun(arity:u8, tbl:u32)->NidFun {
247 NidFun { nid: NID { n:F+(((1<<(1<<arity)) -1) & tbl as u64)+((arity as u64)<< 32)}} }
248
249 #[inline(always)] pub fn is_fun(&self)->bool { self.n & F == F }
251 #[inline(always)] pub fn to_fun(&self)->Option<NidFun> {
252 if self.is_fun() { Some(NidFun { nid:*self }) } else { None }}
253
254 #[inline(always)] pub fn tbl(&self)->Option<u32> { if self.is_fun(){ Some(self.idx() as u32)} else {None} }
255
256 #[inline] pub fn might_depend_on(&self, v:vid::VID)->bool {
259 if self.is_const() { false }
260 else if self.is_vid() { self.vid() == v }
261 else { let sv = self.vid(); sv == v || sv.is_above(&v) }}
262
263 #[inline] pub fn _from_u64(x:u64)->Self { NID{n:x} }
265 #[inline] pub fn _to_u64(&self)->u64 { self.n }
266}
267
268#[test] fn test_tbl_fmt() {
269 assert_eq!("t1110", format!("{}", NID::fun(2, 0b1110).to_nid()));
270 assert_eq!("f3.FC", format!("{}", NID::fun(3, 0xFC).to_nid()));}
271
272include!("nid-fun.rs");
273
274#[allow(non_upper_case_globals)]
276pub mod named {
277 use super::NID;
278 pub const x0:NID = NID::var(0);
279 pub const x1:NID = NID::var(1);
280 pub const x2:NID = NID::var(2);
281 pub const x3:NID = NID::var(3);
282 pub const x4:NID = NID::var(4);
283 pub const v0:NID = NID::vir(0);
284 pub const v1:NID = NID::vir(1);
285 pub const v2:NID = NID::vir(2);
286 pub const v3:NID = NID::vir(3);
287 pub const v4:NID = NID::vir(4);
288}