earley_omnitool/forest/compact_bocage/
node.rs

1use std::cell::Cell;
2use std::hint;
3
4use cfg::symbol::Symbol;
5
6pub use self::Node::*;
7use self::Tag::*;
8use forest::node_handle::{NodeHandle, NULL_HANDLE};
9
10pub struct Graph {
11    pub(crate) vec: Vec<Cell<u16>>,
12}
13
14impl Graph {
15    pub(crate) fn with_capacity(capacity: usize) -> Self {
16        Graph {
17            vec: Vec::with_capacity(capacity),
18        }
19    }
20
21    pub(crate) fn push(&mut self, node: Node) -> NodeHandle {
22        let position = self.vec.len() as u32;
23        let (node_repr, size) = node.to_repr(position);
24        unsafe {
25            self.vec
26                .extend(node_repr.fields[..size].iter().cloned().map(Cell::new));
27        }
28        NodeHandle(position)
29    }
30
31    pub(crate) fn set_up(&mut self, mut handle: NodeHandle, node: Node) {
32        let (node_repr, size) = node.to_repr(handle.0);
33        let mut current_handle = handle;
34        while current_handle.usize() < handle.usize() + size {
35            let current_node = self.get(current_handle);
36            self.push(current_node);
37            current_handle.0 += current_node.classify(current_handle.0).size() as u32;
38        }
39        for i in 0..size {
40            unsafe {
41                self.vec[handle.usize() + i].set(node_repr.fields[i]);
42            }
43        }
44        handle.0 += size as u32;
45        while handle.0 < current_handle.0 {
46            self.vec[handle.usize()].set(NopTag.to_u16());
47            handle.0 += 1;
48        }
49    }
50
51    pub(crate) fn get(&self, handle: NodeHandle) -> Node {
52        self.iter_from(handle).next().unwrap()
53    }
54
55    pub(crate) fn iter_from(&self, handle: NodeHandle) -> Iter {
56        Iter {
57            vec: &self.vec[..],
58            handle,
59        }
60    }
61}
62
63#[derive(Clone, Copy)]
64pub(crate) struct Iter<'a> {
65    pub(crate) vec: &'a [Cell<u16>],
66    pub(crate) handle: NodeHandle,
67}
68
69impl<'a> Iterator for Iter<'a> {
70    type Item = Node;
71
72    fn next(&mut self) -> Option<Node> {
73        unsafe {
74            let head = if let Some(head) = self.vec.get(self.handle.usize()).cloned() {
75                head.get()
76            } else {
77                return None;
78            };
79            let (tag, head) = get_and_erase_tag(head);
80            if let NopTag = tag {
81                self.handle.0 += 1;
82                self.next()
83            } else {
84                let mut node_repr = NodeRepr { fields: [0; 6] };
85                node_repr.fields[0] = head;
86                let slice = &self.vec[self.handle.usize() + 1..self.handle.usize() + tag.size()];
87                for (i, val) in slice.iter().enumerate() {
88                    node_repr.fields[1 + i] = val.get();
89                }
90                let result = node_repr.expand(tag, self.handle.0);
91                self.handle.0 += tag.size() as u32;
92                Some(result)
93            }
94        }
95    }
96}
97
98impl<'a> Iter<'a> {
99    #[inline]
100    pub(crate) fn peek(&mut self) -> Option<Node> {
101        self.clone().next()
102    }
103}
104
105// Node variants `Sum`/`Product` are better known in literature as `OR`/`AND`.
106#[derive(Copy, Clone, Debug, Eq, PartialEq)]
107pub enum Node {
108    Sum {
109        /// 8 bytes.
110        /// Invariant: count > 1.
111        /// Invariant: This node can only be directly followed by `Product`.
112        count: u32,
113        nonterminal: Symbol,
114    },
115    Product {
116        /// 12+ bytes.
117        action: u32,
118        left_factor: NodeHandle,
119        right_factor: Option<NodeHandle>,
120    },
121    NullingLeaf {
122        /// 4 bytes.
123        symbol: Symbol,
124    },
125    Evaluated {
126        /// 4 bytes.
127        symbol: Symbol,
128    },
129}
130
131#[derive(Clone, Copy)]
132union NodeRepr {
133    fields: [u16; 6],
134    small_sum: SmallSumRepr,
135    small_link: SmallLinkRepr,
136    medium_link: MediumLinkRepr,
137    small_product: SmallProductRepr,
138    small_leaf: SmallLeafRepr,
139    small_nulling_leaf: SmallNullingLeafRepr,
140    sum: SumRepr,
141    product: ProductRepr,
142    leaf: LeafRepr,
143    nop: NopRepr,
144}
145
146#[derive(Clone, Copy)]
147struct SmallSumRepr {
148    nonterminal: u8,
149    // smaller (big end position)
150    count: u8,
151}
152
153#[derive(Clone, Copy)]
154struct SumRepr {
155    count: u32,
156    nonterminal: Symbol,
157}
158
159#[derive(Clone, Copy)]
160struct SmallLinkRepr {
161    action: u8,
162    // smaller (big end position)
163    distance: u8,
164}
165
166#[derive(Clone, Copy)]
167struct MediumLinkRepr {
168    distance: u16,
169    action: u16,
170}
171
172#[derive(Clone, Copy)]
173struct SmallProductRepr {
174    left_distance: u8,
175    // smaller (big end position)
176    right_distance: u8,
177    action: u16,
178}
179
180#[derive(Clone, Copy)]
181#[repr(packed)]
182struct ProductRepr {
183    upper_action: u16,
184    lower_action: u16,
185    left_factor: NodeHandle,
186    right_factor: NodeHandle,
187}
188
189#[derive(Clone, Copy)]
190struct SmallNullingLeafRepr {
191    symbol: u16,
192}
193
194#[derive(Clone, Copy)]
195struct LeafRepr {
196    symbol: Symbol,
197}
198
199#[derive(Clone, Copy)]
200struct SmallLeafRepr {
201    symbol: u16,
202}
203
204#[derive(Clone, Copy)]
205struct NopRepr {
206    nop: u16,
207}
208
209#[derive(Copy, Clone, Eq, PartialEq, Debug)]
210pub(super) enum Tag {
211    SmallSumTag = 0b000 << TAG_BIT,
212    SmallLinkTag = 0b001 << TAG_BIT,
213    MediumLinkTag = 0b010 << TAG_BIT,
214    SmallProductTag = 0b011 << TAG_BIT,
215    SmallLeafTag = 0b100 << TAG_BIT,
216    // SmallNonnullingLeaf = 0b1000 << (TAG_BIT - 1),
217    SmallNullingLeafTag = 0b1001 << (TAG_BIT - 1),
218    LeafTag = 0b101 << TAG_BIT,
219    SumTag = 0b111 << TAG_BIT,
220    ProductTag = 0b110 << TAG_BIT,
221    NopTag = 0b1111_1111_1111_1111,
222}
223
224impl Tag {
225    #[inline]
226    fn from_u16(num: u16) -> Option<Self> {
227        let n = num & TAG_MASK;
228        if num == NopTag.to_u16() {
229            Some(NopTag)
230        } else if n == LeafTag.to_u16() {
231            Some(LeafTag)
232        } else if n == SumTag.to_u16() {
233            Some(SumTag)
234        } else if n == ProductTag.to_u16() {
235            Some(ProductTag)
236        } else if n == SmallSumTag.to_u16() {
237            Some(SmallSumTag)
238        } else if n == SmallLinkTag.to_u16() {
239            Some(SmallLinkTag)
240        } else if n == MediumLinkTag.to_u16() {
241            Some(MediumLinkTag)
242        } else if n == SmallProductTag.to_u16() {
243            Some(SmallProductTag)
244        } else if n == SmallLeafTag.to_u16() {
245            let n = num & SMALL_LEAF_TAG_MASK;
246            if n == SmallLeafTag.to_u16() {
247                Some(SmallLeafTag)
248            } else if n == SmallNullingLeafTag.to_u16() {
249                Some(SmallNullingLeafTag)
250            } else {
251                None
252            }
253        } else {
254            None
255        }
256    }
257
258    #[inline]
259    pub(super) fn to_u16(self) -> u16 {
260        match self {
261            SmallSumTag => 0b000 << TAG_BIT,
262            SmallLinkTag => 0b001 << TAG_BIT,
263            MediumLinkTag => 0b010 << TAG_BIT,
264            SmallProductTag => 0b011 << TAG_BIT,
265            SmallLeafTag => 0b100 << TAG_BIT,
266            // SmallNonnullingLeaf = 0b1000 << (TAG_BIT - 1),
267            SmallNullingLeafTag => 0b1001 << (TAG_BIT - 1),
268            LeafTag => 0b101 << TAG_BIT,
269            SumTag => 0b111 << TAG_BIT,
270            ProductTag => 0b110 << TAG_BIT,
271            NopTag => 0b1111_1111_1111_1111,
272        }
273    }
274
275    #[inline]
276    fn mask(self) -> u16 {
277        match self {
278            SmallSumTag => TAG_MASK,
279            SmallLinkTag => TAG_MASK,
280            MediumLinkTag => TAG_MASK,
281            SmallProductTag => TAG_MASK,
282            SmallLeafTag => SMALL_LEAF_TAG_MASK,
283            // SmallNonnullingLeaf = 0b1000 << (TAG_BIT - 1),
284            SmallNullingLeafTag => SMALL_LEAF_TAG_MASK,
285            LeafTag => TAG_MASK,
286            SumTag => TAG_MASK,
287            ProductTag => TAG_MASK,
288            NopTag => 0b1111_1111_1111_1111,
289        }
290    }
291
292    #[inline]
293    pub(super) fn size(self) -> usize {
294        match self {
295            SmallSumTag => 1,
296            SmallLinkTag => 1,
297            MediumLinkTag => 2,
298            SmallProductTag => 2,
299            SmallLeafTag => 1,
300            SmallNullingLeafTag => 1,
301            LeafTag => 4,
302            SumTag => 4,
303            ProductTag => 6,
304            NopTag => 1,
305        }
306    }
307}
308
309const TAG_BIT: usize = 5 + 8;
310const TAG_MASK: u16 = 0b111 << TAG_BIT;
311const SMALL_LEAF_TAG_MASK: u16 = 0b1111 << (TAG_BIT - 1);
312pub(super) const NULL_ACTION: u32 = !((TAG_MASK as u32) << 16);
313
314impl NodeRepr {
315    fn expand(self, tag: Tag, position: u32) -> Node {
316        unsafe {
317            match (self, tag) {
318                (
319                    NodeRepr {
320                        small_sum: SmallSumRepr { nonterminal, count },
321                    },
322                    SmallSumTag,
323                ) => Sum {
324                    nonterminal: Symbol::from(nonterminal as u32),
325                    count: count as u32,
326                },
327                (
328                    NodeRepr {
329                        sum: SumRepr { nonterminal, count },
330                    },
331                    SumTag,
332                ) => Sum { nonterminal, count },
333                (
334                    NodeRepr {
335                        small_link: SmallLinkRepr { distance, action },
336                    },
337                    SmallLinkTag,
338                ) => Product {
339                    action: action as u32,
340                    left_factor: NodeHandle(position - distance as u32),
341                    right_factor: None,
342                },
343                (
344                    NodeRepr {
345                        medium_link: MediumLinkRepr { distance, action },
346                    },
347                    MediumLinkTag,
348                ) => Product {
349                    action: action as u32,
350                    left_factor: NodeHandle(position - distance as u32),
351                    right_factor: None,
352                },
353                (
354                    NodeRepr {
355                        small_product:
356                            SmallProductRepr {
357                                right_distance,
358                                left_distance,
359                                action,
360                            },
361                    },
362                    SmallProductTag,
363                ) => Product {
364                    action: action as u32,
365                    left_factor: NodeHandle(position - left_distance as u32),
366                    right_factor: Some(NodeHandle(position - right_distance as u32)),
367                },
368                (
369                    NodeRepr {
370                        product:
371                            ProductRepr {
372                                upper_action,
373                                lower_action,
374                                left_factor,
375                                right_factor,
376                            },
377                    },
378                    ProductTag,
379                ) => Product {
380                    action: (upper_action as u32) << 16 | (lower_action as u32),
381                    left_factor,
382                    right_factor: right_factor.to_option(),
383                },
384                (
385                    NodeRepr {
386                        small_nulling_leaf: SmallNullingLeafRepr { symbol },
387                    },
388                    SmallNullingLeafTag,
389                ) => NullingLeaf {
390                    symbol: Symbol::from(symbol as u32),
391                },
392                (
393                    NodeRepr {
394                        small_leaf: SmallLeafRepr { symbol },
395                    },
396                    SmallLeafTag,
397                ) => Evaluated {
398                    symbol: Symbol::from(symbol as u32),
399                },
400                (
401                    NodeRepr {
402                        leaf: LeafRepr { symbol },
403                    },
404                    LeafTag,
405                ) => Evaluated { symbol },
406                _ => unreachable!(),
407            }
408        }
409    }
410}
411
412impl Node {
413    #[inline]
414    fn to_repr(self, position: u32) -> (NodeRepr, usize) {
415        let tag = self.classify(position);
416        unsafe {
417            let mut result = match (self, tag) {
418                (Sum { nonterminal, count }, SmallSumTag) => NodeRepr {
419                    small_sum: SmallSumRepr {
420                        nonterminal: nonterminal.usize() as u8,
421                        count: count as u8,
422                    },
423                },
424                (Sum { nonterminal, count }, SumTag) => NodeRepr {
425                    sum: SumRepr { nonterminal, count },
426                },
427                (
428                    Product {
429                        left_factor,
430                        right_factor: None,
431                        action,
432                    },
433                    SmallLinkTag,
434                ) => NodeRepr {
435                    small_link: SmallLinkRepr {
436                        distance: (position - left_factor.0) as u8,
437                        action: action as u8,
438                    },
439                },
440                (
441                    Product {
442                        left_factor,
443                        right_factor: None,
444                        action,
445                    },
446                    MediumLinkTag,
447                ) => NodeRepr {
448                    medium_link: MediumLinkRepr {
449                        distance: (position - left_factor.0) as u16,
450                        action: action as u16,
451                    },
452                },
453                (
454                    Product {
455                        left_factor,
456                        right_factor: Some(right),
457                        action,
458                    },
459                    SmallProductTag,
460                ) => NodeRepr {
461                    small_product: SmallProductRepr {
462                        right_distance: (position - right.0) as u8,
463                        left_distance: (position - left_factor.0) as u8,
464                        action: action as u16,
465                    },
466                },
467                (
468                    Product {
469                        left_factor,
470                        right_factor,
471                        action,
472                    },
473                    ProductTag,
474                ) => NodeRepr {
475                    product: ProductRepr {
476                        upper_action: (action >> 16) as u16,
477                        lower_action: action as u16,
478                        left_factor,
479                        right_factor: right_factor.unwrap_or(NULL_HANDLE),
480                    },
481                },
482                (NullingLeaf { symbol }, SmallNullingLeafTag) => NodeRepr {
483                    small_nulling_leaf: SmallNullingLeafRepr {
484                        symbol: symbol.usize() as u16,
485                    },
486                },
487                (NullingLeaf { symbol }, LeafTag) => NodeRepr {
488                    leaf: LeafRepr { symbol },
489                },
490                (Evaluated { symbol }, SmallLeafTag) => NodeRepr {
491                    small_leaf: SmallLeafRepr {
492                        symbol: symbol.usize() as u16,
493                    },
494                },
495                (Evaluated { symbol }, LeafTag) => NodeRepr {
496                    leaf: LeafRepr { symbol },
497                },
498                _ => unreachable!(),
499            };
500            result.fields[0] |= tag.to_u16();
501            (result, tag.size())
502        }
503    }
504
505    #[inline]
506    pub(super) fn classify(self, position: u32) -> Tag {
507        match self {
508            Product {
509                left_factor,
510                right_factor,
511                action,
512            } => match right_factor {
513                Some(handle) => {
514                    if position >= handle.0
515                        && position >= left_factor.0
516                        && position - handle.0 < (1 << 5)
517                        && position - left_factor.0 < (1 << 8)
518                        && action < (1 << 16)
519                    {
520                        SmallProductTag
521                    } else {
522                        ProductTag
523                    }
524                }
525                None => {
526                    if position >= left_factor.0
527                        && position - left_factor.0 < (1 << 5)
528                        && action < (1 << 8)
529                    {
530                        SmallLinkTag
531                    } else if position >= left_factor.0
532                        && position - left_factor.0 < (1 << (5 + 8))
533                        && action < (1 << 16)
534                    {
535                        MediumLinkTag
536                    } else {
537                        ProductTag
538                    }
539                }
540            },
541            NullingLeaf { symbol } => {
542                if symbol.usize() < (1 << (4 + 8)) {
543                    SmallNullingLeafTag
544                } else {
545                    LeafTag
546                }
547            }
548            Evaluated { symbol } => {
549                if symbol.usize() < (1 << (4 + 8)) {
550                    SmallLeafTag
551                } else {
552                    LeafTag
553                }
554            }
555            Sum { nonterminal, count } => {
556                if count < (1 << 5) && nonterminal.usize() < (1 << 8) {
557                    SmallSumTag
558                } else {
559                    SumTag
560                }
561            }
562        }
563    }
564}
565
566#[inline]
567unsafe fn unwrap_unchecked<T>(opt: Option<T>) -> T {
568    match opt {
569        Some(val) => val,
570        None => hint::unreachable_unchecked(),
571    }
572}
573
574#[inline]
575unsafe fn get_and_erase_tag(field: u16) -> (Tag, u16) {
576    let tag = unwrap_unchecked(Tag::from_u16(field));
577    (tag, field & !tag.mask())
578}