• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // This file is part of ICU4X. For terms of use, please see the file
2 // called LICENSE at the top level of the ICU4X source tree
3 // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4 
5 //! This module contains internal collections for the non-const builder.
6 
7 use super::super::branch_meta::BranchMeta;
8 use super::super::konst::ConstArrayBuilder;
9 use alloc::collections::VecDeque;
10 use alloc::vec::Vec;
11 
12 /// A trait applied to a data structure for building a ZeroTrie.
13 pub(crate) trait TrieBuilderStore {
14     /// Create a new empty store.
atbs_new_empty() -> Self15     fn atbs_new_empty() -> Self;
16 
17     /// Return the length in bytes of the store.
atbs_len(&self) -> usize18     fn atbs_len(&self) -> usize;
19 
20     /// Push a byte to the front of the store.
atbs_push_front(&mut self, byte: u8)21     fn atbs_push_front(&mut self, byte: u8);
22 
23     /// Push multiple bytes to the front of the store.
atbs_extend_front(&mut self, other: &[u8])24     fn atbs_extend_front(&mut self, other: &[u8]);
25 
26     /// Read the store into a `Vec<u8>`.
atbs_to_bytes(&self) -> Vec<u8>27     fn atbs_to_bytes(&self) -> Vec<u8>;
28 
29     /// Perform the operation `self[index] |= bits`
atbs_bitor_assign(&mut self, index: usize, bits: u8)30     fn atbs_bitor_assign(&mut self, index: usize, bits: u8);
31 
32     /// Swap the adjacent ranges `self[start..mid]` and `self[mid..limit]`.
atbs_swap_ranges(&mut self, start: usize, mid: usize, limit: usize)33     fn atbs_swap_ranges(&mut self, start: usize, mid: usize, limit: usize);
34 
35     /// Remove and return the first element in the store, or `None` if empty.
atbs_pop_front(&mut self) -> Option<u8>36     fn atbs_pop_front(&mut self) -> Option<u8>;
37 
38     /// Prepend `n` zeros to the front of the store.
atbs_prepend_n_zeros(&mut self, n: usize)39     fn atbs_prepend_n_zeros(&mut self, n: usize) {
40         let mut i = 0;
41         while i < n {
42             self.atbs_push_front(0);
43             i += 1;
44         }
45     }
46 }
47 
48 impl TrieBuilderStore for VecDeque<u8> {
atbs_new_empty() -> Self49     fn atbs_new_empty() -> Self {
50         VecDeque::new()
51     }
atbs_len(&self) -> usize52     fn atbs_len(&self) -> usize {
53         self.len()
54     }
atbs_push_front(&mut self, byte: u8)55     fn atbs_push_front(&mut self, byte: u8) {
56         self.push_front(byte);
57     }
atbs_extend_front(&mut self, other: &[u8])58     fn atbs_extend_front(&mut self, other: &[u8]) {
59         // TODO: No extend_front on VecDeque?
60         self.reserve(other.len());
61         for b in other.iter().rev() {
62             self.push_front(*b);
63         }
64     }
atbs_to_bytes(&self) -> Vec<u8>65     fn atbs_to_bytes(&self) -> Vec<u8> {
66         let mut v = Vec::with_capacity(self.len());
67         let (a, b) = self.as_slices();
68         v.extend(a);
69         v.extend(b);
70         v
71     }
atbs_bitor_assign(&mut self, index: usize, bits: u8)72     fn atbs_bitor_assign(&mut self, index: usize, bits: u8) {
73         self[index] |= bits;
74     }
atbs_swap_ranges(&mut self, mut start: usize, mut mid: usize, mut limit: usize)75     fn atbs_swap_ranges(&mut self, mut start: usize, mut mid: usize, mut limit: usize) {
76         if start > mid || mid > limit {
77             panic!("Invalid args to atbs_swap_ranges(): start > mid || mid > limit");
78         }
79         if limit > self.len() {
80             panic!(
81                 "Invalid args to atbs_swap_ranges(): limit out of range: {limit} > {}",
82                 self.len()
83             );
84         }
85         // The following algorithm is an in-place swap of two adjacent ranges of potentially
86         // different lengths. Would make a good coding interview question.
87         loop {
88             if start == mid || mid == limit {
89                 return;
90             }
91             let len0 = mid - start;
92             let len1 = limit - mid;
93             let mut i = start;
94             let mut j = limit - core::cmp::min(len0, len1);
95             while j < limit {
96                 self.swap(i, j);
97                 i += 1;
98                 j += 1;
99             }
100             if len0 < len1 {
101                 mid = start + len0;
102                 limit -= len0;
103             } else {
104                 start += len1;
105                 mid = limit - len1;
106             }
107         }
108     }
atbs_pop_front(&mut self) -> Option<u8>109     fn atbs_pop_front(&mut self) -> Option<u8> {
110         self.pop_front()
111     }
112 }
113 
114 /// A data structure that holds any number of [`BranchMeta`] items.
115 pub(crate) struct NonConstLengthsStack {
116     data: Vec<BranchMeta>,
117 }
118 
119 impl core::fmt::Debug for NonConstLengthsStack {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result120     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
121         self.as_slice().fmt(f)
122     }
123 }
124 
125 impl NonConstLengthsStack {
126     /// Creates a new empty [`NonConstLengthsStack`].
new() -> Self127     pub const fn new() -> Self {
128         Self { data: Vec::new() }
129     }
130 
131     /// Returns whether the stack is empty.
is_empty(&self) -> bool132     pub fn is_empty(&self) -> bool {
133         self.data.is_empty()
134     }
135 
136     /// Adds a [`BranchMeta`] to the stack.
push(&mut self, meta: BranchMeta)137     pub fn push(&mut self, meta: BranchMeta) {
138         self.data.push(meta);
139     }
140 
141     /// Returns a copy of the [`BranchMeta`] on the top of the stack, panicking if
142     /// the stack is empty.
peek_or_panic(&self) -> BranchMeta143     pub fn peek_or_panic(&self) -> BranchMeta {
144         *self.data.last().unwrap()
145     }
146 
147     /// Removes many [`BranchMeta`]s from the stack, returning them in a [`ConstArrayBuilder`].
pop_many_or_panic(&mut self, len: usize) -> ConstArrayBuilder<256, BranchMeta>148     pub fn pop_many_or_panic(&mut self, len: usize) -> ConstArrayBuilder<256, BranchMeta> {
149         debug_assert!(len <= 256);
150         let mut result = ConstArrayBuilder::new_empty([BranchMeta::default(); 256], 256);
151         let mut ix = 0;
152         loop {
153             if ix == len {
154                 break;
155             }
156             let i = self.data.len() - ix - 1;
157             // Won't panic because len <= 256
158             result = result.const_push_front_or_panic(match self.data.get(i) {
159                 Some(x) => *x,
160                 None => panic!("Not enough items in the ConstLengthsStack"),
161             });
162             ix += 1;
163         }
164         self.data.truncate(self.data.len() - len);
165         result
166     }
167 
168     /// Non-const function that returns the initialized elements as a slice.
as_slice(&self) -> &[BranchMeta]169     fn as_slice(&self) -> &[BranchMeta] {
170         &self.data
171     }
172 }
173 
174 #[cfg(test)]
175 mod tests {
176     use super::*;
177 
178     #[test]
test_swap_ranges()179     fn test_swap_ranges() {
180         let s = b"..abcdefghijkl=";
181         let mut s = s.iter().copied().collect::<VecDeque<u8>>();
182         s.atbs_swap_ranges(2, 7, 14);
183         assert_eq!(s.atbs_to_bytes(), b"..fghijklabcde=");
184     }
185 }
186