-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f5fb9d8
commit be2fa54
Showing
6 changed files
with
163 additions
and
123 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,65 +1,62 @@ | ||
/// A trie that stores objects at each node. Supports wildcard path | ||
/// elements denoted by a ":" at the beginning. | ||
final class Trie<Key: Hashable, Value> { | ||
/// Storage of the objects at this node. | ||
private var storage: [Key: Value] = [:] | ||
final class Trie<Value> { | ||
/// Storage of the object at this node. | ||
private var value: Value? | ||
/// This node's children, mapped by their path for instant lookup. | ||
private var children: [String: Trie] = [:] | ||
/// Any children with wildcards in their path. | ||
private var wildcardChildren: [String: Trie] = [:] | ||
/// Any children with parameters in their path. | ||
private var parameterChildren: [String: Trie] = [:] | ||
|
||
/// Search this node & it's children for an object at a path, | ||
/// stored with the given key. | ||
/// Search this node & it's children for an object at a path. | ||
/// | ||
/// - Parameters: | ||
/// - path: The path of the object to search for. If this is | ||
/// empty, it is assumed the object can only be at this node. | ||
/// - storageKey: The key by which the object is stored. | ||
/// - Parameter path: The path of the object to search for. If this is | ||
/// empty, it is assumed the object can only be at this node. | ||
/// - Returns: A tuple containing the object and any parsed path | ||
/// parameters. `nil` if the object isn't in this node or its | ||
/// children. | ||
func search(path: [String], storageKey: Key) -> (value: Value, parameters: [PathParameter])? { | ||
func search(path: [String]) -> (value: Value, parameters: [PathParameter])? { | ||
if let first = path.first { | ||
let newPath = Array(path.dropFirst()) | ||
if let matchingChild = children[first] { | ||
return matchingChild.search(path: newPath, storageKey: storageKey) | ||
} else { | ||
for (wildcard, node) in wildcardChildren { | ||
guard var val = node.search(path: newPath, storageKey: storageKey) else { | ||
continue | ||
} | ||
|
||
val.parameters.insert(PathParameter(parameter: wildcard, stringValue: first), at: 0) | ||
return val | ||
return matchingChild.search(path: newPath) | ||
} | ||
|
||
for (wildcard, node) in parameterChildren { | ||
guard var val = node.search(path: newPath) else { | ||
continue | ||
} | ||
return nil | ||
|
||
val.parameters.insert(PathParameter(parameter: wildcard, stringValue: first), at: 0) | ||
return val | ||
} | ||
} else { | ||
return storage[storageKey].map { ($0, []) } | ||
return nil | ||
} | ||
|
||
return value.map { ($0, []) } | ||
} | ||
|
||
/// Inserts a value at the given path with a storage key. | ||
/// Inserts a value at the given path. | ||
/// | ||
/// - Parameters: | ||
/// - path: The path to the node where this value should be | ||
/// stored. | ||
/// - storageKey: The key by which to store the value. | ||
/// - value: The value to store. | ||
func insert(path: [String], storageKey: Key, value: Value) { | ||
func insert(path: [String], value: Value) { | ||
if let first = path.first { | ||
if first.hasPrefix(":") { | ||
let firstWithoutEscape = String(first.dropFirst()) | ||
let child = wildcardChildren[firstWithoutEscape] ?? Self() | ||
child.insert(path: Array(path.dropFirst()), storageKey: storageKey, value: value) | ||
wildcardChildren[firstWithoutEscape] = child | ||
let child = parameterChildren[firstWithoutEscape] ?? Self() | ||
child.insert(path: Array(path.dropFirst()), value: value) | ||
parameterChildren[firstWithoutEscape] = child | ||
} else { | ||
let child = children[first] ?? Self() | ||
child.insert(path: Array(path.dropFirst()), storageKey: storageKey, value: value) | ||
child.insert(path: Array(path.dropFirst()), value: value) | ||
children[first] = child | ||
} | ||
} else { | ||
storage[storageKey] = value | ||
self.value = value | ||
} | ||
} | ||
} |
Oops, something went wrong.