import Foundation private final class ValueBoxKeyImpl { let memory: UnsafeMutableRawPointer init(memory: UnsafeMutableRawPointer) { self.memory = memory } deinit { free(self.memory) } } public struct ValueBoxKey: Equatable, Hashable, CustomStringConvertible, Comparable { public let memory: UnsafeMutableRawPointer public let length: Int private let impl: ValueBoxKeyImpl public init(length: Int) { self.memory = malloc(length)! self.length = length self.impl = ValueBoxKeyImpl(memory: self.memory) } public init(_ value: String) { let data = value.data(using: .utf8, allowLossyConversion: true) ?? Data() 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) } public init(_ buffer: MemoryBuffer) { self.memory = malloc(buffer.length) self.length = buffer.length self.impl = ValueBoxKeyImpl(memory: self.memory) memcpy(self.memory, buffer.memory, buffer.length) } 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) } } public func setBytes(_ offset: Int, value: UnsafeRawBufferPointer) { assert(offset >= 0 && offset + value.count <= self.length) memcpy(self.memory + offset, value.baseAddress!.assumingMemoryBound(to: UInt8.self), value.count) } 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) } 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) } public func setInt64(_ offset: Int, value: Int64) { assert(offset >= 0 && offset + 8 <= self.length) var bigEndianValue = Int64(bigEndian: value) memcpy(self.memory + offset, &bigEndianValue, 8) } public func setInt8(_ offset: Int, value: Int8) { assert(offset >= 0 && offset + 1 <= self.length) var varValue = value memcpy(self.memory + offset, &varValue, 1) } public func setUInt8(_ offset: Int, value: UInt8) { assert(offset >= 0 && offset + 1 <= self.length) var varValue = value memcpy(self.memory + offset, &varValue, 1) } public func setUInt16(_ offset: Int, value: UInt16) { assert(offset >= 0 && offset + 2 <= self.length) var varValue = value memcpy(self.memory + offset, &varValue, 2) } public func getData(_ offset: Int, length: Int) -> Data { assert(offset >= 0 && offset + length <= self.length) var value = Data(count: length) let _ = value.withUnsafeMutableBytes { bytes in memcpy(bytes.baseAddress!.assumingMemoryBound(to: UInt8.self), self.memory + offset, length) } return value } public func getMemoryBuffer(_ offset: Int, length: Int) -> MemoryBuffer { assert(offset >= 0 && offset + length <= self.length) let result = MemoryBuffer(memory: malloc(length)!, capacity: length, length: length, freeWhenDone: true) memcpy(result.memory, self.memory + offset, length) return result } 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) } 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) } 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) } 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 } 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 } 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 } 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 } 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 } } 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 } 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 } 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 { if i == 0 { assert(self.length > 1) let previousKey = ValueBoxKey(length: self.length - 1) memcpy(previousKey.memory, self.memory, self.length - 1) return previousKey } else { byte = 0xff memory[i] = byte } } i -= 1 } return key } 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]) string.appendFormat("%02x", byte) } return string as String } public var stringValue: String { if let string = String(data: Data(bytes: self.memory, count: self.length), encoding: .utf8) { return string } else { return "" } } public func substringValue(_ range: Range) -> 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) } public func hash(into hasher: inout Hasher) { hasher.combine(bytes: UnsafeRawBufferPointer(start: self.memory, count: self.length)) } public static func ==(lhs: ValueBoxKey, rhs: ValueBoxKey) -> Bool { return lhs.length == rhs.length && memcmp(lhs.memory, rhs.memory, lhs.length) == 0 } public static func <(lhs: ValueBoxKey, rhs: ValueBoxKey) -> Bool { return mdb_cmp_memn(lhs.memory, lhs.length, rhs.memory, rhs.length) < 0 } 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) } 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 } } 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 len = a_length len_diff = a_length - b_length if len_diff > 0 { len = b_length len_diff = 1 } diff = Int(memcmp(a_memory, b_memory, len)) return diff != 0 ? diff : len_diff < 0 ? -1 : len_diff }