1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
use crate::element::Element;
use crate::util;

/// RadixTrie stores values associated with strings
///
/// # Example
/// ```rust
/// use another_radix_trie::RadixTrie;
/// let mut trie = RadixTrie::<usize>::new();
/// trie.insert("ON", 3);
/// trie.insert("ON20", 4)
/// // The internal structure of this trie will be
/// // - "ON" 3
/// //    - "20" 4
/// ```
pub struct RadixTrie<T> {
    entry: Element<T>,
}

impl<T> RadixTrie<T> {
    /// Construct a new trie
    pub fn new() -> Self {
        RadixTrie {
            entry: Element::Base {
                label: "".to_owned(),
                children: vec![],
            },
        }
    }

    /// Insert label and associated value into the trie.
    /// Values will be override if the label provided is already in the trie
    /// # Example
    /// ```rust
    /// use another_radix_trie::RadixTrie;
    ///
    /// let mut trie = RadixTrie::<()>::new();
    /// trie.insert("label", ());
    /// ```
    pub fn insert(&mut self, mut label: &str, value: T) {
        let mut entry = (&mut self.entry).children_mut();
        while label.len() > 0 {
            let label_init_char = label.chars().next().unwrap();
            let target_index = util::binary_search(label_init_char, &entry);
            if target_index >= entry.len() {
                return entry.push(util::element_new_value(label, value, vec![]));
            }
            let target = &entry[target_index];
            let shared_prefix = util::longest_shared_prefix(target.label(), label);
            if shared_prefix.is_empty() {
                // no shared prefix, insert directly
                return entry.insert(target_index, util::element_new_value(label, value, vec![]));
            } else if shared_prefix == label {
                let children = match target.label() == label {
                    true => entry.remove(target_index).children_own(), // new value to replace the old value. Inherits the old one's children
                    false => {
                        let shared_prefix_len = shared_prefix.len();
                        let old_element = entry.remove(target_index);
                        let new_label = old_element.label()[shared_prefix_len..].to_owned();
                        vec![old_element.set_label(new_label)]
                    } // add the old value as a child
                };
                let item = util::element_new_value(label, value, children);
                return entry.insert(target_index, item);
            } else if shared_prefix == target.label() {
                // existing one is the prefix
                label = &label[shared_prefix.len()..]; // search the parts after the shared prefix
                entry = (&mut entry[target_index]).children_mut();
            } else {
                // The existing and newly adding one intersect
                let shared_common = shared_prefix.to_owned();
                let joined_item = Self::join_intersected_nodes(
                    entry.remove(target_index),
                    util::element_new_value(&label[shared_common.len()..], value, vec![]),
                    shared_common,
                );
                return entry.insert(target_index, joined_item);
            }
        }
    }

    /// When two nodes have intersected labels, call this helper to process
    fn join_intersected_nodes(
        original: Element<T>,
        new: Element<T>,
        shared_common: String,
    ) -> Element<T> {
        let new_original_label = original.label()[shared_common.len()..].to_owned();
        let original_item = original.set_label(new_original_label);
        let mut children = vec![original_item, new];
        children.sort_by(|e1, e2| e1.label().cmp(e2.label()));
        Element::Node {
            label: shared_common,
            children,
        }
    }

    /// Returns the borrowed value associated with related label.
    /// If the label does not exist in the
    /// # Example
    /// ```rust
    /// use another_radix_trie::RadixTrie;
    ///
    /// let mut trie = RadixTrie::<usize>::new();
    /// trie.insert("label", 5);
    /// assert_eq!(trie.find("label"), Some(&5));
    /// assert_eq!(trie.find("not exist"), None);
    /// ```
    pub fn find(&self, mut label: &str) -> Option<&T> {
        let mut entry = self.entry.children();
        while label.len() > 0 {
            let target_index = util::binary_search(label.chars().next().unwrap(), &entry);
            if target_index >= entry.len() {
                break;
            }
            let target = &entry[target_index];
            if target.label() == label {
                // found label
                return target.value();
            } else if label.starts_with(target.label()) {
                // existing_label matches the prefix of label. Move to next node
                label = &label[target.label().len()..];
                entry = target.children();
            } else {
                // not matched
                break;
            }
        }
        None
    }

    /// Returns the mutable borrowed value associated with related label.
    /// If the label does not exist in the
    /// # Example
    /// ```rust
    /// use another_radix_trie::RadixTrie;
    ///
    /// let mut trie = RadixTrie::<usize>::new();
    /// trie.insert("label", 5);
    /// assert_eq!(trie.find_mut("label"), Some(&mut 5));
    /// assert_eq!(trie.find("not exist"), None);
    /// ```
    pub fn find_mut(&mut self, mut label: &str) -> Option<&mut T> {
        let mut entry = self.entry.children_mut();
        while label.len() > 0 {
            let target_index = util::binary_search(label.chars().next().unwrap(), &entry);
            if target_index >= entry.len() {
                break;
            }
            let target = &mut entry[target_index];
            if target.label() == label {
                // found label
                return target.value_mut();
            } else if label.starts_with(target.label()) {
                // existing_label matches the prefix of label. Move to next node
                label = &label[target.label().len()..];
                entry = target.children_mut();
            } else {
                // not matched
                break;
            }
        }
        None
    }

    /// Removes the value associated with related label.
    /// If the provided label does not exist in the trie, return None
    /// # Example
    /// ```rust
    /// use another_radix_trie::RadixTrie;
    ///
    /// let mut trie = RadixTrie::<usize>::new();
    /// trie.insert("label", 5);
    /// assert_eq!(trie.remove("label"), Some(5));
    /// assert_eq!(trie.remove("not exist"), None);
    /// ```
    pub fn remove(&mut self, mut label: &str) -> Option<T> {
        let mut parent = &mut self.entry;
        while label.len() > 0 {
            let parent_is_node = parent.is_node();
            let target_index =
                util::binary_search(label.chars().next().unwrap(), parent.children());
            if target_index >= parent.children().len() {
                break;
            }
            let target = &parent.children()[target_index];
            if target.label() == label {
                // existing_label matches label
                let (label, value, mut children) =
                    parent.children_mut().remove(target_index).unpack();
                if children.len() > 1 {
                    // target node has more than one children. Make target node a none value node
                    parent
                        .children_mut()
                        .insert(target_index, Element::Node { label, children });
                } else if children.len() == 1 {
                    // Only one child. Make the child parent
                    let child = children.pop().unwrap();
                    // Connect parent prefix with the child label
                    let child_label_prepend_parent_prefix = format!("{}{}", label, child.label());
                    parent.children_mut().insert(
                        target_index,
                        child.set_label(child_label_prepend_parent_prefix),
                    );
                }
                // if parent has only one node child and parent is node. Merge them
                if parent.children().len() == 1 && parent_is_node {
                    let another_child = parent.children_mut().pop().unwrap();
                    let label = format!("{}{}", parent.label(), another_child.label());
                    *parent = another_child.set_label(label);
                }
                return value;
            } else if label.starts_with(target.label()) {
                label = &label[target.label().len()..];
                parent = &mut parent.children_mut()[target_index];
            } else {
                break;
            }
        }
        None
    }

    /// Returns all values with their labels where the labels start with given prefix
    /// # Example
    /// ```rust
    /// use another_radix_trie::RadixTrie;
    ///
    /// let mut trie = RadixTrie::<usize>::new();
    /// trie.insert("lab", 3);
    /// trie.insert("label", 5);
    /// assert_eq!(trie.start_with("la"), vec![(String::from("lab"), &3), (String::from("label"), &5)])
    /// ```
    pub fn start_with(&self, mut prefix: &str) -> Vec<(String, &T)> {
        let mut entry = self.entry.children();
        let mut prefixes: Vec<&str> = vec![];
        while prefix.len() > 0 {
            let target_index = util::binary_search(prefix.chars().next().unwrap(), &entry);
            if target_index >= entry.len() {
                break;
            }
            let target = &entry[target_index];
            if target.label().starts_with(prefix) {
                // found label
                let existing_prefix: String = prefixes.join("");
                return target
                    .collect_all_child_values()
                    .into_iter()
                    .map(|(prefix, value)| (format!("{}{}", existing_prefix, prefix), value))
                    .collect();
            } else if prefix.starts_with(target.label()) {
                // existing_label matches the prefix of label. Move to next node
                prefixes.push(target.label());
                prefix = &prefix[target.label().len()..];
                entry = target.children();
            } else {
                // not matched
                break;
            }
        }
        vec![]
    }
}

#[cfg(test)]
mod trie_tests {
    use crate::trie::RadixTrie;

    #[test]
    fn test_insert_find_remove() {
        let mut trie = RadixTrie::<usize>::new();
        trie.insert("ON", 647);
        trie.insert("ON2", 416);
        assert_eq!(trie.find("ON"), Some(&647));
        assert_eq!(trie.find("ON2"), Some(&416));
        assert_eq!(trie.find("NS"), None);
        assert_eq!(trie.remove("ON"), Some(647));
        assert_eq!(trie.remove("ON2"), Some(416));
        assert_eq!(trie.remove("NS"), None);
    }

    #[test]
    fn test_insert_find_remove_longer() {
        let mut trie = RadixTrie::<usize>::new();
        let words = ["Won", "Wonder", "Wonderful", "World", "Axes"];
        for word in &words {
            trie.insert(word, word.len())
        }
        for word in &words {
            assert_eq!(trie.find(word), Some(&word.len()));
            assert_eq!(trie.remove(word), Some(word.len()));
        }
    }

    #[test]
    fn test_start_with() {
        let mut trie = RadixTrie::<usize>::new();
        let words = ["Won", "Wonder", "Wonderful", "World", "Axes"];
        for word in &words {
            trie.insert(word, word.len())
        }
        let res = trie.start_with("W");
        let expected: Vec<(String, &usize)> = vec![
            ("Won".into(), &3),
            ("World".into(), &5),
            ("Wonder".into(), &6),
            ("Wonderful".into(), &9),
        ];
        assert_eq!(res, expected)
    }

    #[test]
    fn test_start_with_won() {
        let mut trie = RadixTrie::<usize>::new();
        let words = ["Won", "Wonder", "Wonderful", "World", "Axes"];
        for word in &words {
            trie.insert(word, word.len())
        }
        let res = trie.start_with("Won");
        let expected: Vec<(String, &usize)> = vec![
            ("Won".into(), &3),
            ("Wonder".into(), &6),
            ("Wonderful".into(), &9),
        ];
        assert_eq!(res, expected)
    }

    #[test]
    fn test_remove_with_merge_down() {
        let mut trie = RadixTrie::<usize>::new();
        trie.insert("exe", 3);
        trie.insert("execute", 7);
        trie.insert("exec", 4);
        trie.insert("example", 7);
        trie.remove("exec").expect("Removed exec");
        let cute = &trie.entry.children()[0].children()[1].children()[0];
        assert_eq!(cute.label(), "cute");
    }

    #[test]
    fn test_remove_with_merge_up() {
        let mut trie = RadixTrie::<usize>::new();
        trie.insert("exe", 3);
        trie.insert("execute", 7);
        trie.insert("exec", 4);
        trie.insert("example", 7);
        trie.remove("example").expect("Removed example");
        assert_eq!(trie.entry.children()[0].label(), "exe");
    }

    #[test]
    fn test_insert_find_mut() {
        let mut trie = RadixTrie::<usize>::new();
        trie.insert("ON", 647);
        let found = trie.find_mut("ON");
        assert_eq!(found, Some(&mut 647));
        *found.unwrap() = 416;
        let found = trie.find("ON");
        assert_eq!(found, Some(&416));
    }
}