/// Check if a byte is a digit @inline(__always) func isDigit(_ byte: UInt8) -> Bool { byte >= kZero && byte <= kNine } /// Looks for x and y separated by a comma. func parseCoordinates(_ bytes: T, _ start: Int, _ end: Int) -> ( MapPoint, Int )? where T.Element == UInt8, T.Index == Int { var index = skipWhitespace(bytes, end, start) guard let (xCoordinate, nextIndex) = parseSingleCoordinate(bytes, index, end) else { return nil } index = nextIndex guard expectComma(bytes, &index, end) else { return nil } guard let (yCoordinate, nextIndex) = parseSingleCoordinate(bytes, index, end) else { return nil } index = nextIndex guard expectClosingParen(bytes, &index, end) else { return nil } return (MapPoint(xCoordinate: xCoordinate, yCoordinate: yCoordinate), index) } /// Checks if a candidate for a coordinate is a digit, and parses it. @inline(__always) func parseSingleCoordinate(_ bytes: T, _ start: Int, _ end: Int) -> (Double, Int)? where T.Element == UInt8, T.Index == Int { var index = start while index < end && (isDigit(bytes[index]) || bytes[index] == 46) { index += 1 } guard index > start else { return nil } guard let value = parseDouble(bytes, start, index) else { return nil } return (value, index) } /// Advances the index until we find a comma. @inline(__always) func expectComma(_ bytes: T, _ index: inout Int, _ end: Int) -> Bool where T.Element == UInt8, T.Index == Int { index = skipWhitespace(bytes, end, index) guard index < end && bytes[index] == kComma else { return false } index += 1 index = skipWhitespace(bytes, end, index) return true } /// Advances the index until we find a closing parenthesis @inline(__always) func expectClosingParen(_ bytes: T, _ index: inout Int, _ end: Int) -> Bool where T.Element == UInt8, T.Index == Int { index = skipWhitespace(bytes, end, index) guard index < end && bytes[index] == kCloseParenthesis else { return false } index += 1 return true } /// Parses a double @inline(__always) func parseDouble(_ bytes: T, _ start: Int, _ end: Int) -> Double? where T.Element == UInt8, T.Index == Int { var index = skipWhitespace(bytes, end, start) let numStart = index while index < end && (isDigit(bytes[index]) || bytes[index] == kPeriod) { index += 1 } guard index > numStart else { return nil } // Why not String(data:encoding:)? This is much faster. // swiftlint:disable:next optional_data_string_conversion let str = String(decoding: bytes[numStart..(_ bytes: T, _ end: Int, _ start: Int) -> Int where T.Element == UInt8, T.Index == Int { var index = start while index < end && (bytes[index] == kSpace || bytes[index] == kTab) { index += 1 } return index } /// Decreases an index by looking for whitespace right-to-left func shaveWhitespace(_ bytes: T, _ start: Int, _ end: Int) -> Int where T.Element == UInt8, T.Index == Int { var index = end while index > start && (bytes[index - 1] == kSpace || bytes[index - 1] == kTab) { index -= 1 } return index } /// Given the bytes buffer, finds the next non-empty line. @inline(__always) func extractLine(_ bytes: T, _ index: inout Int, _ length: Int) -> ( Int, Int )? where T.Element == UInt8, T.Index == Int { while index < length && (bytes[index] == kNewline || bytes[index] == kCarriageReturn) { index += 1 } let lineStart = index while index < length && bytes[index] != kNewline && bytes[index] != kCarriageReturn { index += 1 } if lineStart == index { return nil } var start = lineStart var end = index start = skipWhitespace(bytes, end, start) end = shaveWhitespace(bytes, start, end) if start == end { return nil } return (start, end) } /// Trims a byte collection and returns a string @inline(__always) func extractTrimmedString(_ bytes: T, _ start: Int, _ end: Int) -> String? where T.Element == UInt8, T.Index == Int { var trimStart = start var trimEnd = end trimStart = skipWhitespace(bytes, trimEnd, trimStart) trimEnd = shaveWhitespace(bytes, trimStart, trimEnd) guard trimStart < trimEnd else { return nil } // Why not String(data:encoding:)? This is much faster. // swiftlint:disable:next optional_data_string_conversion return String(decoding: bytes[trimStart..