Skip to main content

t_oc/
lib.rs

1//! Trie Occurrence Counter is frequency dictionary that uses any `impl Iterator<Item = char>` type as occurrent.
2//!
3//! Support for English letters A–Za–z OOB.
4
5use std::vec::Vec;
6
7/// Versatile result type used by tree entry operations.
8pub type VerRes = Result<usize, KeyError>;
9/// Addition result type used by [`Toc::add`] operation.
10pub type AddRes = Result<Option<usize>, KeyError>;
11
12mod uc;
13use uc::UC;
14
15/// `Letter` is `Alphabet` element, represents tree node.
16#[cfg_attr(test, derive(PartialEq))]
17struct Letter {
18    #[cfg(test)]
19    val: char,
20    ab: Option<Alphabet>,
21    ct: Option<usize>,
22}
23
24impl Letter {
25    const fn new() -> Self {
26        Letter {
27            #[cfg(test)]
28            val: '💚',
29            ab: None,
30            ct: None,
31        }
32    }
33
34    const fn ab(&self) -> bool {
35        self.ab.is_some()
36    }
37
38    const fn ct(&self) -> bool {
39        self.ct.is_some()
40    }
41
42    const fn to_mut_ptr(&self) -> *mut Self {
43        (self as *const Self).cast_mut()
44    }
45}
46
47/// Tree node arms. Consists of `Letter`s.
48type Alphabet = Box<[Letter]>;
49/// Index conversion function. Tighten with alphabet used.
50/// Returns corresponding `usize`d index of `char`.
51///
52/// For details see `english_letters::ix` implementation.
53pub type Ix = fn(char) -> usize;
54
55/// Reversal index conversion function. Symmetrically mirrors `Ix` function.
56///
57/// For details see `english_letters::re` implementation.
58pub type Re = fn(usize) -> char;
59
60/// Alphabet function, tree arms generation of length specified.
61fn ab(len: usize) -> Alphabet {
62    let mut ab = Vec::new();
63    ab.reserve_exact(len);
64
65    #[cfg(test)]
66    #[cfg(feature = "test-ext")]
67    let mut c = 'A' as u8;
68
69    let sc = ab.spare_capacity_mut();
70    for ix in 0..len {
71        let mut _letter = sc[ix].write(Letter::new());
72
73        #[cfg(test)]
74        #[cfg(feature = "test-ext")]
75        {
76            _letter.val = c as char;
77
78            const Z: u8 = 'Z' as u8;
79            c = if c == Z { 'a' as u8 } else { c + 1 }
80        }
81    }
82
83    unsafe { ab.set_len(len) };
84
85    ab.into_boxed_slice()
86}
87
88/// Module for working with English alphabet letters, A-Za-z.
89///
90/// For details see `Toc::new_with()`.
91pub mod english_letters {
92
93    /// 26
94    pub const BASE_ALPHABET_LEN: usize = 26;
95    /// 52
96    pub const ALPHABET_LEN: usize = BASE_ALPHABET_LEN * 2;
97
98    const A: usize = 'A' as usize;
99    #[allow(non_upper_case_globals)]
100    const a: usize = 'a' as usize;
101
102    /// Index conversion function.
103    pub fn ix(c: char) -> usize {
104        let code_point = c as usize;
105
106        match code_point {
107            | c if c > 64 && c < 91 => c - A,
108            | c if c > 96 && c < 123 => c - a + BASE_ALPHABET_LEN,
109            | _ => {
110                panic!("Index conversion failed because code point `{code_point}` is unsupported.")
111            },
112        }
113    }
114
115    /// Index reversal conversion function.
116    pub fn re(i: usize) -> char {
117        let code_point = match i {
118            | i if i < 26 => i + A,
119            | i if i > 25 && i < 52 => i + a - BASE_ALPHABET_LEN,
120            | _ => {
121                panic!("Char conversion failed because index `{i}` conversion is not supported.")
122            },
123        };
124
125        code_point as u8 as char
126    }
127}
128
129/// Key error type used by tree entry operations.
130#[derive(Debug, PartialEq, Eq, Clone)]
131pub enum KeyError {
132    /// Zero occurrent usage.
133    ZeroLen,
134    /// Unknown occurrent usage.
135    Unknown,
136}
137
138#[cfg_attr(test, derive(PartialEq, Debug))]
139enum TraRes<'a> {
140    Ok(&'a Letter),
141    OkMut(&'a mut Letter),
142    ZeroLen,
143    UnknownForNotEntry,
144    UnknownForAbsentPath,
145}
146
147impl<'a> TraRes<'a> {
148    fn ver_res(&self) -> KeyError {
149        let p = || panic!("Unsupported");
150
151        return match self {
152            | TraRes::ZeroLen => KeyError::ZeroLen,
153            | TraRes::UnknownForNotEntry | TraRes::UnknownForAbsentPath => KeyError::Unknown,
154            | TraRes::Ok(_) => p(),
155            | TraRes::OkMut(_) => p(),
156        };
157    }
158}
159
160// TC: Ω(n ⋅ alphabet size) ⇒ Ω(n), n = nodes count
161// SC: Θ(s + n) ⇒ Θ(s), n = nodes count, s = key lengths sum
162// to lower estimation add unpredictable count of string clonings
163// and buffers (capacity-) reallocations
164fn ext(ab: &Alphabet, buff: &mut String, re: Re, o: &mut Vec<(String, usize)>) {
165    for ix in 0..ab.len() {
166        buff.push(re(ix));
167
168        let letter = &ab[ix];
169
170        if let Some(ct) = letter.ct {
171            let key = buff.clone();
172            o.push((key, ct));
173        }
174
175        if let Some(ab) = letter.ab.as_ref() {
176            ext(ab, buff, re, o);
177        }
178
179        _ = buff.pop();
180    }
181}
182
183/// Trie Occurrence Counter is frequency dictionary that uses any `impl Iterator<Item = char>` type as occurrent.
184///
185/// OOB English letters A–Za–z support only.
186///
187/// ```
188/// use t_oc::Toc;
189/// use std::panic::catch_unwind;
190///
191/// let mut toc = Toc::new();
192/// let occurrent = "true";
193///
194/// _ = toc.add(occurrent.chars(), None);
195/// _ = toc.add(true.to_string().chars(), None);
196///
197/// assert_eq!(2, toc.acq(occurrent.chars()).unwrap());
198/// toc.put(occurrent.chars(), 15);
199/// assert_eq!(15, toc.acq(occurrent.chars()).unwrap());
200///
201/// let catch = catch_unwind(move|| _ = toc.add("#&%".chars(), None));
202/// assert!(catch.is_err());
203/// ```
204///
205/// When asymptotic computational complexity is not explicitly specified , it is:
206/// - TC: Θ(c) where c is count of `char`s iterated over.
207/// - SC: Θ(0).
208pub struct Toc {
209    // tree root
210    rt: Alphabet,
211    // index fn
212    ix: Ix,
213    // rev index fn
214    re: Option<Re>,
215    // alphabet len
216    al: usize,
217    // backtrace buff
218    tr: UC<Vec<*mut Letter>>,
219    // occurrent count
220    ct: usize,
221}
222
223impl Toc {
224    /// Constructs default version of `Toc`, i.e. via
225    /// `fn new_with()` with `english_letters::{ix, re, ALPHABET_LEN}`.
226    pub fn new() -> Self {
227        Self::new_with(
228            english_letters::ix,
229            Some(english_letters::re),
230            english_letters::ALPHABET_LEN,
231        )
232    }
233
234    /// Allows to use custom alphabet different from default alphabet.
235    ///
236    /// ```
237    /// use t_oc::Toc;
238    ///
239    /// fn ix(c: char) -> usize {
240    ///     match c {
241    ///         '&' => 0,
242    ///         '|' => 1,
243    ///         _ => panic!(),
244    ///     }
245    /// }
246    ///
247    /// // if `fn Toc::ext` will not be used, pass `None` for `re`
248    /// fn re(i: usize) -> char {
249    ///     match i {
250    ///         0 => '&',
251    ///         1 => '|',
252    ///         _ => panic!(),
253    ///     }
254    /// }
255    ///
256    /// let ab_len = 2;
257    ///
258    /// let mut toc = Toc::new_with(ix, Some(re), ab_len);
259    /// let a = "&";
260    /// let b = "|";
261    /// let aba = "&|&";
262    /// _ = toc.add(a.chars(), None);
263    /// _ = toc.add(a.chars(), None);
264    /// _ = toc.add(b.chars(), None);
265    /// _ = toc.add(aba.chars(), None);
266    /// assert_eq!(2, toc.acq(a.chars()).unwrap());
267    /// assert_eq!(1, toc.acq(aba.chars()).unwrap());
268    pub fn new_with(ix: Ix, re: Option<Re>, ab_len: usize) -> Self {
269        Self {
270            rt: ab(ab_len),
271            ix,
272            re,
273            al: ab_len,
274            tr: UC::new(Vec::new()),
275            ct: 0,
276        }
277    }
278
279    /// Used to set internal backtracing buffer capacity.
280    ///
281    /// `Toc` uses internal buffer, to avoid excessive allocations and copying, which grows
282    /// over time due backtracing in `rem` method which backtraces whole path from entry
283    /// node to root node.
284    ///
285    /// Use this method to shrink or extend it to fit actual program needs. Neither shrinking nor extending
286    /// is guaranteed to be exact. See `Vec::with_capacity()` and `Vec::reserve()`. For optimal `rem` performance, set `approx_cap` to, at least, `occurrent.count()`.
287    ///
288    /// Some high value is sufficient anyway. Since buffer continuous
289    /// usage, its capacity will likely expand at some point in time to size sufficient to all occurrents.
290    ///
291    /// Return value is actual buffer capacity.
292    ///
293    /// **Note:** While `String` is UTF8 encoded, its byte length does not have to equal its `char` count
294    /// which is either equal or lesser.
295    /// ```
296    /// let sights = "🤩";
297    /// assert_eq!(4, sights.len());
298    /// assert_eq!(1, sights.chars().count());
299    ///
300    /// let yes = "sí";
301    /// assert_eq!(3, yes.len());
302    /// assert_eq!(2, yes.chars().nth(1).unwrap().len_utf8());
303    ///
304    /// let abc = "abc";
305    /// assert_eq!(3, abc.len());
306    /// ```
307    pub fn put_trace_cap(&mut self, approx_cap: usize) -> usize {
308        let tr = &mut self.tr;
309        let cp = tr.capacity();
310
311        if cp < approx_cap {
312            tr.get_mut().reserve(approx_cap);
313        } else if cp > approx_cap {
314            *tr = UC::new(Vec::with_capacity(approx_cap));
315        }
316
317        tr.capacity()
318    }
319
320    /// Used to obtain internal backtracing buffer capacity.
321    ///
322    /// Check with `fn put_trace_cap` for details.
323    pub fn acq_trace_cap(&self) -> usize {
324        self.tr.capacity()
325    }
326
327    /// Used to add occurence to tree.
328    ///
329    /// Counter is of word size. Add overflow is wrapped using [`usize::wrapping_add`].
330    ///
331    /// Optional `val` parameter can be used to insert exact value.
332    ///
333    /// Return value is `Ok(Option<usize>)` for non-zero occurent and holds previous value, if there was some.
334    ///
335    /// Only invalid key classified is zero-length key.
336    ///
337    /// - SC: Θ(q) where q is number of unique nodes, i.e. `char`s in respective branches.
338    pub fn add(&mut self, mut occurrent: impl Iterator<Item = char>, val: Option<usize>) -> AddRes {
339        let c = occurrent.next();
340
341        if c.is_none() {
342            return Err(KeyError::ZeroLen);
343        }
344
345        let c = unsafe { c.unwrap_unchecked() };
346
347        let ix = self.ix;
348        let al = self.al;
349
350        let mut letter = &mut self.rt[ix(c)];
351
352        while let Some(c) = occurrent.next() {
353            let alphabet = letter.ab.get_or_insert_with(|| ab(al));
354            letter = &mut alphabet[ix(c)];
355        }
356
357        let ct = letter.ct;
358
359        let ct_none = ct.is_none();
360        if ct_none {
361            self.ct += 1;
362        }
363
364        letter.ct = Some(if let Some(v) = val {
365            v
366        } else {
367            if ct_none {
368                1
369            } else {
370                unsafe { ct.unwrap_unchecked() }.wrapping_add(1)
371            }
372        });
373
374        Ok(ct)
375    }
376
377    /// Used to acquire value for `occurrent`.
378    ///
379    /// If `Ok(usize)`, `usize` is `occurrent` occurrences count.
380    pub fn acq(&self, occurrent: impl Iterator<Item = char>) -> VerRes {
381        let track_res = self.track(occurrent, false, false);
382        if let TraRes::Ok(l) = track_res {
383            let ct = l.ct;
384            let ct = unsafe { ct.unwrap_unchecked() };
385            Ok(ct)
386        } else {
387            Err(track_res.ver_res())
388        }
389    }
390
391    /// Used to put new value for `occurrent` occurrences.
392    ///
393    /// If `Ok(usize)`, `usize` is previous value.
394    pub fn put(&mut self, occurrent: impl Iterator<Item = char>, val: usize) -> VerRes {
395        let track_res = self.track(occurrent, false, true);
396
397        if let TraRes::OkMut(l) = track_res {
398            let old = l.ct.replace(val);
399            let old = unsafe { old.unwrap_unchecked() };
400            Ok(old)
401        } else {
402            Err(track_res.ver_res())
403        }
404    }
405
406    /// Used to remove `occurrent` from tree.
407    ///
408    /// If `Ok(usize)`, `usize` is `occurrent` occurrences count.
409    ///
410    /// - _c_ is count of `char`s iterated over.
411    /// - TC: Ω(c) or ϴ(c) (backtracing buffer capacity dependent complexity).
412    /// - SC: ϴ(c).
413    ///
414    /// Check with `put_trace_cap` for details on backtracing.
415    pub fn rem(&mut self, occurrent: impl Iterator<Item = char>) -> VerRes {
416        let track_res = self.track(occurrent, true, false);
417        let res = if let TraRes::Ok(_) = track_res {
418            let ct = Self::rem_actual(self);
419            self.ct -= 1;
420            Ok(ct)
421        } else {
422            Err(track_res.ver_res())
423        };
424
425        self.tr.get_mut().clear();
426        res
427    }
428
429    fn rem_actual(&mut self) -> usize {
430        let mut trace = self.tr.iter().map(|x| unsafe { x.as_mut() }.unwrap());
431        let entry = unsafe { trace.next_back().unwrap_unchecked() };
432
433        let ct = entry.ct.take();
434
435        if !entry.ab() {
436            while let Some(l) = trace.next_back() {
437                let alphabet = l.ab.as_ref().unwrap();
438                let mut remove_alphab = true;
439
440                for ix in 0..self.al {
441                    let letter = &alphabet[ix];
442
443                    if letter.ab() || letter.ct() {
444                        remove_alphab = false;
445                        break;
446                    }
447                }
448
449                if remove_alphab {
450                    l.ab = None;
451                } else {
452                    break;
453                }
454
455                if l.ct() {
456                    break;
457                }
458            }
459        }
460
461        unsafe { ct.unwrap_unchecked() }
462    }
463
464    // - s is count of `char`s iterated over
465    // - TC: Ω(s) when `tracing = true`, ϴ(s) otherwise
466    // - SC: ϴ(s) when `tracing = true`, ϴ(0) otherwise
467    fn track(
468        &self,
469        mut occurrent: impl Iterator<Item = char>,
470        tracing: bool,
471        okmut: bool,
472    ) -> TraRes {
473        let c = occurrent.next();
474
475        if c.is_none() {
476            return TraRes::ZeroLen;
477        }
478
479        let c = unsafe { c.unwrap_unchecked() };
480
481        let ix = &self.ix;
482        let tr = self.tr.get_mut();
483
484        let mut letter = &self.rt[ix(c)];
485
486        loop {
487            if tracing {
488                tr.push(letter.to_mut_ptr())
489            }
490
491            if let Some(c) = occurrent.next() {
492                if let Some(ab) = letter.ab.as_ref() {
493                    letter = &ab[ix(c)];
494                } else {
495                    return TraRes::UnknownForAbsentPath;
496                }
497            } else {
498                break;
499            }
500        }
501
502        if letter.ct() {
503            if okmut {
504                let l_mut = unsafe { letter.to_mut_ptr().as_mut().unwrap_unchecked() };
505                TraRes::OkMut(l_mut)
506            } else {
507                TraRes::Ok(letter)
508            }
509        } else {
510            TraRes::UnknownForNotEntry
511        }
512    }
513
514    /// Used to extract occurences from tree.
515    ///
516    /// Extraction is alphabetically ordered. Does not clear tree. Use `fn clr` for clearing.
517    ///
518    /// Return value is `None` for empty `Toc`.
519    ///
520    /// - TC: Ω(n) where n is count of nodes in tree.
521    /// - SC: Θ(s) where s is occurrent lengths summation.
522    ///
523    /// Returned set can be overcapacitated, i.e. its capacity
524    /// will not be shrunken according to its length.
525    pub fn ext(&self) -> Option<Vec<(String, usize)>> {
526        if let Some(re) = self.re {
527            if self.ct == 0 {
528                return None;
529            }
530
531            // capacity is prebuffered to 1000
532            let mut buff = String::with_capacity(1000);
533
534            // capacity is prebuffered to 1000
535            let mut res = Vec::with_capacity(1000);
536
537            ext(&self.rt, &mut buff, re, &mut res);
538            Some(res)
539        } else {
540            panic!("This method is unsupported when `new_with` `re` parameter is provided with `None`.");
541        }
542    }
543
544    /// Used to clear tree.
545    ///
546    /// Return value is count of occurrents in tree before clearing.
547    ///
548    /// TC: Θ(n) where n is count of nodes in tree.
549    pub fn clr(&mut self) -> usize {
550        self.rt = ab(self.al);
551        let ct = self.ct;
552        self.ct = 0;
553        ct
554    }
555
556    /// Used to acquire count of occurrents in tree.
557    pub const fn ct(&self) -> usize {
558        self.ct
559    }
560}
561
562#[cfg(test)]
563mod tests_of_units {
564
565    use crate::Letter;
566    use std::fmt::{Debug, Formatter};
567
568    impl Debug for Letter {
569        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
570            let ab = some_none(self.ab.as_ref());
571
572            return f.write_fmt(format_args!(
573                "Letter {{\n  val: {}\n  ab: {}\n  ct: {:?}\n}}",
574                self.val, ab, self.ct
575            ));
576
577            fn some_none<T>(val: Option<&T>) -> &'static str {
578                if val.is_some() {
579                    "Some"
580                } else {
581                    "None"
582                }
583            }
584        }
585    }
586
587    mod letter {
588
589        use crate::{Letter, ab as ab_fn};
590
591        #[test]
592        fn new() {
593            let letter = Letter::new();
594
595            assert_eq!('💚', letter.val);
596            assert!(letter.ab.is_none());
597            assert!(letter.ct.is_none());
598        }
599
600        #[test]
601        fn ab() {
602            let mut letter = Letter::new();
603            assert_eq!(false, letter.ab());
604
605            letter.ab = Some(ab_fn(0));
606            assert_eq!(true, letter.ab());
607        }
608
609        #[test]
610        fn ct() {
611            let mut letter = Letter::new();
612            assert_eq!(false, letter.ct());
613
614            letter.ct = Some(0);
615            assert_eq!(true, letter.ct());
616        }
617    }
618
619    mod ab {
620
621        use crate::english_letters::ALPHABET_LEN;
622        use crate::ab as ab_fn;
623
624        #[test]
625        fn ab() {
626            let ab = ab_fn(ALPHABET_LEN);
627            assert_eq!(ALPHABET_LEN, ab.len());
628
629            #[cfg(feature = "test-ext")]
630            {
631                let chain = ('A'..='Z').chain('a'..='z');
632
633                for (ix, c) in chain.enumerate() {
634                    let letter = &ab[ix];
635
636                    assert_eq!(c, letter.val);
637                    assert!(letter.ab.is_none());
638                    assert!(letter.ct.is_none());
639                }
640            }
641        }
642
643        #[test]
644        fn zero_len() {
645            let ab = ab_fn(0);
646            assert_eq!(0, ab.len());
647        }
648    }
649
650    mod english_letters {
651
652        use crate::english_letters::{ALPHABET_LEN, BASE_ALPHABET_LEN};
653
654        #[test]
655        fn consts() {
656            assert_eq!(26, BASE_ALPHABET_LEN);
657            assert_eq!(52, ALPHABET_LEN);
658        }
659
660        mod ix {
661            use crate::english_letters::ix;
662            use std::panic::catch_unwind;
663
664            #[test]
665            fn ixes() {
666                assert_eq!(0, ix('A'));
667                assert_eq!(25, ix('Z'));
668                assert_eq!(26, ix('a'));
669                assert_eq!(51, ix('z'));
670            }
671
672            #[test]
673            fn unsupported_char() {
674                let ucs = unsupported_chars();
675
676                for (c, cp) in ucs.map(|x| (x as char, x)) {
677                    let result = catch_unwind(|| ix(c));
678                    assert!(result.is_err());
679
680                    let err = unsafe { result.unwrap_err_unchecked() };
681                    let downcast = err.downcast_ref::<String>().unwrap();
682                    let proof = format!(
683                        "Index conversion failed because code point `{cp}` is unsupported."
684                    );
685                    assert_eq!(&proof, downcast);
686                }
687            }
688
689            fn unsupported_chars() -> [u8; 4] {
690                #[rustfmt::skip] let ucs =
691                [
692                    'A' as u8 -1, 'Z' as u8 +1, // 65–90
693                    'a' as u8 -1, 'z' as u8 +1, // 97–122
694                ];
695                ucs
696            }
697        }
698
699        mod re {
700            use crate::english_letters::re;
701
702            #[test]
703            fn ixes() {
704                assert_eq!('A', re(0));
705                assert_eq!('Z', re(25));
706                assert_eq!('a', re(26));
707                assert_eq!('z', re(51));
708            }
709
710            #[test]
711            #[should_panic(
712                expected = "Char conversion failed because index `52` conversion is not supported."
713            )]
714            fn unsupported_ix() {
715                _ = re(52)
716            }
717        }
718    }
719
720    mod ext {
721
722        type Nest = (char, usize);
723
724        use crate::{ab as ab_ctor, ext, Alphabet};
725        use crate::english_letters::{ALPHABET_LEN, ix, re};
726
727        fn ab_fn() -> Alphabet {
728            ab_ctor(ALPHABET_LEN)
729        }
730
731        #[test]
732        fn basic_test() {
733            let mut ab = ab_fn();
734
735            ab[ix('A')].ct = Some(1);
736            ab[ix('z')].ct = Some(2);
737
738            let mut buff = String::new();
739            let mut test = Vec::new();
740
741            ext(&ab, &mut buff, re, &mut test);
742
743            let proof = vec![(String::from("A"), 1), (String::from("z"), 2)];
744            assert_eq!(proof, test);
745        }
746
747        #[test]
748        fn nesting() {
749            let mut root = ab_fn();
750
751            let nesting = [
752                (('A', 3), ('z', 5)),
753                (('B', 5), ('y', 8)),
754                (('y', 10), ('B', 12)),
755                (('z', 99), ('A', 103)),
756            ];
757
758            for n in nesting {
759                prep(&mut root, n);
760            }
761
762            let mut buff = String::new();
763            let mut test = Vec::new();
764
765            ext(&root, &mut buff, re, &mut test);
766
767            let proof = vec![
768                (String::from("A"), 3),
769                (String::from("Az"), 5),
770                (String::from("B"), 5),
771                (String::from("By"), 8),
772                (String::from("y"), 10),
773                (String::from("yB"), 12),
774                (String::from("z"), 99),
775                (String::from("zA"), 103),
776            ];
777
778            assert_eq!(proof, test);
779
780            fn prep(ab: &mut Alphabet, n: (Nest, Nest)) {
781                let ultra = n.0;
782                let infra = n.1;
783
784                let u_l = &mut ab[ix(ultra.0)];
785                let mut ul_ab = ab_fn();
786
787                let i_l = &mut ul_ab[ix(infra.0)];
788                i_l.ct = Some(infra.1);
789
790                u_l.ab = Some(ul_ab);
791                u_l.ct = Some(ultra.1);
792            }
793        }
794
795        #[test]
796        fn in_depth_recursion() {
797            let mut root = ab_fn();
798
799            let paths = [
800                ("AA", 13),
801                ("AzBq", 11),
802                ("By", 329),
803                ("ZaZazAzAzAbYyb", 55),
804                ("yBC", 7),
805                ("ybXr", 53),
806                ("ybXrQUTmop", 33),
807                ("ybXrQUTmopFVB", 99),
808                ("ybXrQUTmopRFG", 80),
809                ("zAzAZaZaZaByYB", 44),
810            ];
811
812            for p in paths {
813                let mut chars = p.0.chars();
814                let mut le = &mut root[ix(chars.next().unwrap())];
815
816                while let Some(c) = chars.next() {
817                    let ab = le.ab.get_or_insert_with(|| ab_fn());
818                    le = &mut ab[ix(c)];
819                }
820
821                le.ct = Some(p.1)
822            }
823
824            let mut buff = String::new();
825            let mut test = Vec::new();
826
827            ext(&root, &mut buff, re, &mut test);
828
829            let proof = vec![
830                (String::from("AA"), 13),
831                (String::from("AzBq"), 11),
832                (String::from("By"), 329),
833                (String::from("ZaZazAzAzAbYyb"), 55),
834                (String::from("yBC"), 7),
835                (String::from("ybXr"), 53),
836                (String::from("ybXrQUTmop"), 33),
837                (String::from("ybXrQUTmopFVB"), 99),
838                (String::from("ybXrQUTmopRFG"), 80),
839                (String::from("zAzAZaZaZaByYB"), 44),
840            ];
841
842            assert_eq!(proof, test);
843        }
844    }
845
846    mod track_res {
847        use crate::{TraRes, Letter};
848        use crate::KeyError::{ZeroLen, Unknown};
849
850        #[test]
851        fn ver_res_convertible() {
852            assert_eq!(ZeroLen, TraRes::ZeroLen.ver_res());
853            assert_eq!(Unknown, TraRes::UnknownForAbsentPath.ver_res());
854            assert_eq!(Unknown, TraRes::UnknownForNotEntry.ver_res());
855        }
856
857        use std::{ops::Deref, panic::catch_unwind};
858        #[test]
859        fn ver_res_nonconvertible() {
860            let err = catch_unwind(|| TraRes::Ok(&Letter::new()).ver_res());
861
862            assert_eq!(true, err.is_err());
863            assert_eq!(
864                &"Unsupported",
865                err.unwrap_err().downcast::<&str>().unwrap().deref()
866            );
867
868            let err = catch_unwind(|| TraRes::OkMut(&mut Letter::new()).ver_res());
869
870            assert_eq!(true, err.is_err());
871            assert_eq!(
872                &"Unsupported",
873                err.unwrap_err().downcast::<&str>().unwrap().deref()
874            );
875        }
876    }
877
878    mod toc {
879        use crate::{Toc, ab};
880        use crate::english_letters::{ix, re, ALPHABET_LEN};
881
882        #[test]
883        fn new() {
884            let toc = Toc::new();
885            assert_eq!(ALPHABET_LEN, toc.al);
886            assert_eq!(ix as usize, toc.ix as usize);
887            assert_eq!(re as usize, toc.re.unwrap() as usize);
888        }
889
890        #[test]
891        fn new_with() {
892            fn test_ix(_c: char) -> usize {
893                0
894            }
895
896            fn test_re(_i: usize) -> char {
897                '\0'
898            }
899
900            let ab_len = 10;
901            let toc = Toc::new_with(test_ix, Some(test_re), ab_len);
902
903            assert_eq!(ab(ab_len), toc.rt);
904            assert_eq!(ab_len, toc.al);
905            assert_eq!(test_ix as usize, toc.ix as usize);
906            assert_eq!(test_re as usize, toc.re.unwrap() as usize);
907            assert_eq!(0, toc.tr.capacity());
908            assert_eq!(0, toc.ct);
909        }
910
911        mod put_trace_cap {
912            use crate::{Toc, uc::UC};
913
914            #[test]
915            fn extend() {
916                const NEW_CAP: usize = 10;
917
918                let mut toc = Toc::new();
919                assert!(toc.tr.capacity() < NEW_CAP);
920
921                let size = toc.put_trace_cap(NEW_CAP);
922                assert!(size >= NEW_CAP);
923                assert!(toc.tr.capacity() >= NEW_CAP);
924            }
925
926            #[test]
927            fn shrink() {
928                const NEW_CAP: usize = 10;
929                const OLD_CAP: usize = 50;
930
931                let mut toc = Toc::new();
932                toc.tr = UC::new(Vec::with_capacity(OLD_CAP));
933
934                let size = toc.put_trace_cap(NEW_CAP);
935                assert!(size >= NEW_CAP && size < OLD_CAP);
936                let cap = toc.tr.capacity();
937                assert!(cap >= NEW_CAP && cap < OLD_CAP);
938            }
939
940            #[test]
941            fn same() {
942                let mut toc = Toc::new();
943                let cap = toc.tr.capacity();
944
945                let size = toc.put_trace_cap(cap);
946                assert_eq!(cap, size);
947                assert_eq!(cap, toc.tr.capacity());
948            }
949        }
950
951        #[test]
952        fn acq_trace_cap() {
953            const VAL: usize = 10;
954
955            let mut toc = Toc::new();
956            let tr = &mut toc.tr;
957
958            assert!(tr.capacity() < VAL);
959            tr.get_mut().reserve_exact(VAL);
960            assert_eq!(VAL, toc.acq_trace_cap());
961        }
962
963        mod add {
964            use crate::Toc;
965            use crate::KeyError::ZeroLen;
966            use crate::english_letters::ix;
967
968            #[test]
969            fn basic_test() {
970                let entry = || "impreciseness".chars();
971
972                let mut toc = Toc::new();
973                assert_eq!(Ok(None), toc.add(entry(), None));
974                assert_eq!(1, toc.ct);
975
976                let chars: Vec<char> = entry().collect();
977                let len = chars.len();
978                let last_ix = len - 1;
979
980                let mut sup_ab = &toc.rt;
981                for c_ix in 0..len {
982                    let c = chars[c_ix];
983                    let l = &sup_ab[ix(c)];
984
985                    let terminal_it = c_ix == last_ix;
986
987                    let sub_ab = l.ab.as_ref();
988                    assert_eq!(terminal_it, sub_ab.is_none(), "{c_ix}, {c}, {terminal_it}",);
989
990                    if terminal_it {
991                        let ct = l.ct.as_ref();
992                        assert!(ct.is_some());
993                        let ct = unsafe { ct.unwrap_unchecked() };
994                        assert_eq!(&1, ct);
995                    } else {
996                        sup_ab = unsafe { sub_ab.unwrap_unchecked() };
997                    }
998                }
999            }
1000
1001            #[test]
1002            fn zero_occurrent() {
1003                let mut toc = Toc::new();
1004                assert_eq!(Err(ZeroLen), toc.add("".chars(), None));
1005                assert_eq!(0, toc.ct);
1006            }
1007
1008            #[test]
1009            fn singular_occurrent() {
1010                let mut toc = Toc::new();
1011                assert_eq!(Ok(None), toc.add("a".chars(), None));
1012                assert_eq!(Some(1), toc.rt[ix('a')].ct);
1013                assert_eq!(1, toc.ct);
1014            }
1015
1016            #[test]
1017            fn double_add() {
1018                let entry = || "impreciseness".chars();
1019
1020                let mut toc = Toc::new();
1021                assert_eq!(Ok(None), toc.add(entry(), None));
1022                assert_eq!(1, toc.ct);
1023
1024                assert_eq!(Ok(Some(1)), toc.add(entry(), None));
1025                assert_eq!(1, toc.ct);
1026
1027                let chars: Vec<char> = entry().collect();
1028                let len = chars.len();
1029                let last_ix = len - 1;
1030
1031                let mut sup_ab = &toc.rt;
1032                for c_ix in 0..len {
1033                    let c = chars[c_ix];
1034                    let l = &sup_ab[ix(c)];
1035
1036                    let terminal_it = c_ix == last_ix;
1037
1038                    let sub_ab = l.ab.as_ref();
1039                    assert_eq!(terminal_it, sub_ab.is_none(), "{c_ix}, {c}, {terminal_it}",);
1040
1041                    if terminal_it {
1042                        let ct = l.ct.as_ref();
1043                        assert!(ct.is_some());
1044                        let ct = unsafe { ct.unwrap_unchecked() };
1045                        assert_eq!(&2, ct);
1046                    } else {
1047                        sup_ab = unsafe { sub_ab.unwrap_unchecked() };
1048                    }
1049                }
1050            }
1051
1052            #[test]
1053            fn exact() {
1054                let entry = || "impreciseness".chars();
1055                const VAL: usize = 15;
1056
1057                let mut toc = Toc::new();
1058                assert_eq!(Ok(None), toc.add(entry(), Some(VAL)));
1059                assert_eq!(1, toc.ct);
1060
1061                assert_eq!(Ok(VAL), toc.acq(entry()));
1062            }
1063
1064            #[test]
1065            fn exact_over() {
1066                let entry = || "impreciseness".chars();
1067                const VAL: usize = 15;
1068
1069                let mut toc = Toc::new();
1070                _ = toc.add(entry(), None);
1071                assert_eq!(1, toc.ct);
1072
1073                assert_eq!(Ok(Some(1)), toc.add(entry(), Some(VAL)));
1074                assert_eq!(1, toc.ct);
1075
1076                assert_eq!(Ok(VAL), toc.acq(entry()));
1077            }
1078
1079            #[test]
1080            #[allow(non_snake_case)]
1081            #[rustfmt::skip]
1082            #[cfg(feature = "test-ext")]
1083            fn load() {
1084
1085                let strs = [
1086                    ("zzbb", 44_441), ("zzaa", 88_999),
1087                    ("xya", 77_666), ("xyz", 22_333),
1088                    ("abc", 33_222), ("abd", 74_332),
1089                    ("abcd", 11_234), ("abce", 11_234),
1090                    ("qaa", 16_678), ("qrs", 24_555),
1091                    ("qrt", 900_001), ("qua", 130_901),
1092                    ("qwa", 2_006),
1093                    ("percent", 77_110), ("percentile", 99_888),
1094                    ("quail", 20_333), ("qualification", 33_111),
1095                    ("quality", 555_666), ("quantity", 116_777),
1096                    ("XYAB", 544_555), ("XYABA", 111_900),
1097                    ("JUI", 30_000), ("JUN", 100_000),
1098                    ("XYA", 80_000), ("XYQ", 11_111),
1099                    ("XYZ", 111_333), ("XYABC", 222_000),
1100                    ("MOMENT", 15_999), ("INSTANT", 34_341),
1101                    ("JUNCTURE", 789_223),
1102                    ("ABC", 14_234), ("ABD", 34_123)
1103                ];
1104
1105                let mut toc = Toc::new();
1106                for (s, c) in strs {
1107                    for i in 0..c {
1108                        let res = toc.add(s.chars(), None);
1109                        let prev = if i > 0 {
1110                            Some(i)
1111                        } else {
1112                            None
1113                        };        
1114                        assert_eq!(Ok(prev), res);
1115                    }
1116                }
1117
1118                for (s, c) in strs {
1119                    let res = toc.acq(s.chars());
1120                    assert_eq!(Ok(c), res);                 
1121                }
1122                
1123                assert_eq!(strs.len(), toc.ct);
1124            }
1125
1126            #[test]
1127            fn overflow_wrap() {
1128                let mut toc = Toc::new();
1129
1130                let entry = || "a".chars();
1131
1132                _ = toc.add(entry(), None);
1133                _ = toc.put(entry(), usize::MAX);
1134                _ = toc.add(entry(), None);
1135                assert_eq!(Ok(0), toc.acq(entry()));
1136                assert_eq!(1, toc.ct);
1137            }
1138        }
1139
1140        mod acq {
1141            use crate::Toc;
1142            use crate::KeyError::{ZeroLen, Unknown};
1143
1144            #[test]
1145            #[allow(non_upper_case_globals)]
1146            fn known_unknown() {
1147                let a = || "a".chars();
1148                let b = || "b".chars();
1149
1150                let mut toc = Toc::new();
1151                _ = toc.add(a(), None);
1152
1153                assert_eq!(Ok(1), toc.acq(a()));
1154                assert_eq!(Err(Unknown), toc.acq(b()));
1155            }
1156
1157            #[test]
1158            fn zero_occurrent() {
1159                let toc = Toc::new();
1160                assert_eq!(Err(ZeroLen), toc.acq("".chars()));
1161            }
1162        }
1163
1164        mod put {
1165            use crate::Toc;
1166            use crate::KeyError::{ZeroLen, Unknown};
1167
1168            #[test]
1169            #[allow(non_upper_case_globals)]
1170            fn known_unknown() {
1171                let a = || "a".chars();
1172                let b = || "b".chars();
1173
1174                let mut toc = Toc::new();
1175                _ = toc.add(a(), None);
1176
1177                assert_eq!(Ok(1), toc.put(a(), 3));
1178                assert_eq!(Ok(3), toc.acq(a()));
1179                assert_eq!(Err(Unknown), toc.put(b(), 3));
1180            }
1181
1182            #[test]
1183            fn zero_occurrent() {
1184                let mut toc = Toc::new();
1185                assert_eq!(Err(ZeroLen), toc.put("".chars(), 3));
1186            }
1187        }
1188
1189        mod rem {
1190            use crate::Toc;
1191            use crate::KeyError::{ZeroLen, Unknown};
1192
1193            #[test]
1194            fn known_unknown() {
1195                let known = || "VigilantAndVigourous".chars();
1196                let unknown = || "NeglectfulAndFeeble".chars();
1197
1198                let mut toc = Toc::new();
1199                _ = toc.add(known(), None);
1200
1201                assert_eq!(Err(Unknown), toc.rem(unknown()));
1202                assert_eq!(0, toc.tr.len());
1203
1204                assert_eq!(1, toc.ct());
1205
1206                assert_eq!(Ok(1), toc.rem(known()));
1207                assert_eq!(Err(Unknown), toc.acq(known()));
1208                assert_eq!(0, toc.tr.len());
1209
1210                assert_eq!(0, toc.ct());
1211            }
1212
1213            #[test]
1214            fn zero_occurrent() {
1215                let mut toc = Toc::new();
1216                assert_eq!(Err(ZeroLen), toc.rem("".chars()));
1217            }
1218        }
1219
1220        mod rem_actual {
1221            use crate::{Toc, TraRes};
1222            use crate::KeyError::Unknown;
1223            use crate::english_letters::ix;
1224
1225            #[test]
1226            fn basic_test() {
1227                let entry = || "ABCxyz".chars();
1228                let mut toc = Toc::new();
1229                _ = toc.add(entry(), None);
1230
1231                _ = toc.track(entry(), true, false);
1232
1233                assert_eq!(1, Toc::rem_actual(&mut toc));
1234
1235                #[allow(non_snake_case)]
1236                let K = &toc.rt[ix('A')];
1237                assert_eq!(false, K.ab());
1238            }
1239
1240            #[test]
1241            fn ab_len_test() {
1242                let ix = |c| match c {
1243                    | 'a' => 0,
1244                    | 'z' => 99,
1245                    | _ => panic!(),
1246                };
1247
1248                let key_1 = || "aaa".chars();
1249                let key_2 = || "aaz".chars();
1250
1251                let key_1_val = 50;
1252                let key_2_val = 60;
1253
1254                let mut toc = Toc::new_with(ix, None, 100);
1255                _ = toc.add(key_1(), Some(key_1_val));
1256                _ = toc.add(key_2(), Some(key_2_val));
1257
1258                _ = toc.track(key_1(), true, false);
1259
1260                assert_eq!(key_1_val, Toc::rem_actual(&mut toc));
1261                assert!(toc.acq(key_2()).is_ok());
1262            }
1263
1264            #[test]
1265            fn inner_entry() {
1266                let mut toc = Toc::new();
1267
1268                let outer = || "Keyword".chars();
1269                _ = toc.add(outer(), None);
1270
1271                let inner = || "Key".chars();
1272                _ = toc.add(inner(), None);
1273
1274                _ = toc.track(inner(), true, false);
1275
1276                assert_eq!(1, Toc::rem_actual(&mut toc));
1277                assert_eq!(Err(Unknown), toc.acq(inner()));
1278                assert_eq!(Ok(1), toc.acq(outer()));
1279            }
1280
1281            #[test]
1282            fn entry_with_peer_entry() {
1283                let mut toc = Toc::new();
1284
1285                let peer = || "Keyworder".chars();
1286                _ = toc.add(peer(), None);
1287
1288                let test = || "Keywordee".chars();
1289                _ = toc.add(test(), None);
1290
1291                _ = toc.track(test(), true, false);
1292
1293                assert_eq!(1, Toc::rem_actual(&mut toc));
1294                assert_eq!(Err(Unknown), toc.acq(test()));
1295                assert_eq!(Ok(1), toc.acq(peer()));
1296            }
1297
1298            #[test]
1299            fn entry_with_peer_with_alphabet() {
1300                let mut toc = Toc::new();
1301
1302                let peer = || "Keyworders".chars();
1303                _ = toc.add(peer(), None);
1304
1305                let test = || "Keywordee".chars();
1306                _ = toc.add(test(), None);
1307
1308                _ = toc.track(test(), true, false);
1309
1310                assert_eq!(1, Toc::rem_actual(&mut toc));
1311                assert_eq!(Err(Unknown), toc.acq(test()));
1312                assert_eq!(Ok(1), toc.acq(peer()));
1313            }
1314
1315            #[test]
1316            fn entry_under_entry() {
1317                let mut toc = Toc::new();
1318
1319                let above = || "Keyworder".chars();
1320                _ = toc.add(above(), None);
1321
1322                let under = || "Keyworders".chars();
1323                _ = toc.add(under(), None);
1324
1325                _ = toc.track(under(), true, false);
1326
1327                assert_eq!(1, Toc::rem_actual(&mut toc));
1328                assert_eq!(Err(Unknown), toc.acq(under()));
1329                assert_eq!(Ok(1), toc.acq(above()));
1330
1331                let res = toc.track(above(), false, false);
1332                if let TraRes::Ok(l) = res {
1333                    #[cfg(feature = "test-ext")]
1334                    assert_eq!('r', l.val);
1335                    assert_eq!(false, l.ab());
1336                } else {
1337                    panic!("TraRes::Ok(_) was expected, instead {:?}.", res);
1338                }
1339            }
1340        }
1341
1342        mod track {
1343            use crate::{Toc, TraRes};
1344
1345            #[test]
1346            fn zero_occurrent() {
1347                let toc = Toc::new();
1348                let res = toc.track("".chars(), false, false);
1349                assert_eq!(TraRes::ZeroLen, res);
1350            }
1351
1352            #[test]
1353            #[cfg(feature = "test-ext")]
1354            fn singular_occurrent() {
1355                let entry = || "A".chars();
1356
1357                let mut toc = Toc::new();
1358
1359                _ = toc.add(entry(), None);
1360                let res = toc.track(entry(), true, false);
1361
1362                if let TraRes::Ok(l) = res {
1363                    let l_val = l.val;
1364                    let tr = &toc.tr;
1365
1366                    assert_eq!('A', l_val);
1367                    assert_eq!(1, tr.len());
1368
1369                    let l = unsafe { tr[0].as_ref() }.unwrap();
1370                    assert_eq!('A', l.val)
1371                } else {
1372                    panic!("TraRes::Ok(_) was expected, instead {:?}.", res);
1373                }
1374            }
1375
1376            #[test]
1377            #[cfg(feature = "test-ext")]
1378            fn tracing() {
1379                let entry = || "DictionaryLexicon".chars();
1380
1381                let mut toc = Toc::new();
1382                _ = toc.add(entry(), None);
1383                _ = toc.track(entry(), true, false);
1384
1385                let proof = entry().collect::<Vec<char>>();
1386                let tr = &toc.tr;
1387
1388                assert_eq!(proof.len(), tr.len());
1389
1390                for (x, &c) in proof.iter().enumerate() {
1391                    let l = tr[x];
1392                    let l = unsafe { l.as_ref() }.unwrap();
1393                    assert_eq!(c, l.val);
1394                }
1395            }
1396
1397            #[test]
1398            #[cfg(feature = "test-ext")]
1399            fn ok_variants() {
1400                let entry = || "Wordbook".chars();
1401                let last = 'k';
1402
1403                let mut toc = Toc::new();
1404                _ = toc.add(entry(), None);
1405                let res = toc.track(entry(), false, false);
1406
1407                match res {
1408                    | TraRes::Ok(l) => assert_eq!(last, l.val),
1409                    | _ => panic!("TraRes::Ok(_) was expected, instead {:?}.", res),
1410                }
1411
1412                let res = toc.track(entry(), false, true);
1413                match res {
1414                    | TraRes::OkMut(l) => assert_eq!(last, l.val),
1415                    | _ => panic!("TraRes::OkMut(_) was expected, instead {:?}.", res),
1416                }
1417            }
1418
1419            #[test]
1420            fn unknown_not_path() {
1421                let key = || "Wordbook".chars();
1422                let bad_key = || "Wordbooks".chars();
1423
1424                let mut toc = Toc::new();
1425                _ = toc.add(key(), None);
1426                let res = toc.track(bad_key(), false, false);
1427                assert_eq!(TraRes::UnknownForAbsentPath, res);
1428            }
1429
1430            #[test]
1431            fn unknown_not_entry() {
1432                let key = || "Wordbooks".chars();
1433                let bad_key = || "Wordbook".chars();
1434
1435                let mut toc = Toc::new();
1436                _ = toc.add(key(), None);
1437                let res = toc.track(bad_key(), false, false);
1438                assert_eq!(TraRes::UnknownForNotEntry, res);
1439            }
1440        }
1441
1442        mod ext {
1443            use crate::Toc;
1444            use crate::english_letters::ix;
1445
1446            #[test]
1447            fn basic_test() {
1448                let proof = vec![
1449                    (String::from("AA"), 13),
1450                    (String::from("AzBq"), 11),
1451                    (String::from("By"), 329),
1452                    (String::from("ZaZazAzAzAbYyb"), 55),
1453                    (String::from("yBC"), 7),
1454                    (String::from("ybXr"), 53),
1455                    (String::from("ybXrQUTmop"), 33),
1456                    (String::from("ybXrQUTmopFVB"), 99),
1457                    (String::from("ybXrQUTmopRFG"), 80),
1458                    (String::from("zAzAZaZaZaByYB"), 44),
1459                ];
1460
1461                let mut toc = Toc::new();
1462                for p in proof.iter() {
1463                    _ = toc.add(p.0.chars(), Some(p.1));
1464                }
1465
1466                let ext = toc.ext();
1467                assert_eq!(true, ext.is_some());
1468
1469                let ext = ext.unwrap();
1470                assert_eq!(proof.len(), ext.len());
1471                assert_eq!(proof, ext);
1472                assert_eq!(true, ext.capacity() >= 1000);
1473
1474                for p in proof.iter() {
1475                    assert_eq!(Ok(p.1), toc.acq(p.0.chars()));
1476                }
1477            }
1478
1479            #[test]
1480            #[should_panic(
1481                expected = "This method is unsupported when `new_with` `re` parameter is provided with `None`."
1482            )]
1483            fn re_not_provided() {
1484                _ = Toc::new_with(ix, None, 0).ext()
1485            }
1486
1487            #[test]
1488            fn empty_tree() {
1489                let toc = Toc::new();
1490                assert_eq!(None, toc.ext());
1491            }
1492        }
1493
1494        use crate::KeyError::Unknown;
1495
1496        #[test]
1497        fn clr() {
1498            let key = || "abc".chars();
1499
1500            let mut toc = Toc::new();
1501            _ = toc.add(key(), None);
1502            assert_eq!(1, toc.clr());
1503
1504            assert_eq!(Err(Unknown), toc.acq(key()));
1505            assert_eq!(ab(ALPHABET_LEN), toc.rt);
1506            assert_eq!(0, toc.ct);
1507        }
1508
1509        #[test]
1510        fn ct() {
1511            let test = 3;
1512            let mut toc = Toc::new();
1513            assert_eq!(0, toc.ct());
1514            toc.ct = test;
1515            assert_eq!(test, toc.ct());
1516        }
1517    }
1518}
1519
1520// cargo fmt && cargo test --features test-ext --release
1521// cargo fmt && cargo test --release