1
+ package org.utbot.fuzzer
2
+
3
+ fun <T > trieOf (vararg values : Iterable <T >): Trie <T , T > = IdentityTrie <T >().apply {
4
+ values.forEach(this ::add)
5
+ }
6
+
7
+ fun stringTrieOf (vararg values : String ): StringTrie = StringTrie ().apply {
8
+ values.forEach(this ::add)
9
+ }
10
+
11
+ class StringTrie : IdentityTrie <Char >() {
12
+ fun add (string : String ) = super .add(string.toCharArray().asIterable())
13
+ fun removeCompletely (string : String ) = super .removeCompletely(string.toCharArray().asIterable())
14
+ fun remove (string : String ) = super .remove(string.toCharArray().asIterable())
15
+ operator fun get (string : String ) = super .get(string.toCharArray().asIterable())
16
+ fun collect () = asSequence().map { String (it.toCharArray()) }.toSet()
17
+ }
18
+
19
+ open class IdentityTrie <T > : Trie <T , T >({ it })
20
+
21
+ /* *
22
+ * Implementation of a trie for any iterable values.
23
+ */
24
+ open class Trie <T , K >(
25
+ private val keyExtractor : (T ) -> K
26
+ ) : Iterable<List<T>> {
27
+
28
+ private val roots = HashMap <K , NodeImpl <T , K >>()
29
+ private val implementations = HashMap <Node <T >, NodeImpl <T , K >>()
30
+
31
+ /* *
32
+ * Adds value into a trie.
33
+ *
34
+ * If value already exists then do nothing except increasing internal counter of added values.
35
+ * The counter can be returned by [Node.count].
36
+ *
37
+ * @return corresponding [Node] of the last element in the `values`
38
+ */
39
+ fun add (values : Iterable <T >): Node <T > {
40
+ val root = try { values.first() } catch (e: NoSuchElementException ) { error(" Empty list are not allowed" ) }
41
+ var key = keyExtractor(root)
42
+ var node = roots.computeIfAbsent(key) { NodeImpl (root, null ) }
43
+ values.asSequence().drop(1 ).forEach { value ->
44
+ key = keyExtractor(value)
45
+ node = node.children.computeIfAbsent(key) { NodeImpl (value, node) }
46
+ }
47
+ node.count++
48
+ implementations[node] = node
49
+ return node
50
+ }
51
+
52
+ /* *
53
+ * Decreases node counter value or removes the value completely if `counter == 1`.
54
+ *
55
+ * Use [removeCompletely] to remove the value from the trie regardless of counter value.
56
+ *
57
+ * @return removed node if value exists.
58
+ */
59
+ fun remove (values : Iterable <T >): Node <T >? {
60
+ val node = findImpl(values) ? : return null
61
+ return when {
62
+ node.count == 1 -> removeCompletely(values)
63
+ node.count > 1 -> node.apply { count-- }
64
+ else -> throw IllegalStateException (" count should be 1 or greater" )
65
+ }
66
+ }
67
+
68
+ /* *
69
+ * Removes value from a trie.
70
+ *
71
+ * The value is removed completely from the trie. Thus, the next code is true:
72
+ *
73
+ * ```
74
+ * trie.remove(someValue)
75
+ * trie.get(someValue) == null
76
+ * ```
77
+ *
78
+ * Use [remove] to decrease counter value instead of removal.
79
+ *
80
+ * @return removed node if value exists
81
+ */
82
+ fun removeCompletely (values : Iterable <T >): Node <T >? {
83
+ val node = findImpl(values) ? : return null
84
+ if (node.count > 0 && node.children.isEmpty()) {
85
+ var n: NodeImpl <T , K >? = node
86
+ while (n != null ) {
87
+ val key = keyExtractor(n.data)
88
+ n = n.parent
89
+ if (n == null ) {
90
+ val removed = roots.remove(key)
91
+ check(removed != null )
92
+ } else {
93
+ val removed = n.children.remove(key)
94
+ check(removed != null )
95
+ if (n.count != 0 ) {
96
+ break
97
+ }
98
+ }
99
+ }
100
+ }
101
+ return if (node.count > 0 ) {
102
+ node.count = 0
103
+ implementations.remove(node)
104
+ node
105
+ } else {
106
+ null
107
+ }
108
+ }
109
+
110
+ operator fun get (values : Iterable <T >): Node <T >? {
111
+ return findImpl(values)
112
+ }
113
+
114
+ operator fun get (node : Node <T >): List <T >? {
115
+ return implementations[node]?.let (this ::buildValue)
116
+ }
117
+
118
+ private fun findImpl (values : Iterable <T >): NodeImpl <T , K >? {
119
+ val root = try { values.first() } catch (e: NoSuchElementException ) { return null }
120
+ var key = keyExtractor(root)
121
+ var node = roots[key] ? : return null
122
+ values.asSequence().drop(1 ).forEach { value ->
123
+ key = keyExtractor(value)
124
+ node = node.children[key] ? : return null
125
+ }
126
+ return node.takeIf { it.count > 0 }
127
+ }
128
+
129
+ override fun iterator (): Iterator <List <T >> {
130
+ return iterator {
131
+ roots.values.forEach { node ->
132
+ traverseImpl(node)
133
+ }
134
+ }
135
+ }
136
+
137
+ private suspend fun SequenceScope<List<T>>.traverseImpl (node : NodeImpl <T , K >) {
138
+ val stack = ArrayDeque <NodeImpl <T , K >>()
139
+ stack.addLast(node)
140
+ while (stack.isNotEmpty()) {
141
+ val n = stack.removeLast()
142
+ if (n.count > 0 ) {
143
+ yield (buildValue(n))
144
+ }
145
+ n.children.values.forEach(stack::addLast)
146
+ }
147
+ }
148
+
149
+ private fun buildValue (node : NodeImpl <T , K >): List <T > {
150
+ return generateSequence(node) { it.parent }.map { it.data }.toList().asReversed()
151
+ }
152
+
153
+ interface Node <T > {
154
+ val data: T
155
+ val count: Int
156
+ }
157
+
158
+ /* *
159
+ * Trie node
160
+ *
161
+ * @param data data to be stored
162
+ * @param parent reference to the previous element of the value
163
+ * @param count number of value insertions
164
+ * @param children list of children mapped by their key
165
+ */
166
+ private class NodeImpl <T , K >(
167
+ override val data : T ,
168
+ val parent : NodeImpl <T , K >? ,
169
+ override var count : Int = 0 ,
170
+ val children : MutableMap <K , NodeImpl <T , K >> = HashMap (),
171
+ ) : Node<T>
172
+ }
0 commit comments