174 lines
5.3 KiB
Swift

import Foundation
private let emptyMemory = malloc(1)!
public class MemoryBuffer: Equatable, CustomStringConvertible {
public internal(set) var memory: UnsafeMutableRawPointer
var capacity: Int
public internal(set) var length: Int
var freeWhenDone: Bool
public init(copyOf buffer: MemoryBuffer) {
self.memory = malloc(buffer.length)
memcpy(self.memory, buffer.memory, buffer.length)
self.capacity = buffer.length
self.length = buffer.length
self.freeWhenDone = true
}
public init(memory: UnsafeMutableRawPointer, capacity: Int, length: Int, freeWhenDone: Bool) {
self.memory = memory
self.capacity = capacity
self.length = length
self.freeWhenDone = freeWhenDone
}
public init(data: Data) {
if data.count == 0 {
self.memory = emptyMemory
self.capacity = 0
self.length = 0
self.freeWhenDone = false
} else {
self.memory = malloc(data.count)!
data.copyBytes(to: self.memory.assumingMemoryBound(to: UInt8.self), count: data.count)
self.capacity = data.count
self.length = data.count
self.freeWhenDone = false
}
}
public init() {
self.memory = emptyMemory
self.capacity = 0
self.length = 0
self.freeWhenDone = false
}
deinit {
if self.freeWhenDone {
free(self.memory)
}
}
public var description: String {
let hexString = NSMutableString()
let bytes = self.memory.assumingMemoryBound(to: UInt8.self)
for i in 0 ..< self.length {
hexString.appendFormat("%02x", UInt(bytes[i]))
}
return hexString as String
}
public func makeData() -> Data {
if self.length == 0 {
return Data()
} else {
return Data(bytes: self.memory, count: self.length)
}
}
public func withDataNoCopy(_ f: (Data) -> Void) {
f(Data(bytesNoCopy: self.memory, count: self.length, deallocator: .none))
}
public static func ==(lhs: MemoryBuffer, rhs: MemoryBuffer) -> Bool {
return lhs.length == rhs.length && memcmp(lhs.memory, rhs.memory, lhs.length) == 0
}
}
public final class WriteBuffer: MemoryBuffer {
public var offset = 0
public override init() {
super.init(memory: malloc(32), capacity: 32, length: 0, freeWhenDone: true)
}
public func makeReadBufferAndReset() -> ReadBuffer {
let buffer = ReadBuffer(memory: self.memory, length: self.offset, freeWhenDone: true)
self.memory = malloc(32)
self.capacity = 32
self.offset = 0
return buffer
}
public func readBufferNoCopy() -> ReadBuffer {
return ReadBuffer(memory: self.memory, length: self.offset, freeWhenDone: false)
}
override public func makeData() -> Data {
return Data(bytes: self.memory.assumingMemoryBound(to: UInt8.self), count: self.offset)
}
public func reset() {
self.offset = 0
}
public func write(_ data: UnsafeRawPointer, offset: Int, length: Int) {
if self.offset + length > self.capacity {
self.capacity = self.offset + length + 256
if self.length == 0 {
self.memory = malloc(self.capacity)!
} else {
self.memory = realloc(self.memory, self.capacity)
}
}
memcpy(self.memory + self.offset, data + offset, length)
self.offset += length
self.length = self.offset
}
public func write(_ data: Data) {
let length = data.count
if self.offset + length > self.capacity {
self.capacity = self.offset + length + 256
if self.length == 0 {
self.memory = malloc(self.capacity)!
} else {
self.memory = realloc(self.memory, self.capacity)
}
}
data.copyBytes(to: self.memory.advanced(by: offset).assumingMemoryBound(to: UInt8.self), count: length)
self.offset += length
self.length = self.offset
}
}
public final class ReadBuffer: MemoryBuffer {
public var offset = 0
override public init(data: Data) {
super.init(data: data)
}
public init(memory: UnsafeMutableRawPointer, length: Int, freeWhenDone: Bool) {
super.init(memory: memory, capacity: length, length: length, freeWhenDone: freeWhenDone)
}
public init(memoryBufferNoCopy: MemoryBuffer) {
super.init(memory: memoryBufferNoCopy.memory, capacity: memoryBufferNoCopy.length, length: memoryBufferNoCopy.length, freeWhenDone: false)
}
public func dataNoCopy() -> Data {
return Data(bytesNoCopy: self.memory.assumingMemoryBound(to: UInt8.self), count: self.length, deallocator: .none)
}
public func read(_ data: UnsafeMutableRawPointer, offset: Int, length: Int) {
memcpy(data + offset, self.memory.advanced(by: self.offset), length)
self.offset += length
}
public func skip(_ length: Int) {
self.offset += length
}
public func reset() {
self.offset = 0
}
public func sharedBufferNoCopy() -> ReadBuffer {
return ReadBuffer(memory: memory, length: length, freeWhenDone: false)
}
}