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