blob: 5e0806105b9d8c3f340be07cc97040c1988d72bb [file] [log] [blame]
Sean Condonf4f54a12018-10-10 23:25:46 +01001/*
2 * Copyright 2018-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17export interface TrieC {
18 p: any;
19 s: string[];
20}
21
22export interface TrieT {
23 k: any;
24 p: any;
25 q: any;
26}
27
28export enum TrieRemoved {
29 REMOVED = 'removed',
30 ABSENT = 'absent'
31}
32
33export enum TrieInsert {
34 ADDED = 'added',
35 UPDATED = 'updated'
36}
37
38/**
39 * Combine TrieRemoved and TrieInsert in to a union type
40 */
41export type TrieActions = TrieRemoved | TrieInsert;
42
43export enum TrieOp {
44 PLUS = '+',
45 MINUS = '-'
46}
47
48
49export class Trie {
50 p: any;
51 w: string;
52 s: string[];
53 c: TrieC;
54 t: TrieT[];
55 x: number;
56 f1: (TrieC) => TrieC;
57 f2: () => TrieActions;
58 data: any;
59
60
61 constructor(
62 op: TrieOp,
63 trie: any,
64 word: string,
65 data?: any
66 ) {
67 this.p = trie;
68 this.w = word.toUpperCase();
69 this.s = this.w.split('');
70 this.c = { p: this.p, s: this.s },
71 this.t = [];
72 this.x = 0;
73 this.f1 = op === TrieOp.PLUS ? this.add : this.probe;
74 this.f2 = op === TrieOp.PLUS ? this.insert : this.remove;
75 this.data = data;
76 while (this.c.s.length) {
77 this.c = this.f1(this.c);
78 }
79 }
80
81 add(cAdded: TrieC): TrieC {
82 const q = cAdded.s.shift();
83 let np = cAdded.p[q];
84
85 if (!np) {
86 cAdded.p[q] = {};
87 np = cAdded.p[q];
88 this.x = 1;
89 }
90 return { p: np, s: cAdded.s };
91 }
92
93 probe(cProbed: TrieC): TrieC {
94 const q = cProbed.s.shift();
95 const k: number = Object.keys(cProbed.p).length;
96 const np = cProbed.p[q];
97
98 this.t.push({ q: q, k: k, p: cProbed.p });
99 if (!np) {
100 this.t = [];
101 return { p: [], s: [] };
102 }
103 return { p: np, s: cProbed.s };
104 }
105
106 insert(): TrieInsert {
107 this.c.p._data = this.data;
108 return this.x ? TrieInsert.ADDED : TrieInsert.UPDATED;
109 }
110
111 remove(): TrieRemoved {
112 if (this.t.length) {
113 this.t = this.t.reverse();
114 while (this.t.length) {
115 const d = this.t.shift();
116 delete d.p[d.q];
117 if (d.k > 1) {
118 this.t = [];
119 }
120 }
121 return TrieRemoved.REMOVED;
122 }
123 return TrieRemoved.ABSENT;
124 }
125}