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