-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDictionary.swift
93 lines (78 loc) · 2.62 KB
/
Dictionary.swift
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
//
// Dictionary.swift
// BencodeKit
//
// Created by Charlotte Tortorella on 27/1/17.
// Copyright © 2017 Monadic Consulting. All rights reserved.
//
public struct OrderedDictionary<Key: Hashable, Value>: Collection {
public typealias Index = Int
public func index(after i: Index) -> Index {
return i + 1
}
public var startIndex: Index {
return 0
}
public var endIndex: Index {
return keys.count
}
public var keys: Array<Key> = []
public var values: Array<Value> {
return keys.flatMap { dictionary[$0] }
}
private var dictionary: Dictionary<Key, Value> = [:]
public init(_ elements: [(Key, Value)] = []) {
self.keys = elements.map { $0.0 }
self.dictionary = Dictionary(uniqueKeysWithValues: elements)
}
public init(_ elements: (Key, Value)...) {
self.init(elements)
}
public subscript(key: Key) -> Value? {
get {
return dictionary[key]
}
set(newValue) {
if let value = newValue {
if dictionary.updateValue(value, forKey: key) == nil {
keys.append(key)
}
} else {
dictionary.removeValue(forKey: key)
keys = keys.filter { $0 != key }
}
}
}
public subscript(index: Index) -> (Key, Value) {
get {
let key = keys[index]
return (key, dictionary[key]!)
}
}
}
internal func bdecodeDictionary(_ data: Data, _ index: Data.Index) throws -> (Bencode, Data.Index) {
guard data[index] == "d" else {
throw BencodingError.invalidDictionary(index)
}
var currentIndex = data.index(after: index)
guard currentIndex != data.endIndex else {
throw BencodingError.unterminatedDictionary(index)
}
var values: [(String, Bencode)] = []
while !(data[currentIndex] == "e") {
let (keyMatch, valueIndex) = try bdecode(data, currentIndex)
guard case .bytes(let key) = keyMatch else {
throw BencodingError.nonStringDictionaryKey(currentIndex)
}
let (valueMatch, nextIndex) = try bdecode(data, valueIndex)
let stringKey = key.reduce("") { string, byte in
string.appendingFormat("%c", byte)
}
values.append((stringKey, valueMatch))
currentIndex = nextIndex
guard currentIndex != data.endIndex else {
throw BencodingError.unterminatedDictionary(index)
}
}
return (.dictionary(OrderedDictionary(values)), data.index(after: currentIndex))
}