ValueBoxKey
ValueBoxKeyImpl
class
ValueBoxKeyImpl
1
2
3
4
5
let memory: UnsafeMutableRawPointer
deinit {
free(self.memory)
}
struct
ValueBoxKey:
Equatable,
Hashable,
Comparable
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
public let memory: UnsafeMutableRawPointer
public let length: Int
private let impl: ValueBoxKeyImpl
// utf8 encoding with allowLossyConversion option
// -[Data copyBytesTo:count:]
public init(_ value: String) {
let data = value.data(using: .utf8, allowLossyConversion: true) ?? Data()
// malloc
self.memory = malloc(data.count)
self.length = data.count
self.impl = ValueBoxKeyImpl(memory: self.memory)
data.copyBytes(to: self.memory.assumingMemoryBound(to: UInt8.self), count: data.count)
}
// init with memoryBuffer
public init(_ buffer: MemoryBuffer) {
// malloc
self.memory = malloc(buffer.length)
self.length = buffer.length
self.impl = ValueBoxKeyImpl(memory: self.memory)
// copy buffet.memory to self.memory
memcpy(self.memory, buffer.memory, buffer.length)
}
// copy bytes in data to self.memory + offset
public func setData(_ offset: Int, value: Data) {
assert(offset >= 0 && offset + value.count <= self.length)
let valueLength = value.count
value.withUnsafeBytes { rawBytes -> Void in
let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self)
memcpy(self.memory + offset, bytes, valueLength)
}
}
// copy bigEndian representation of value with 4 bytes to `self.memory + offset`
public func setInt32(_ offset: Int, value: Int32) {
assert(offset >= 0 && offset + 4 <= self.length)
var bigEndianValue = Int32(bigEndian: value)
memcpy(self.memory + offset, &bigEndianValue, 4)
}
// copy bigEndian representation of value with 4 bytes to `self.memory + offset`
public func setUInt32(_ offset: Int, value: UInt32) {
assert(offset >= 0 && offset + 4 <= self.length)
var bigEndianValue = UInt32(bigEndian: value)
memcpy(self.memory + offset, &bigEndianValue, 4)
}
// copy value with one byte to `self.memory + offset`
public func setInt8(_ offset: Int, value: Int8) {
assert(offset >= 0 && offset + 1 <= self.length)
var varValue = value
memcpy(self.memory + offset, &varValue, 1)
}
// copy value with one byte to `self.memory + offset`
public func setUInt8(_ offset: Int, value: UInt8) {
assert(offset >= 0 && offset + 1 <= self.length)
var varValue = value
memcpy(self.memory + offset, &varValue, 1)
}
// copy value with two bytes to `self.memory + offset`
public func setUInt16(_ offset: Int, value: UInt16) {
assert(offset >= 0 && offset + 2 <= self.length)
var varValue = value
memcpy(self.memory + offset, &varValue, 2)
}
// copy 4 bytes from self.memory + offset as a Int32 bigEndian value
public func getInt32(_ offset: Int) -> Int32 {
assert(offset >= 0 && offset + 4 <= self.length)
var value: Int32 = 0
memcpy(&value, self.memory + offset, 4)
return Int32(bigEndian: value)
}
// copy 4 bytes from self.memory + offset as a UInt32 bigEndian value
public func getUInt32(_ offset: Int) -> UInt32 {
assert(offset >= 0 && offset + 4 <= self.length)
var value: UInt32 = 0
memcpy(&value, self.memory + offset, 4)
return UInt32(bigEndian: value)
}
// copy 8 bytes from `self.memory + offset` as a Int32 bigEndian value
public func getInt64(_ offset: Int) -> Int64 {
assert(offset >= 0 && offset + 8 <= self.length)
var value: Int64 = 0
memcpy(&value, self.memory + offset, 8)
return Int64(bigEndian: value)
}
// copy one byte from `self.memory + offset` as a Int8 value
public func getInt8(_ offset: Int) -> Int8 {
assert(offset >= 0 && offset + 1 <= self.length)
var value: Int8 = 0
memcpy(&value, self.memory + offset, 1)
return value
}
// copy one byte from `self.memory + offset` as a UInt8 value
public func getUInt8(_ offset: Int) -> UInt8 {
assert(offset >= 0 && offset + 1 <= self.length)
var value: UInt8 = 0
memcpy(&value, self.memory + offset, 1)
return value
}
// copy two bytes from `self.memory + offset` as a UInt16 value
public func getUInt16(_ offset: Int) -> UInt16 {
assert(offset >= 0 && offset + 2 <= self.length)
var value: UInt16 = 0
memcpy(&value, self.memory + offset, 2)
return value
}
// copy prefix length bytes to a new created `ValueBoxKey`
public func prefix(_ length: Int) -> ValueBoxKey {
assert(length <= self.length, "length <= self.length")
let key = ValueBoxKey(length: length)
memcpy(key.memory, self.memory, length)
return key
}
// `memcmp` other's memory with self.prefix length memory bytes
public func isPrefix(to other: ValueBoxKey) -> Bool {
if self.length == 0 {
return true
} else if self.length <= other.length {
return memcmp(self.memory, other.memory, self.length) == 0
} else {
return false
}
}
// return the reverse result of self.memory in byte unit
public var reversed: ValueBoxKey {
let key = ValueBoxKey(length: self.length)
let keyMemory = key.memory.assumingMemoryBound(to: UInt8.self)
let selfMemory = self.memory.assumingMemoryBound(to: UInt8.self)
var i = self.length - 1
while i >= 0 {
keyMemory[i] = selfMemory[self.length - 1 - i]
i -= 1
}
return key
}
// plus 1 to last byte
public var successor: ValueBoxKey {
let key = ValueBoxKey(length: self.length)
memcpy(key.memory, self.memory, self.length)
let memory = key.memory.assumingMemoryBound(to: UInt8.self)
var i = self.length - 1
while i >= 0 {
var byte = memory[i]
if byte != 0xff {
byte += 1
memory[i] = byte
break
} else {
byte = 0
memory[i] = byte
}
i -= 1
}
return key
}
// the predecessor
// minus 1 from the last byte
public var predecessor: ValueBoxKey {
let key = ValueBoxKey(length: self.length)
memcpy(key.memory, self.memory, self.length)
let memory = key.memory.assumingMemoryBound(to: UInt8.self)
var i = self.length - 1
while i >= 0 {
var byte = memory[i]
if byte != 0x00 {
byte -= 1
memory[i] = byte
break
} else {// 0x00 byte
if i == 0 {// all bytes in self.memory are 0x00
// return the memory with copied bytes from self.memory in 0 ... self.length - 1 range
// with value [0x00 0xff 0xff ...]
assert(self.length > 1)
let previousKey = ValueBoxKey(length: self.length - 1)
memcpy(previousKey.memory, self.memory, self.length - 1)
return previousKey
} else {// if not the first, then replace the 0x00 with 0xff
byte = 0xff
memory[i] = byte
}
}
i -= 1
}
return key
}
// description
public var description: String {
let string = NSMutableString()
let memory = self.memory.assumingMemoryBound(to: UInt8.self)
for i in 0 ..< self.length {
let byte: Int = Int(memory[i])
// dump every single byte with two bits hex representation
string.appendFormat("%02x", byte)
}
return string as String
}
// utf8 encoded string of the bytes
public var stringValue: String {
if let string = String(data: Data(bytes: self.memory, count: self.length), encoding: .utf8) {
return string
} else {
return "<unavailable>"
}
}
// utf8 encoded string of bytes in range
public func substringValue(_ range: Range<Int>) -> String? {
assert(range.lowerBound >= 0 && range.upperBound <= self.length)
return String(data: Data(bytes: self.memory.advanced(by: range.lowerBound), count: range.count), encoding: .utf8)
}
// hashable
public func hash(into hasher: inout Hasher) {
hasher.combine(bytes: UnsafeRawBufferPointer(start: self.memory, count: self.length))
}
// memcmp
public static func ==(lhs: ValueBoxKey, rhs: ValueBoxKey) -> Bool {
return lhs.length == rhs.length && memcmp(lhs.memory, rhs.memory, lhs.length) == 0
}
// mdb_cmp_memn
public static func <(lhs: ValueBoxKey, rhs: ValueBoxKey) -> Bool {
return mdb_cmp_memn(lhs.memory, lhs.length, rhs.memory, rhs.length) < 0
}
// return a memory buffer with copies memory bytes
public func toMemoryBuffer() -> MemoryBuffer {
let data = malloc(self.length)!
memcpy(data, self.memory, self.length)
return MemoryBuffer(memory: data, capacity: self.length, length: self.length, freeWhenDone: true)
}
// return new key with memory alignment [lhs.memory rhs.memory]
public static func +(lhs: ValueBoxKey, rhs: ValueBoxKey) -> ValueBoxKey {
let result = ValueBoxKey(length: lhs.length + rhs.length)
memcpy(result.memory, lhs.memory, lhs.length)
memcpy(result.memory.advanced(by: lhs.length), rhs.memory, rhs.length)
return result
}
mdb_cmp_memn
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private func mdb_cmp_memn(_ a_memory: UnsafeMutableRawPointer, _ a_length: Int, _ b_memory: UnsafeMutableRawPointer, _ b_length: Int) -> Int
{
var diff: Int = 0
var len_diff: Int = 0
var len: Int = 0 // min(a_length, b_length)
len = a_length
len_diff = a_length - b_length
if len_diff > 0 {
len = b_length
len_diff = 1
}
// memcmp len bytes
diff = Int(memcmp(a_memory, b_memory, len))
return diff != 0 ? diff : len_diff < 0 ? -1 : len_diff
}
memcmp
<=
the first byte that does not match in both memory blocks has a lower value in ptr1 than in ptr2 (if evaluated as unsigned char values)=0
the contents of both memory blocks are equal>0
the first byte that does not match in both memory blocks has a greater value in ptr1 than in ptr2 (if evaluated as unsigned char values)
ValueBox
enum
ValueBoxFilterResult
1
2
3
case accept
case skip
case stop
protocol
ValueBox
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
func begin()
func commit()
func checkpoint()
func beginStats()
func endStats()
// evalute the records from start to end until the evaluation expression `values` return false
func range(_ table: ValueBoxTable, start: ValueBoxKey, end: ValueBoxKey, values: (ValueBoxKey, ReadBuffer) -> Bool, limit: Int)
// evalute the records from start to end
// ignore the `skip` record
// accetp the `accept` record
// stop when reach a `stop` record
// break when acceptedCount reach the `limit`
// break when no records
func filteredRange(_ table: ValueBoxTable, start: ValueBoxKey, end: ValueBoxKey, values: (ValueBoxKey, ReadBuffer) -> ValueBoxFilterResult, limit: Int)
// evalute the records from start to end
// ignore the `skip` record
// accetp the `accept` record
// stop when reach a `stop` record
// break when acceptedCount reach the `limit`
// break when no records
func filteredRange(_ table: ValueBoxTable, start: ValueBoxKey, end: ValueBoxKey, keys: (ValueBoxKey) -> ValueBoxFilterResult, limit: Int)
// evalute the records from start to end until the evaluation expression `keys` return false
func range(_ table: ValueBoxTable, start: ValueBoxKey, end: ValueBoxKey, keys: (ValueBoxKey) -> Bool, limit: Int)
// evalute the records until the evaluation expression `values` return false
func scan(_ table: ValueBoxTable, values: (ValueBoxKey, ReadBuffer) -> Bool)
// evalute the records until the evaluation expression `keys` return false
func scan(_ table: ValueBoxTable, keys: (ValueBoxKey) -> Bool)
// evalute the records until the evaluation expression `values` return false
func scanInt64(_ table: ValueBoxTable, values: (Int64, ReadBuffer) -> Bool)
// evalute the records until the evaluation expression `keys` return false
func scanInt64(_ table: ValueBoxTable, keys: (Int64) -> Bool)
// get value with key
func get(_ table: ValueBoxTable, key: ValueBoxKey) -> ReadBuffer?
// read the value blob incrementally
func read(_ table: ValueBoxTable, key: ValueBoxKey, _ process: (Int, (UnsafeMutableRawPointer, Int, Int) -> Void) -> Void)
// read & write the value blob incrementally
func readWrite(_ table: ValueBoxTable, key: ValueBoxKey, _ process: (Int, (UnsafeMutableRawPointer, Int, Int) -> Void, (UnsafeRawPointer, Int, Int) -> Void) -> Void)
// whether the `value` associated with the `key` exists
func exists(_ table: ValueBoxTable, key: ValueBoxKey) -> Bool
// set `value` for `key`
func set(_ table: ValueBoxTable, key: ValueBoxKey, value: MemoryBuffer)
// remove with key
func remove(_ table: ValueBoxTable, key: ValueBoxKey, secure: Bool)
// update key from previousKey to updatedKey
func move(_ table: ValueBoxTable, from previousKey: ValueBoxKey, to updatedKey: ValueBoxKey)
// copy record with fromkey from fromTable to toTable with toKey
func copy(fromTable: ValueBoxTable, fromKey: ValueBoxKey, toTable: ValueBoxTable, toKey: ValueBoxKey)
// remove records with the key from start to end
func removeRange(_ table: ValueBoxTable, start: ValueBoxKey, end: ValueBoxKey)
// insert info full text table
/**
guard let collectionIdData = collectionId.data(using: .utf8), let itemIdData = itemId.data(using: .utf8), let contentsData = contents.data(using: .utf8), let tagsData = tags.data(using: .utf8) else {
return
}
sqlite3_prepare_v2(self.database.handle, "INSERT INTO ft\(table.id) (collectionId, itemId, contents, tags) VALUES(?, ?, ?, ?)", -1, &statement, nil)
*/
func fullTextSet(_ table: ValueBoxFullTextTable, collectionId: String, itemId: String, contents: String, tags: String)
// evalute the records with associated given values
// until the evaluation expression `values` return false
func fullTextMatch(_ table: ValueBoxFullTextTable, collectionId: String?, query: String, tags: String?, values: (String, String) -> Bool)
// remove records with associated itemid
func fullTextRemove(_ table: ValueBoxFullTextTable, itemId: String, secure: Bool)
// empty the table
func removeAllFromTable(_ table: ValueBoxTable)
// drop the table
func removeTable(_ table: ValueBoxTable)
// rename table
func renameTable(_ table: ValueBoxTable, to toTable: ValueBoxTable)
// remote the database and tables from disk also memory
func drop()
// count records with associated key in start ... end range
func count(_ table: ValueBoxTable, start: ValueBoxKey, end: ValueBoxKey) -> Int
// count all records in table
func count(_ table: ValueBoxTable) -> Int
// detach database which previous attached from exportBsePath
func exportEncrypted(to exportBasePath: String, encryptionParameters: ValueBoxEncryptionParameters)
ValueBoxTable
struct
ValueBoxTable
1
2
3
let id: Int32
let keyType: ValueBoxKeyType
let compactValuesOnCreation: Bool
SqliteValueBoxTable
struct
SqliteValueBoxTable
1
2
let table: ValueBoxTable
let hasPrimaryKey: Bool
SqliteValueBox
class
SqliteValueBox:
ValueBox
见另一篇
Table
class
Table
1
2
3
4
5
6
7
8
public final let valueBox: ValueBox
public final let table: ValueBoxTable
public final let useCaches: Bool
open func clearMemoryCache() {
}
open func beforeCommit() {
}