Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 22 additions & 24 deletions Sources/FoundationEssentials/JSON/BufferView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,29 @@

@frozen @usableFromInline
internal struct BufferView<Element> {
@usableFromInline let baseAddress: UnsafeRawPointer
@usableFromInline let start: BufferViewIndex<Element>
@usableFromInline let count: Int

private var baseAddress: UnsafeRawPointer { start._rawValue }

@inlinable
init(baseAddress: UnsafeRawPointer, count: Int) {
init(start index: BufferViewIndex<Element>, count: Int) {
precondition(count >= 0, "Count must not be negative")
if !_isPOD(Element.self) {
precondition(
Int(bitPattern: baseAddress) & (MemoryLayout<Element>.alignment - 1) == 0,
index.isAligned,
"baseAddress must be properly aligned for \(Element.self)"
)
}
self.baseAddress = baseAddress
self.start = index
self.count = count
}

@inlinable
init(baseAddress: UnsafeRawPointer, count: Int) {
self.init(start: .init(rawValue: baseAddress), count: count)
}

init?(unsafeBufferPointer buffer: UnsafeBufferPointer<Element>) {
guard let baseAddress = UnsafeRawPointer(buffer.baseAddress) else { return nil }
self.init(baseAddress: baseAddress, count: buffer.count)
Expand Down Expand Up @@ -102,14 +109,10 @@ extension BufferView:
@usableFromInline typealias SubSequence = Self

@inlinable @inline(__always)
var startIndex: Index { .init(rawValue: baseAddress) }
var startIndex: Index { start }

@inlinable @inline(__always)
var endIndex: Index {
.init(
rawValue: baseAddress.advanced(by: count * MemoryLayout<Element>.stride)
)
}
var endIndex: Index { start.advanced(by: count) }

@inlinable @inline(__always)
var indices: Range<Index> {
Expand Down Expand Up @@ -213,12 +216,7 @@ extension BufferView:

@inlinable @inline(__always)
subscript(unchecked bounds: Range<BufferViewIndex<Element>>) -> Self {
get {
BufferView(
baseAddress: UnsafeRawPointer(bounds.lowerBound._rawValue),
count: bounds.count
)
}
get { BufferView(start: bounds.lowerBound, count: bounds.count) }
}

@_alwaysEmitIntoClient
Expand Down Expand Up @@ -367,37 +365,37 @@ extension BufferView {
func prefix(_ maxLength: Int) -> BufferView {
precondition(maxLength >= 0, "Can't have a prefix of negative length.")
let nc = maxLength < count ? maxLength : count
return BufferView(baseAddress: baseAddress, count: nc)
return BufferView(start: start, count: nc)
}

@usableFromInline
func suffix(_ maxLength: Int) -> BufferView {
precondition(maxLength >= 0, "Can't have a suffix of negative length.")
let nc = maxLength < count ? maxLength : count
let newStart = baseAddress.advanced(by: (count &- nc) * MemoryLayout<Element>.stride)
return BufferView(baseAddress: newStart, count: nc)
let newStart = start.advanced(by: count &- nc)
return BufferView(start: newStart, count: nc)
}

@usableFromInline
func dropFirst(_ k: Int = 1) -> BufferView {
precondition(k >= 0, "Can't drop a negative number of elements.")
let dc = k < count ? k : count
let newStart = baseAddress.advanced(by: dc * MemoryLayout<Element>.stride)
return BufferView(baseAddress: newStart, count: count &- dc)
let newStart = start.advanced(by: dc)
return BufferView(start: newStart, count: count &- dc)
}

@usableFromInline
func dropLast(_ k: Int = 1) -> BufferView {
precondition(k >= 0, "Can't drop a negative number of elements.")
let nc = k < count ? count &- k : 0
return BufferView(baseAddress: baseAddress, count: nc)
return BufferView(start: start, count: nc)
}

@usableFromInline
func prefix(upTo index: BufferViewIndex<Element>) -> BufferView {
_checkBounds(Range(uncheckedBounds: (startIndex, index)))
return BufferView(
baseAddress: baseAddress,
start: start,
count: distance(from: startIndex, to: index)
)
}
Expand All @@ -406,7 +404,7 @@ extension BufferView {
func suffix(from index: BufferViewIndex<Element>) -> BufferView {
_checkBounds(Range(uncheckedBounds: (index, endIndex)))
return BufferView(
baseAddress: index._rawValue,
start: index,
count: distance(from: index, to: endIndex)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ extension Data {
}
}

extension BufferView {
extension BufferView<UInt8> {
internal subscript(region: JSONMap.Region) -> BufferView {
precondition(
region.startOffset >= 0 && region.startOffset < count && region.count >= 0
Expand All @@ -39,7 +39,7 @@ extension BufferView {
}

internal subscript(unchecked region: JSONMap.Region) -> BufferView {
let address = startIndex._rawValue.advanced(by: region.startOffset)
return BufferView(baseAddress: address, count: region.count)
let address = startIndex.advanced(by: region.startOffset)
return BufferView(start: address, count: region.count)
}
}
24 changes: 14 additions & 10 deletions Sources/FoundationEssentials/JSON/JSON5Scanner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1029,20 +1029,24 @@ extension JSON5Scanner {
}

static func validateInfinity(from jsonBytes: BufferView<UInt8>, fullSource: BufferView<UInt8>) throws {
guard jsonBytes.count >= _json5Infinity.utf8CodeUnitCount else {
throw JSONError.invalidSpecialValue(expected: "\(_json5Infinity)", location: .sourceLocation(at: jsonBytes.startIndex, fullSource: fullSource))
}
guard strncmp(jsonBytes.baseAddress, _json5Infinity.utf8Start, _json5Infinity.utf8CodeUnitCount) == 0 else {
throw JSONError.invalidSpecialValue(expected: "\(_json5Infinity)", location: .sourceLocation(at: jsonBytes.startIndex, fullSource: fullSource))
try jsonBytes.withUnsafeRawPointer { ptr, count in
guard count >= _json5Infinity.utf8CodeUnitCount else {
throw JSONError.invalidSpecialValue(expected: "\(_json5Infinity)", location: .sourceLocation(at: jsonBytes.startIndex, fullSource: fullSource))
}
guard strncmp(ptr, _json5Infinity.utf8Start, _json5Infinity.utf8CodeUnitCount) == 0 else {
throw JSONError.invalidSpecialValue(expected: "\(_json5Infinity)", location: .sourceLocation(at: jsonBytes.startIndex, fullSource: fullSource))
}
}
}

static func validateNaN(from jsonBytes: BufferView<UInt8>, fullSource: BufferView<UInt8>) throws {
guard jsonBytes.count >= _json5NaN.utf8CodeUnitCount else {
throw JSONError.invalidSpecialValue(expected: "\(_json5NaN)", location: .sourceLocation(at: jsonBytes.startIndex, fullSource: fullSource))
}
guard strncmp(jsonBytes.baseAddress, _json5NaN.utf8Start, _json5NaN.utf8CodeUnitCount) == 0 else {
throw JSONError.invalidSpecialValue(expected: "\(_json5NaN)", location: .sourceLocation(at: jsonBytes.startIndex, fullSource: fullSource))
try jsonBytes.withUnsafeRawPointer { ptr, count in
guard count >= _json5NaN.utf8CodeUnitCount else {
throw JSONError.invalidSpecialValue(expected: "\(_json5NaN)", location: .sourceLocation(at: jsonBytes.startIndex, fullSource: fullSource))
}
guard strncmp(ptr, _json5NaN.utf8Start, _json5NaN.utf8CodeUnitCount) == 0 else {
throw JSONError.invalidSpecialValue(expected: "\(_json5NaN)", location: .sourceLocation(at: jsonBytes.startIndex, fullSource: fullSource))
}
}
}

Expand Down
15 changes: 8 additions & 7 deletions Sources/FoundationEssentials/JSON/JSONDecoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -873,14 +873,15 @@ extension JSONDecoderImpl: Decoder {
self.options.nonConformingFloatDecodingStrategy
{
let result = withBuffer(for: region) { (stringBuffer, _) -> T? in
if posInfString.withUTF8({ stringBuffer.count == $0.count && memcmp(stringBuffer.baseAddress, $0.baseAddress, $0.count) == 0 }) {
return T.infinity
} else if negInfString.withUTF8({ stringBuffer.count == $0.count && memcmp(stringBuffer.baseAddress, $0.baseAddress, $0.count) == 0 }) {
return -T.infinity
} else if nanString.withUTF8({ stringBuffer.count == $0.count && memcmp(stringBuffer.baseAddress, $0.baseAddress, $0.count) == 0 }) {
return T.nan
stringBuffer.withUnsafeRawPointer { (ptr, count) -> T? in
func bytesAreEqual(_ b: UnsafeBufferPointer<UInt8>) -> Bool {
count == b.count && memcmp(ptr, b.baseAddress, b.count) == 0
}
if posInfString.withUTF8(bytesAreEqual(_:)) { return T.infinity }
if negInfString.withUTF8(bytesAreEqual(_:)) { return -T.infinity }
if nanString.withUTF8(bytesAreEqual(_:)) { return T.nan }
return nil
}
return nil
}
if let result { return result }
}
Expand Down