icu_collections/char16trie/
trie.rs1#[cfg(feature = "alloc")]
6use alloc::string::String;
7use yoke::Yokeable;
8use zerofrom::ZeroFrom;
9use zerovec::{ZeroSlice, ZeroVec};
10
11const MAX_BRANCH_LINEAR_SUB_NODE_LENGTH: usize = 5;
19
20const MIN_LINEAR_MATCH: u16 = 0x30;
22const MAX_LINEAR_MATCH_LENGTH: u16 = 0x10;
23
24const MIN_VALUE_LEAD: u16 = MIN_LINEAR_MATCH + MAX_LINEAR_MATCH_LENGTH; const NODE_TYPE_MASK: u16 = MIN_VALUE_LEAD - 1; const VALUE_IS_FINAL: u16 = 0x8000;
32
33const MAX_ONE_UNIT_VALUE: u16 = 0x3fff;
35
36const MIN_TWO_UNIT_VALUE_LEAD: u16 = MAX_ONE_UNIT_VALUE + 1; const MAX_ONE_UNIT_NODE_VALUE: u16 = 0xff;
39
40const MIN_TWO_UNIT_NODE_VALUE_LEAD: u16 = MIN_VALUE_LEAD + ((MAX_ONE_UNIT_NODE_VALUE + 1) << 6); const THREE_UNIT_NODE_VALUE_LEAD: u16 = 0x7fc0;
43
44const THREE_UNIT_VALUE_LEAD: u16 = 0x7fff;
45
46const MAX_ONE_UNIT_DELTA: u16 = 0xfbff;
48const MIN_TWO_UNIT_DELTA_LEAD: u16 = MAX_ONE_UNIT_DELTA + 1; const THREE_UNIT_DELTA_LEAD: u16 = 0xffff;
50
51fn skip_value(pos: usize, lead: u16) -> usize {
52 if lead < MIN_TWO_UNIT_VALUE_LEAD {
53 pos
54 } else if lead < THREE_UNIT_VALUE_LEAD {
55 pos + 1
56 } else {
57 pos + 2
58 }
59}
60
61fn skip_node_value(pos: usize, lead: u16) -> usize {
62 if lead < MIN_TWO_UNIT_NODE_VALUE_LEAD {
63 pos
64 } else if lead < THREE_UNIT_NODE_VALUE_LEAD {
65 pos + 1
66 } else {
67 pos + 2
68 }
69}
70
71#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
82#[cfg_attr(feature = "databake", derive(databake::Bake))]
83#[cfg_attr(feature = "databake", databake(path = icu_collections::char16trie))]
84#[derive(#[automatically_derived]#[allow(clippy::exhaustive_structs)]
impl<'data> ::core::clone::Clone for Char16Trie<'data> {
#[inline]
fn clone(&self) -> Self {
Char16Trie { data: ::core::clone::Clone::clone(&self.data) }
}
}Clone, #[automatically_derived]#[allow(clippy::exhaustive_structs)]
impl<'data> ::core::fmt::Debug for Char16Trie<'data> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field1_finish(f,
"Char16Trie data", &&self.data)
}
}Debug, #[automatically_derived]#[allow(clippy::exhaustive_structs)]
impl<'data> ::core::marker::StructuralPartialEq for Char16Trie<'data> { }
#[automatically_derived]#[allow(clippy::exhaustive_structs)]
impl<'data> ::core::cmp::PartialEq for Char16Trie<'data> {
#[inline]
fn eq(&self, other: &Self) -> bool { self.data == other.data }
}PartialEq, #[automatically_derived]#[allow(clippy::exhaustive_structs)]
impl<'data> ::core::cmp::Eq for Char16Trie<'data> {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<ZeroVec<'data, u16>>;
}
}Eq, impl<'zf, 'zf_inner> zerofrom::ZeroFrom<'zf, Char16Trie<'zf_inner>> for
Char16Trie<'zf> where {
fn zero_from(this: &'zf Char16Trie<'zf_inner>) -> Self {
match *this {
Char16Trie { data: ref __binding_0 } => {
Char16Trie {
data: <ZeroVec<'zf, u16> as
zerofrom::ZeroFrom<'zf,
ZeroVec<'zf_inner, u16>>>::zero_from(__binding_0),
}
}
}
}
}ZeroFrom, unsafe impl<'yoke> yoke::Yokeable<'yoke> for Char16Trie<'static> where {
type Output = Char16Trie<'yoke>;
#[inline]
fn transform(&'yoke self) -> &'yoke Self::Output {
if false { let _: *const &'yoke Self::Output = &raw const self; }
self
}
#[inline]
fn transform_owned(self) -> Self::Output { self }
#[inline]
unsafe fn make(from: Self::Output) -> Self {
::core::mem::transmute::<Self::Output, Self>(from)
}
#[inline]
fn transform_mut<F>(&'yoke mut self, f: F) where F: 'static +
for<'_yoke> FnOnce(&'_yoke mut Self::Output) {
let y = unsafe { &mut *(self as *mut Self as *mut Self::Output) };
f(y)
}
}Yokeable)]
85#[allow(clippy::exhaustive_structs)] pub struct Char16Trie<'data> {
87 #[cfg_attr(feature = "serde", serde(borrow, alias = "trie_data"))]
89 #[doc(hidden)] pub data: ZeroVec<'data, u16>,
91}
92
93impl<'data> Char16Trie<'data> {
94 #[inline]
96 pub fn new(data: ZeroVec<'data, u16>) -> Self {
97 Self { data }
98 }
99
100 #[inline]
102 pub fn cursor(&self) -> Char16TrieCursor<'_> {
103 Char16TrieCursor::new(&self.data)
104 }
105
106 #[deprecated(since = "2.4.0", note = "use `Char16Trie::cursor`")]
108 #[allow(deprecated)]
109 #[inline]
110 pub fn iter(&self) -> Char16TrieIterator<'_> {
111 Char16TrieIterator::new(&self.data)
112 }
113
114 #[cfg(feature = "alloc")]
137 pub fn iter2(&self) -> impl Iterator<Item = (String, i32)> + '_ {
138 let cursor = self.cursor();
139 let mut root_value = cursor.value();
140 let mut stack = alloc::vec![(cursor, 0)];
141 let mut prefix = String::new();
142 let mut lead_surrogate = None;
143 core::iter::from_fn(move || {
144 if let Some(v) = root_value.take() {
145 return Some((String::new(), v));
146 }
147 while let Some((cursor, i)) = stack.last_mut() {
148 let mut next_cursor = cursor.clone();
149 if let Some(c) = next_cursor.probe(*i) {
150 *i += 1;
151
152 if let Some(lead) = lead_surrogate.take() {
153 prefix.push(
154 char::decode_utf16([lead, c])
155 .next()
156 .and_then(Result::ok)
157 .unwrap_or(char::REPLACEMENT_CHARACTER),
158 );
159 } else if matches!(c, 0xD800..0xDC00) {
160 lead_surrogate = Some(c);
161 } else {
162 prefix
163 .push(char::from_u32(c as u32).unwrap_or(char::REPLACEMENT_CHARACTER));
164 }
165
166 let v = next_cursor.value();
167 stack.push((next_cursor, 0));
168 if let Some(v) = v {
169 return Some((prefix.clone(), v));
170 }
171 } else {
172 stack.pop();
173 if lead_surrogate.take().is_none()
174 && let Some(ch @ '\u{10000}'..) = prefix.pop()
175 {
176 lead_surrogate = Some(u16_lead(ch as u32));
177 }
178 }
179 }
180 None
181 })
182 }
183}
184
185#[derive(#[automatically_derived]impl<'a> ::core::clone::Clone for Char16TrieCursor<'a>
{
#[inline]
fn clone(&self) -> Self {
Char16TrieCursor {
trie: ::core::clone::Clone::clone(&self.trie),
pos: ::core::clone::Clone::clone(&self.pos),
remaining_match_length: ::core::clone::Clone::clone(&self.remaining_match_length),
}
}
}Clone, #[automatically_derived]impl<'a> ::core::fmt::Debug for Char16TrieCursor<'a> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field3_finish(f,
"Char16TrieCursor trie pos remaining_match_length", &self.trie,
&self.pos, &&self.remaining_match_length)
}
}Debug)]
187pub struct Char16TrieCursor<'a> {
188 trie: &'a ZeroSlice<u16>,
190 pos: Option<usize>,
192 remaining_match_length: Option<u8>,
195}
196
197#[deprecated(since = "2.4.0", note = "use `Char16TrieCursor`")]
199#[derive(#[automatically_derived]impl<'a> ::core::clone::Clone for
Char16TrieIterator<'a> {
#[inline]
fn clone(&self) -> Self {
Char16TrieIterator(::core::clone::Clone::clone(&self.0))
}
}Clone, #[automatically_derived]impl<'a> ::core::fmt::Debug for Char16TrieIterator<'a>
{
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field1_finish(f,
"Char16TrieIterator", &&self.0)
}
}Debug)]
200pub struct Char16TrieIterator<'a>(Char16TrieCursor<'a>);
201
202#[deprecated(since = "2.4.0", note = "use `Char16TrieCursor`")]
204#[derive(#[automatically_derived]#[doc(hidden)]#[allow(clippy::exhaustive_enums)]
unsafe impl ::core::clone::TrivialClone for TrieResult { }
#[automatically_derived]#[allow(clippy::exhaustive_enums)]
impl ::core::clone::Clone for TrieResult {
#[inline]
fn clone(&self) -> Self {
let _: ::core::clone::AssertParamIsClone<i32>;
*self
}
}Clone, #[automatically_derived]#[allow(clippy::exhaustive_enums)]
impl ::core::marker::Copy for TrieResult { }Copy, #[automatically_derived]#[allow(clippy::exhaustive_enums)]
impl ::core::fmt::Debug for TrieResult {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Self::NoMatch => ::core::fmt::Formatter::write_str(f, "NoMatch"),
Self::NoValue => ::core::fmt::Formatter::write_str(f, "NoValue"),
Self::FinalValue(__self_0) =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"FinalValue", &__self_0),
Self::Intermediate(__self_0) =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"Intermediate", &__self_0),
}
}
}Debug, #[automatically_derived]#[allow(clippy::exhaustive_enums)]
impl ::core::marker::StructuralPartialEq for TrieResult { }
#[automatically_derived]#[allow(clippy::exhaustive_enums)]
impl ::core::cmp::PartialEq for TrieResult {
#[inline]
fn eq(&self, other: &Self) -> bool {
::core::intrinsics::discriminant_value(self) ==
::core::intrinsics::discriminant_value(other) &&
match (self, other) {
(Self::FinalValue(__self_0), Self::FinalValue(__arg1_0)) =>
__self_0 == __arg1_0,
(Self::Intermediate(__self_0), Self::Intermediate(__arg1_0))
=> __self_0 == __arg1_0,
_ => true,
}
}
}PartialEq)]
205#[allow(clippy::exhaustive_enums)]
206pub enum TrieResult {
207 NoMatch,
211 NoValue,
214 FinalValue(i32),
218 Intermediate(i32),
222}
223
224fn u16_lead(supplementary: u32) -> u16 {
229 (((supplementary) >> 10) + 0xd7c0) as u16
230}
231
232fn u16_tail(supplementary: u32) -> u16 {
237 (((supplementary) & 0x3ff) | 0xdc00) as u16
238}
239
240impl<'a> Char16TrieCursor<'a> {
241 #[inline]
243 pub fn new(trie: &'a ZeroSlice<u16>) -> Self {
244 Self {
245 trie,
246 pos: Some(0),
247 remaining_match_length: None,
248 }
249 }
250
251 #[inline]
275 pub fn step(&mut self, c: char) {
276 self.step32(c as u32);
277 }
278
279 #[inline]
303 pub fn step32(&mut self, c: u32) {
304 let c = if let Ok(c) = u16::try_from(c) {
305 c
306 } else {
307 self.step16(u16_lead(c));
308 u16_tail(c)
309 };
310 self.step16(c);
311 }
312
313 #[inline]
337 pub fn step16(&mut self, c: u16) {
338 let Some(pos) = self.pos else {
339 return;
340 };
341 self.pos = if let Some(length) = self.remaining_match_length {
342 if Some(c) == self.trie.get(pos) {
344 self.remaining_match_length = length.checked_sub(1);
345 Some(pos + 1)
346 } else {
347 None
348 }
349 } else {
350 self.next_impl(pos, c)
351 };
352 }
353
354 #[cfg(feature = "alloc")]
355 fn probe(&mut self, mut index: usize) -> Option<u16> {
356 let mut pos = self.pos?;
357 if let Some(length) = self.remaining_match_length {
358 if index > 0 {
359 return None;
360 }
361 let unit = self.trie.get(pos)?;
362 self.remaining_match_length = length.checked_sub(1);
363 self.pos = Some(pos + 1);
364 return Some(unit);
365 }
366 let mut node = self.trie.get(pos)?;
367 pos += 1;
368 if node >= MIN_VALUE_LEAD {
369 if (node & VALUE_IS_FINAL) != 0 {
370 return None;
371 }
372 pos = skip_node_value(pos, node);
374 node &= NODE_TYPE_MASK;
375 }
376 if node >= MIN_LINEAR_MATCH {
377 if index > 0 {
378 return None;
379 }
380 let length = (node - MIN_LINEAR_MATCH) as u8;
381 let unit = self.trie.get(pos)?;
382 self.remaining_match_length = length.checked_sub(1);
383 self.pos = Some(pos + 1);
384 return Some(unit);
385 }
386 let mut length = node as usize;
387 if length == 0 {
388 length = self.trie.get(pos)? as usize;
389 pos += 1;
390 }
391 length += 1;
392 if index >= length {
393 return None;
394 }
395
396 while length > MAX_BRANCH_LINEAR_SUB_NODE_LENGTH {
399 let half = length >> 1;
400 if index < half {
401 length = half;
402 pos = self.jump_by_delta(pos + 1)?;
403 } else {
404 index -= half;
405 length -= half;
406 pos = self.skip_delta(pos + 1)?;
407 }
408 }
409 while index > 0 {
411 index -= 1;
412 length -= 1;
413 pos = self.skip_value(pos + 1)?;
414 }
415 let unit = self.trie.get(pos)?;
416 pos += 1;
417 if length > 1 {
418 let node = self.trie.get(pos)?;
419 if node & VALUE_IS_FINAL == 0 {
420 pos += 1;
422
423 if node < MIN_TWO_UNIT_VALUE_LEAD {
424 pos += node as usize;
425 } else if node < THREE_UNIT_VALUE_LEAD {
426 pos += (((node - MIN_TWO_UNIT_VALUE_LEAD) as u32) << 16) as usize
427 | self.trie.get(pos)? as usize;
428 pos += 1;
429 } else {
430 pos +=
431 ((self.trie.get(pos)? as usize) << 16) | self.trie.get(pos + 1)? as usize;
432 pos += 2;
433 }
434 }
435 }
436 self.pos = Some(pos);
437 Some(unit)
438 }
439
440 #[inline]
442 pub fn value(&self) -> Option<i32> {
443 if self.remaining_match_length.is_some() {
444 return None;
445 }
446 let pos = self.pos?;
447 let lead_unit = self.trie.get(pos)?;
448 if lead_unit < MIN_VALUE_LEAD {
449 None
450 } else if lead_unit & VALUE_IS_FINAL != 0 {
451 let v = self.read_value(pos + 1, lead_unit & 0x7fff);
452 if true {
if !v.is_some() {
::core::panicking::panic("assertion failed: v.is_some()")
};
};debug_assert!(v.is_some());
453 Some(v.unwrap_or(0))
454 } else {
455 let v = self.read_node_value(pos + 1, lead_unit);
456 if true {
if !v.is_some() {
::core::panicking::panic("assertion failed: v.is_some()")
};
};debug_assert!(v.is_some());
457 Some(v.unwrap_or(0))
458 }
459 }
460
461 #[inline]
466 pub fn is_empty(&self) -> bool {
467 let Some(pos) = self.pos else {
468 return true;
469 };
470 self.remaining_match_length.is_none()
471 && self.trie.get(pos).is_none_or(|u| u & VALUE_IS_FINAL != 0)
472 }
473
474 fn branch_next(&self, mut pos: usize, mut length: usize, in_unit: u16) -> Option<usize> {
475 if length == 0 {
476 length = self.trie.get(pos)? as usize;
477 pos += 1;
478 }
479 length += 1;
480
481 while length > MAX_BRANCH_LINEAR_SUB_NODE_LENGTH {
484 if in_unit < self.trie.get(pos)? {
485 length >>= 1;
486 pos = self.jump_by_delta(pos + 1)?;
487 } else {
488 length = length - (length >> 1);
489 pos = self.skip_delta(pos + 1)?;
490 }
491 }
492 loop {
496 if in_unit == self.trie.get(pos)? {
497 pos += 1;
498 let node = self.trie.get(pos)?;
499 if node & VALUE_IS_FINAL != 0 {
500 return Some(pos);
501 }
502 pos += 1;
504
505 if node < MIN_TWO_UNIT_VALUE_LEAD {
506 pos += node as usize;
507 } else if node < THREE_UNIT_VALUE_LEAD {
508 pos += (((node - MIN_TWO_UNIT_VALUE_LEAD) as u32) << 16) as usize
509 | self.trie.get(pos)? as usize;
510 pos += 1;
511 } else {
512 pos +=
513 ((self.trie.get(pos)? as usize) << 16) | self.trie.get(pos + 1)? as usize;
514 pos += 2;
515 }
516 return Some(pos);
517 }
518 length -= 1;
519 pos = self.skip_value(pos + 1)?;
520 if length <= 1 {
521 break;
522 }
523 }
524
525 (in_unit == self.trie.get(pos)?).then_some(pos + 1)
526 }
527
528 fn next_impl(&mut self, pos: usize, in_unit: u16) -> Option<usize> {
529 let mut node = self.trie.get(pos)?;
530 let mut pos = pos + 1;
531 loop {
532 if node < MIN_LINEAR_MATCH {
533 return self.branch_next(pos, node as usize, in_unit);
534 } else if node < MIN_VALUE_LEAD {
535 let length = (node - MIN_LINEAR_MATCH) as u8;
537 if in_unit == self.trie.get(pos)? {
538 self.remaining_match_length = length.checked_sub(1);
539 return Some(pos + 1);
540 }
541 break;
543 } else if (node & VALUE_IS_FINAL) != 0 {
544 break;
546 } else {
547 pos = skip_node_value(pos, node);
549 node &= NODE_TYPE_MASK;
550 }
551 }
552 None
553 }
554
555 #[inline(always)] fn jump_by_delta(&self, pos: usize) -> Option<usize> {
557 let delta = self.trie.get(pos)?;
558 let v = if delta < MIN_TWO_UNIT_DELTA_LEAD {
559 pos + 1 + delta as usize
561 } else if delta == THREE_UNIT_DELTA_LEAD {
562 let delta =
563 ((self.trie.get(pos + 1)? as usize) << 16) | (self.trie.get(pos + 2)? as usize);
564 pos + delta + 3
565 } else {
566 let delta = (((delta - MIN_TWO_UNIT_DELTA_LEAD) as usize) << 16)
567 | (self.trie.get(pos + 1)? as usize);
568 pos + delta + 2
569 };
570 Some(v)
571 }
572
573 #[inline(always)] fn skip_value(&self, pos: usize) -> Option<usize> {
575 let lead_unit = self.trie.get(pos)?;
576 Some(skip_value(pos + 1, lead_unit & 0x7fff))
577 }
578
579 #[inline(always)] fn skip_delta(&self, pos: usize) -> Option<usize> {
581 let delta = self.trie.get(pos)?;
582 let v = if delta < MIN_TWO_UNIT_DELTA_LEAD {
583 pos + 1
584 } else if delta == THREE_UNIT_DELTA_LEAD {
585 pos + 3
586 } else {
587 pos + 2
588 };
589 Some(v)
590 }
591
592 #[inline(always)] fn read_value(&self, pos: usize, lead_unit: u16) -> Option<i32> {
594 let v = if lead_unit < MIN_TWO_UNIT_VALUE_LEAD {
595 lead_unit.into()
596 } else if lead_unit < THREE_UNIT_VALUE_LEAD {
597 (((lead_unit - MIN_TWO_UNIT_VALUE_LEAD) as i32) << 16) | self.trie.get(pos)? as i32
598 } else {
599 ((self.trie.get(pos)? as i32) << 16) | self.trie.get(pos + 1)? as i32
600 };
601 Some(v)
602 }
603
604 #[inline(always)] fn read_node_value(&self, pos: usize, lead_unit: u16) -> Option<i32> {
606 let v = if lead_unit < (MIN_TWO_UNIT_NODE_VALUE_LEAD) {
607 ((lead_unit >> 6) - 1).into()
608 } else if lead_unit < THREE_UNIT_NODE_VALUE_LEAD {
609 ((((lead_unit & 0x7fc0) - MIN_TWO_UNIT_NODE_VALUE_LEAD) as i32) << 10)
610 | self.trie.get(pos)? as i32
611 } else {
612 ((self.trie.get(pos)? as i32) << 16) | self.trie.get(pos + 1)? as i32
613 };
614 Some(v)
615 }
616}
617
618impl core::fmt::Write for Char16TrieCursor<'_> {
619 fn write_str(&mut self, s: &str) -> core::fmt::Result {
620 for c in s.encode_utf16() {
621 self.step16(c);
622 }
623 Ok(())
624 }
625
626 fn write_char(&mut self, c: char) -> core::fmt::Result {
627 self.step(c);
628 Ok(())
629 }
630}
631
632#[allow(deprecated)]
633impl<'a> Char16TrieIterator<'a> {
634 #[inline]
636 pub fn new(trie: &'a ZeroSlice<u16>) -> Self {
637 Self(Char16TrieCursor::new(trie))
638 }
639
640 #[inline]
642 pub fn next(&mut self, c: char) -> TrieResult {
643 self.next32(c as u32)
644 }
645
646 #[inline]
648 pub fn next32(&mut self, c: u32) -> TrieResult {
649 if c <= 0xffff {
650 self.next16(c as u16)
651 } else {
652 self.0.step16(u16_lead(c));
653 self.next16(u16_tail(c))
654 }
655 }
656
657 #[inline]
659 pub fn next16(&mut self, c: u16) -> TrieResult {
660 self.0.step16(c);
661 match (self.0.value(), self.0.is_empty()) {
662 (Some(v), true) => TrieResult::FinalValue(v),
663 (Some(v), false) => TrieResult::Intermediate(v),
664 (None, true) => TrieResult::NoMatch,
665 (None, false) => TrieResult::NoValue,
666 }
667 }
668}