-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Creating Bytes from JSONValue with a Pointer #2
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -131,3 +131,117 @@ public func == (lhs: JSONValue, rhs: JSONValue) -> Bool { | |
return false | ||
} | ||
} | ||
|
||
@available(*, deprecated, message: "Don't use this, this is slow") | ||
class WritableBuffer { | ||
private var ptr: UnsafeMutableRawBufferPointer | ||
|
||
@usableFromInline typealias _Index = UInt32 | ||
@usableFromInline typealias _Capacity = UInt32 | ||
|
||
@usableFromInline var _index : _Index = 0 | ||
@usableFromInline var _capacity: _Capacity = 6144 | ||
|
||
init() { | ||
self.ptr = UnsafeMutableRawBufferPointer.allocate(byteCount: Int(_capacity), alignment: 0) | ||
} | ||
|
||
@inline(__always) func write(_ ptr: UnsafeRawBufferPointer) { | ||
let bytesCount = ptr.count | ||
let target = UnsafeMutableRawBufferPointer(rebasing: self.ptr.dropFirst(Int(_index))) | ||
target.copyBytes(from: ptr) | ||
self._index += _Index(bytesCount) | ||
} | ||
|
||
@inline(__always) func write(byte: UInt8) { | ||
self.ptr[Int(self._index)] = byte | ||
self._index += 1 | ||
} | ||
|
||
@inline(__always) func toBytes() -> [UInt8] { | ||
return [UInt8](ptr) | ||
} | ||
} | ||
|
||
extension WritableBuffer { | ||
|
||
func write(json: JSONValue) { | ||
|
||
switch json { | ||
case .null: | ||
self.write(byte: UInt8(ascii: "n")) | ||
self.write(byte: UInt8(ascii: "u")) | ||
self.write(byte: UInt8(ascii: "l")) | ||
self.write(byte: UInt8(ascii: "l")) | ||
|
||
case .bool(true): | ||
self.write(byte: UInt8(ascii: "t")) | ||
self.write(byte: UInt8(ascii: "r")) | ||
self.write(byte: UInt8(ascii: "u")) | ||
self.write(byte: UInt8(ascii: "e")) | ||
|
||
case .bool(false): | ||
self.write(byte: UInt8(ascii: "f")) | ||
self.write(byte: UInt8(ascii: "a")) | ||
self.write(byte: UInt8(ascii: "l")) | ||
self.write(byte: UInt8(ascii: "s")) | ||
self.write(byte: UInt8(ascii: "e")) | ||
|
||
case .string(let string): | ||
self.write(byte: UInt8(ascii: "\"")) | ||
string.utf8.withContiguousStorageIfAvailable { | ||
self.write(UnsafeRawBufferPointer($0)) | ||
} | ||
self.write(byte: UInt8(ascii: "\"")) | ||
case .number(let string): | ||
string.utf8.withContiguousStorageIfAvailable { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if contiguous storage isn't available? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was just a proof of concept, if I can make it faster with a pointer. So far I can't which is why I don't support nsstring for now. ;) |
||
self.write(UnsafeRawBufferPointer($0)) | ||
} | ||
case .array(let array): | ||
var iterator = array.makeIterator() | ||
self.write(byte: UInt8(ascii: "[")) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Iterators copy values more often than needed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Am I correct in assuming that you would vote for direct array access? for elem in array? |
||
// we don't like branching, this is why we have this extra | ||
if let first = iterator.next() { | ||
self.write(json: first) | ||
} | ||
while let item = iterator.next() { | ||
self.write(byte: UInt8(ascii: ",")) | ||
self.write(json: item) | ||
} | ||
self.write(byte: UInt8(ascii: "]")) | ||
case .object(let dict): | ||
var iterator = dict.makeIterator() | ||
self.write(byte: UInt8(ascii: "{")) | ||
if let (key, value) = iterator.next() { | ||
self.write(byte: UInt8(ascii: "\"")) | ||
key.utf8.withContiguousStorageIfAvailable { | ||
self.write(UnsafeRawBufferPointer($0)) | ||
} | ||
self.write(byte: UInt8(ascii: "\"")) | ||
self.write(byte: UInt8(ascii: ":")) | ||
self.write(json: value) | ||
} | ||
while let (key, value) = iterator.next() { | ||
self.write(byte: UInt8(ascii: ",")) | ||
self.write(byte: UInt8(ascii: "\"")) | ||
key.utf8.withContiguousStorageIfAvailable { | ||
self.write(UnsafeRawBufferPointer($0)) | ||
} | ||
self.write(byte: UInt8(ascii: "\"")) | ||
self.write(byte: UInt8(ascii: ":")) | ||
self.write(json: value) | ||
} | ||
self.write(byte: UInt8(ascii: "}")) | ||
} | ||
} | ||
} | ||
|
||
extension JSONValue { | ||
|
||
@available(*, deprecated, message: "Don't use this, this is slow") | ||
public func toBytes() -> [UInt8] { | ||
let buffer = WritableBuffer() | ||
buffer.write(json: self) | ||
return buffer.toBytes() | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These should be in bulk
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The implementation I use currently looks like this? Do you think this would be faster in this case?