ByteBuffer: provide multi read/write int methods (#1987)
Motivation: Many network protocols (especially for example NFS) have quite a number of integer values next to each other. In NIO, you'd normally parse/write them with multiple read/writeInteger calls. Unfortunately, that's a bit wasteful because we're checking the bounds as well as the CoW state every time. Modifications: - Provide read/writeMultipleIntegers for up to 15 FixedWidthIntegers. - Benchmarks Result: Faster code. For 10 UInt32s, this is a 5x performance win on my machine, see benchmarks.
This commit is contained in:
parent
addf69cfe6
commit
b2629903ca
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,86 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// This source file is part of the SwiftNIO open source project
|
||||||
|
//
|
||||||
|
// Copyright (c) 2021 Apple Inc. and the SwiftNIO project authors
|
||||||
|
// Licensed under Apache License v2.0
|
||||||
|
//
|
||||||
|
// See LICENSE.txt for license information
|
||||||
|
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
import NIOCore
|
||||||
|
|
||||||
|
final class ByteBufferReadWriteMultipleIntegersBenchmark<I: FixedWidthInteger>: Benchmark {
|
||||||
|
private let iterations: Int
|
||||||
|
private let numberOfInts: Int
|
||||||
|
private var buffer: ByteBuffer = ByteBuffer()
|
||||||
|
|
||||||
|
init(iterations: Int, numberOfInts: Int) {
|
||||||
|
self.iterations = iterations
|
||||||
|
self.numberOfInts = numberOfInts
|
||||||
|
}
|
||||||
|
|
||||||
|
func setUp() throws {
|
||||||
|
self.buffer.reserveCapacity(self.numberOfInts * MemoryLayout<I>.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func tearDown() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func run() throws -> Int {
|
||||||
|
var result: I = 0
|
||||||
|
for _ in 0..<self.iterations {
|
||||||
|
for i in I(0)..<I(10) {
|
||||||
|
self.buffer.writeInteger(i)
|
||||||
|
}
|
||||||
|
for _ in I(0)..<I(10) {
|
||||||
|
result = result &+ self.buffer.readInteger(as: I.self)!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
precondition(result == I(self.iterations) * 45)
|
||||||
|
return self.buffer.readableBytes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final class ByteBufferMultiReadWriteTenIntegersBenchmark<I: FixedWidthInteger>: Benchmark {
|
||||||
|
private let iterations: Int
|
||||||
|
private var buffer: ByteBuffer = ByteBuffer()
|
||||||
|
|
||||||
|
init(iterations: Int) {
|
||||||
|
self.iterations = iterations
|
||||||
|
}
|
||||||
|
|
||||||
|
func setUp() throws {
|
||||||
|
self.buffer.reserveCapacity(10 * MemoryLayout<I>.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func tearDown() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func run() throws -> Int {
|
||||||
|
var result: I = 0
|
||||||
|
for _ in 0..<self.iterations {
|
||||||
|
self.buffer.writeMultipleIntegers(
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
|
||||||
|
as: (I, I, I, I, I, I, I, I, I, I).self
|
||||||
|
)
|
||||||
|
let value = self.buffer.readMultipleIntegers(as: (I, I, I, I, I, I, I, I, I, I).self)!
|
||||||
|
result = result &+ value.0
|
||||||
|
result = result &+ value.1
|
||||||
|
result = result &+ value.2
|
||||||
|
result = result &+ value.3
|
||||||
|
result = result &+ value.4
|
||||||
|
result = result &+ value.5
|
||||||
|
result = result &+ value.6
|
||||||
|
result = result &+ value.7
|
||||||
|
result = result &+ value.8
|
||||||
|
result = result &+ value.9
|
||||||
|
}
|
||||||
|
precondition(result == I(self.iterations) * 45)
|
||||||
|
return self.buffer.readableBytes
|
||||||
|
}
|
||||||
|
}
|
|
@ -814,3 +814,9 @@ try measureAndPrint(desc: "byte_to_message_decoder_decode_many_small",
|
||||||
measureAndPrint(desc: "generate_10k_random_request_keys") {
|
measureAndPrint(desc: "generate_10k_random_request_keys") {
|
||||||
return (0 ..< 10_000).reduce(into: 0, { result, _ in result &+= NIOWebSocketClientUpgrader.randomRequestKey().count })
|
return (0 ..< 10_000).reduce(into: 0, { result, _ in result &+= NIOWebSocketClientUpgrader.randomRequestKey().count })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try measureAndPrint(desc: "bytebuffer_rw_10_uint32s",
|
||||||
|
benchmark: ByteBufferReadWriteMultipleIntegersBenchmark<UInt32>(iterations: 1_000_000, numberOfInts: 10))
|
||||||
|
|
||||||
|
try measureAndPrint(desc: "bytebuffer_multi_rw_10_uint32s",
|
||||||
|
benchmark: ByteBufferMultiReadWriteTenIntegersBenchmark<UInt32>(iterations: 1_000_000))
|
||||||
|
|
|
@ -109,8 +109,10 @@ extension NIOWebSocketClientUpgrader {
|
||||||
var buffer = ByteBuffer()
|
var buffer = ByteBuffer()
|
||||||
buffer.reserveCapacity(minimumWritableBytes: 16)
|
buffer.reserveCapacity(minimumWritableBytes: 16)
|
||||||
/// we may want to use `randomBytes(count:)` once the proposal is accepted: https://forums.swift.org/t/pitch-requesting-larger-amounts-of-randomness-from-systemrandomnumbergenerator/27226
|
/// we may want to use `randomBytes(count:)` once the proposal is accepted: https://forums.swift.org/t/pitch-requesting-larger-amounts-of-randomness-from-systemrandomnumbergenerator/27226
|
||||||
buffer.writeInteger(UInt64.random(in: UInt64.min...UInt64.max, using: &generator))
|
buffer.writeMultipleIntegers(
|
||||||
buffer.writeInteger(UInt64.random(in: UInt64.min...UInt64.max, using: &generator))
|
UInt64.random(in: UInt64.min...UInt64.max, using: &generator),
|
||||||
|
UInt64.random(in: UInt64.min...UInt64.max, using: &generator)
|
||||||
|
)
|
||||||
return String(base64Encoding: buffer.readableBytesView)
|
return String(base64Encoding: buffer.readableBytesView)
|
||||||
}
|
}
|
||||||
/// Generates a random WebSocket Request Key by generating 16 bytes randomly using the `SystemRandomNumberGenerator` and encoding them as a base64 string as defined in RFC6455 https://tools.ietf.org/html/rfc6455#section-4.1.
|
/// Generates a random WebSocket Request Key by generating 16 bytes randomly using the `SystemRandomNumberGenerator` and encoding them as a base64 string as defined in RFC6455 https://tools.ietf.org/html/rfc6455#section-4.1.
|
||||||
|
|
|
@ -221,6 +221,9 @@ extension ByteBufferTest {
|
||||||
("testHashableConformance", testHashableConformance),
|
("testHashableConformance", testHashableConformance),
|
||||||
("testInvalidHash", testInvalidHash),
|
("testInvalidHash", testInvalidHash),
|
||||||
("testValidHashFromSlice", testValidHashFromSlice),
|
("testValidHashFromSlice", testValidHashFromSlice),
|
||||||
|
("testWritingMultipleIntegers", testWritingMultipleIntegers),
|
||||||
|
("testReadAndWriteMultipleIntegers", testReadAndWriteMultipleIntegers),
|
||||||
|
("testAllByteBufferMultiByteVersions", testAllByteBufferMultiByteVersions),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3128,4 +3128,123 @@ extension ByteBufferTest {
|
||||||
XCTAssertEqual(bufferView.hashValue, comparisonBufferView.hashValue)
|
XCTAssertEqual(bufferView.hashValue, comparisonBufferView.hashValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testWritingMultipleIntegers() {
|
||||||
|
let w1 = self.buf.writeMultipleIntegers(UInt32(1), UInt8(2), UInt16(3), UInt64(4), UInt16(5), endianness: .big)
|
||||||
|
let w2 = self.buf.writeMultipleIntegers(UInt32(1), UInt8(2), UInt16(3), UInt64(4), UInt16(5), endianness: .little)
|
||||||
|
XCTAssertEqual(17, w1)
|
||||||
|
XCTAssertEqual(17, w2)
|
||||||
|
|
||||||
|
let one1 = self.buf.readInteger(endianness: .big, as: UInt32.self)
|
||||||
|
let two1 = self.buf.readInteger(endianness: .big, as: UInt8.self)
|
||||||
|
let three1 = self.buf.readInteger(endianness: .big, as: UInt16.self)
|
||||||
|
let four1 = self.buf.readInteger(endianness: .big, as: UInt64.self)
|
||||||
|
let five1 = self.buf.readInteger(endianness: .big, as: UInt16.self)
|
||||||
|
let one2 = self.buf.readInteger(endianness: .little, as: UInt32.self)
|
||||||
|
let two2 = self.buf.readInteger(endianness: .little, as: UInt8.self)
|
||||||
|
let three2 = self.buf.readInteger(endianness: .little, as: UInt16.self)
|
||||||
|
let four2 = self.buf.readInteger(endianness: .little, as: UInt64.self)
|
||||||
|
let five2 = self.buf.readInteger(endianness: .little, as: UInt16.self)
|
||||||
|
|
||||||
|
XCTAssertEqual(1, one1)
|
||||||
|
XCTAssertEqual(1, one2)
|
||||||
|
XCTAssertEqual(2, two1)
|
||||||
|
XCTAssertEqual(2, two2)
|
||||||
|
XCTAssertEqual(3, three1)
|
||||||
|
XCTAssertEqual(3, three2)
|
||||||
|
XCTAssertEqual(4, four1)
|
||||||
|
XCTAssertEqual(4, four2)
|
||||||
|
XCTAssertEqual(5, five1)
|
||||||
|
XCTAssertEqual(5, five2)
|
||||||
|
|
||||||
|
XCTAssertEqual(self.buf.readableBytes, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testReadAndWriteMultipleIntegers() {
|
||||||
|
for endianness in [Endianness.little, .big] {
|
||||||
|
let v1: UInt8 = .random(in: .min ... .max)
|
||||||
|
let v2: UInt16 = .random(in: .min ... .max)
|
||||||
|
let v3: UInt32 = .random(in: .min ... .max)
|
||||||
|
let v4: UInt64 = .random(in: .min ... .max)
|
||||||
|
let v5: UInt64 = .random(in: .min ... .max)
|
||||||
|
let v6: UInt32 = .random(in: .min ... .max)
|
||||||
|
let v7: UInt16 = .random(in: .min ... .max)
|
||||||
|
let v8: UInt8 = .random(in: .min ... .max)
|
||||||
|
let v9: UInt16 = .random(in: .min ... .max)
|
||||||
|
let v10: UInt32 = .random(in: .min ... .max)
|
||||||
|
|
||||||
|
let startWriterIndex = self.buf.writerIndex
|
||||||
|
let written = self.buf.writeMultipleIntegers(
|
||||||
|
v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
|
||||||
|
endianness: endianness,
|
||||||
|
as: (UInt8, UInt16, UInt32, UInt64, UInt64, UInt32, UInt16, UInt8, UInt16, UInt32).self)
|
||||||
|
XCTAssertEqual(startWriterIndex + written, self.buf.writerIndex)
|
||||||
|
XCTAssertEqual(written, self.buf.readableBytes)
|
||||||
|
|
||||||
|
let result = self.buf.readMultipleIntegers(endianness: endianness,
|
||||||
|
as: (UInt8, UInt16, UInt32, UInt64, UInt64, UInt32, UInt16, UInt8, UInt16, UInt32).self)
|
||||||
|
XCTAssertNotNil(result)
|
||||||
|
XCTAssertEqual(0, self.buf.readableBytes)
|
||||||
|
|
||||||
|
XCTAssertEqual(v1, result?.0, "endianness: \(endianness)")
|
||||||
|
XCTAssertEqual(v2, result?.1, "endianness: \(endianness)")
|
||||||
|
XCTAssertEqual(v3, result?.2, "endianness: \(endianness)")
|
||||||
|
XCTAssertEqual(v4, result?.3, "endianness: \(endianness)")
|
||||||
|
XCTAssertEqual(v5, result?.4, "endianness: \(endianness)")
|
||||||
|
XCTAssertEqual(v6, result?.5, "endianness: \(endianness)")
|
||||||
|
XCTAssertEqual(v7, result?.6, "endianness: \(endianness)")
|
||||||
|
XCTAssertEqual(v8, result?.7, "endianness: \(endianness)")
|
||||||
|
XCTAssertEqual(v9, result?.8, "endianness: \(endianness)")
|
||||||
|
XCTAssertEqual(v10, result?.9, "endianness: \(endianness)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAllByteBufferMultiByteVersions() {
|
||||||
|
let i = UInt8(86)
|
||||||
|
self.buf.writeMultipleIntegers(i, i)
|
||||||
|
self.buf.writeMultipleIntegers(i, i, i)
|
||||||
|
self.buf.writeMultipleIntegers(i, i, i, i)
|
||||||
|
self.buf.writeMultipleIntegers(i, i, i, i, i)
|
||||||
|
self.buf.writeMultipleIntegers(i, i, i, i, i, i)
|
||||||
|
self.buf.writeMultipleIntegers(i, i, i, i, i, i, i)
|
||||||
|
self.buf.writeMultipleIntegers(i, i, i, i, i, i, i, i)
|
||||||
|
self.buf.writeMultipleIntegers(i, i, i, i, i, i, i, i, i)
|
||||||
|
self.buf.writeMultipleIntegers(i, i, i, i, i, i, i, i, i, i)
|
||||||
|
self.buf.writeMultipleIntegers(i, i, i, i, i, i, i, i, i, i, i)
|
||||||
|
self.buf.writeMultipleIntegers(i, i, i, i, i, i, i, i, i, i, i, i)
|
||||||
|
self.buf.writeMultipleIntegers(i, i, i, i, i, i, i, i, i, i, i, i, i)
|
||||||
|
self.buf.writeMultipleIntegers(i, i, i, i, i, i, i, i, i, i, i, i, i, i)
|
||||||
|
self.buf.writeMultipleIntegers(i, i, i, i, i, i, i, i, i, i, i, i, i, i, i)
|
||||||
|
XCTAssertEqual(Array(repeating: UInt8(86), count: 119), Array(self.buf.readableBytesView))
|
||||||
|
var values2 = self.buf.readMultipleIntegers(as: (UInt8, UInt8).self)!
|
||||||
|
var values3 = self.buf.readMultipleIntegers(as: (UInt8, UInt8, UInt8).self)!
|
||||||
|
var values4 = self.buf.readMultipleIntegers(as: (UInt8, UInt8, UInt8, UInt8).self)!
|
||||||
|
var values5 = self.buf.readMultipleIntegers(as: (UInt8, UInt8, UInt8, UInt8, UInt8).self)!
|
||||||
|
var values6 = self.buf.readMultipleIntegers(as: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8).self)!
|
||||||
|
var values7 = self.buf.readMultipleIntegers(as: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8).self)!
|
||||||
|
var values8 = self.buf.readMultipleIntegers(as: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8).self)!
|
||||||
|
var values9 = self.buf.readMultipleIntegers(as: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8).self)!
|
||||||
|
var values10 = self.buf.readMultipleIntegers(as: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8).self)!
|
||||||
|
var values11 = self.buf.readMultipleIntegers(as: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8).self)!
|
||||||
|
var values12 = self.buf.readMultipleIntegers(as: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8).self)!
|
||||||
|
var values13 = self.buf.readMultipleIntegers(as: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8).self)!
|
||||||
|
var values14 = self.buf.readMultipleIntegers(as: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8).self)!
|
||||||
|
var values15 = self.buf.readMultipleIntegers(as: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8).self)!
|
||||||
|
|
||||||
|
XCTAssertEqual([i, i], withUnsafeBytes(of: &values2, { Array($0) }))
|
||||||
|
XCTAssertEqual([i, i, i], withUnsafeBytes(of: &values3, { Array($0) }))
|
||||||
|
XCTAssertEqual([i, i, i, i], withUnsafeBytes(of: &values4, { Array($0) }))
|
||||||
|
XCTAssertEqual([i, i, i, i, i], withUnsafeBytes(of: &values5, { Array($0) }))
|
||||||
|
XCTAssertEqual([i, i, i, i, i, i], withUnsafeBytes(of: &values6, { Array($0) }))
|
||||||
|
XCTAssertEqual([i, i, i, i, i, i, i], withUnsafeBytes(of: &values7, { Array($0) }))
|
||||||
|
XCTAssertEqual([i, i, i, i, i, i, i, i], withUnsafeBytes(of: &values8, { Array($0) }))
|
||||||
|
XCTAssertEqual([i, i, i, i, i, i, i, i, i], withUnsafeBytes(of: &values9, { Array($0) }))
|
||||||
|
XCTAssertEqual([i, i, i, i, i, i, i, i, i, i], withUnsafeBytes(of: &values10, { Array($0) }))
|
||||||
|
XCTAssertEqual([i, i, i, i, i, i, i, i, i, i, i], withUnsafeBytes(of: &values11, { Array($0) }))
|
||||||
|
XCTAssertEqual([i, i, i, i, i, i, i, i, i, i, i, i], withUnsafeBytes(of: &values12, { Array($0) }))
|
||||||
|
XCTAssertEqual([i, i, i, i, i, i, i, i, i, i, i, i, i], withUnsafeBytes(of: &values13, { Array($0) }))
|
||||||
|
XCTAssertEqual([i, i, i, i, i, i, i, i, i, i, i, i, i, i], withUnsafeBytes(of: &values14, { Array($0) }))
|
||||||
|
XCTAssertEqual([i, i, i, i, i, i, i, i, i, i, i, i, i, i, i], withUnsafeBytes(of: &values15, { Array($0) }))
|
||||||
|
|
||||||
|
XCTAssertEqual(0, self.buf.readableBytes)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,169 @@
|
||||||
|
#!/bin/bash
|
||||||
|
##===----------------------------------------------------------------------===##
|
||||||
|
##
|
||||||
|
## This source file is part of the SwiftNIO open source project
|
||||||
|
##
|
||||||
|
## Copyright (c) 2021 Apple Inc. and the SwiftNIO project authors
|
||||||
|
## Licensed under Apache License v2.0
|
||||||
|
##
|
||||||
|
## See LICENSE.txt for license information
|
||||||
|
## See CONTRIBUTORS.txt for the list of SwiftNIO project authors
|
||||||
|
##
|
||||||
|
## SPDX-License-Identifier: Apache-2.0
|
||||||
|
##
|
||||||
|
##===----------------------------------------------------------------------===##
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
here="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
|
||||||
|
function gen() {
|
||||||
|
how_many=$1
|
||||||
|
|
||||||
|
# READ
|
||||||
|
echo " @inlinable"
|
||||||
|
echo " @_alwaysEmitIntoClient"
|
||||||
|
echo -n " public mutating func readMultipleIntegers<T1: FixedWidthInteger"
|
||||||
|
for n in $(seq 2 "$how_many"); do
|
||||||
|
echo -n ", T$n: FixedWidthInteger"
|
||||||
|
done
|
||||||
|
echo -n ">("
|
||||||
|
echo -n "endianness: Endianness = .big, as: (T1"
|
||||||
|
for n in $(seq 2 "$how_many"); do
|
||||||
|
echo -n ", T$n"
|
||||||
|
done
|
||||||
|
echo -n ").Type = (T1"
|
||||||
|
for n in $(seq 2 "$how_many"); do
|
||||||
|
echo -n ", T$n"
|
||||||
|
done
|
||||||
|
echo -n ").self) -> (T1"
|
||||||
|
for n in $(seq 2 "$how_many"); do
|
||||||
|
echo -n ", T$n"
|
||||||
|
done
|
||||||
|
echo ")? {"
|
||||||
|
echo " var bytesRequired: Int = MemoryLayout<T1>.size"
|
||||||
|
for n in $(seq 2 "$how_many"); do
|
||||||
|
echo " bytesRequired &+= MemoryLayout<T$n>.size"
|
||||||
|
done
|
||||||
|
echo
|
||||||
|
echo " guard self.readableBytes >= bytesRequired else {"
|
||||||
|
echo " return nil"
|
||||||
|
echo " }"
|
||||||
|
echo
|
||||||
|
for n in $(seq 1 "$how_many"); do
|
||||||
|
echo " var v$n: T$n = 0"
|
||||||
|
done
|
||||||
|
echo " var offset = 0"
|
||||||
|
echo " self.readWithUnsafeReadableBytes { ptr -> Int in"
|
||||||
|
echo " assert(ptr.count >= bytesRequired)"
|
||||||
|
echo " let basePtr = ptr.baseAddress! // safe, ptr is non-empty"
|
||||||
|
for n in $(seq 1 "$how_many"); do
|
||||||
|
echo " withUnsafeMutableBytes(of: &v$n) { destPtr in"
|
||||||
|
echo " destPtr.baseAddress!.copyMemory(from: basePtr + offset, byteCount: MemoryLayout<T$n>.size)"
|
||||||
|
echo " }"
|
||||||
|
echo " offset = offset &+ MemoryLayout<T$n>.size"
|
||||||
|
done
|
||||||
|
echo " assert(offset == bytesRequired)"
|
||||||
|
echo " return offset"
|
||||||
|
echo " }"
|
||||||
|
echo " switch endianness {"
|
||||||
|
for endianness in big little; do
|
||||||
|
echo " case .$endianness:"
|
||||||
|
echo -n " return (T1(${endianness}Endian: v1)"
|
||||||
|
for n in $(seq 2 "$how_many"); do
|
||||||
|
echo -n ", T$n(${endianness}Endian: v$n)"
|
||||||
|
done
|
||||||
|
echo ")"
|
||||||
|
done
|
||||||
|
echo " }"
|
||||||
|
echo " }"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# WRITE
|
||||||
|
echo " @inlinable"
|
||||||
|
echo " @_alwaysEmitIntoClient"
|
||||||
|
echo " @discardableResult"
|
||||||
|
echo -n " public mutating func writeMultipleIntegers<T1: FixedWidthInteger"
|
||||||
|
for n in $(seq 2 "$how_many"); do
|
||||||
|
echo -n ", T$n: FixedWidthInteger"
|
||||||
|
done
|
||||||
|
echo -n ">(_ value1: T1"
|
||||||
|
for n in $(seq 2 "$how_many"); do
|
||||||
|
echo -n ", _ value$n: T$n"
|
||||||
|
done
|
||||||
|
echo -n ", endianness: Endianness = .big, as: (T1"
|
||||||
|
for n in $(seq 2 "$how_many"); do
|
||||||
|
echo -n ", T$n"
|
||||||
|
done
|
||||||
|
echo -n ").Type = (T1"
|
||||||
|
for n in $(seq 2 "$how_many"); do
|
||||||
|
echo -n ", T$n"
|
||||||
|
done
|
||||||
|
echo ").self) -> Int {"
|
||||||
|
for n in $(seq 1 "$how_many"); do
|
||||||
|
echo " var v$n: T$n"
|
||||||
|
done
|
||||||
|
echo " switch endianness {"
|
||||||
|
for endianness in .big .little; do
|
||||||
|
echo " case $endianness:"
|
||||||
|
for n in $(seq 1 "$how_many"); do
|
||||||
|
echo " v$n = value$n${endianness}Endian"
|
||||||
|
done
|
||||||
|
done
|
||||||
|
echo " }"
|
||||||
|
echo
|
||||||
|
echo " var spaceNeeded: Int = MemoryLayout<T1>.size"
|
||||||
|
for n in $(seq 2 "$how_many"); do
|
||||||
|
echo " spaceNeeded &+= MemoryLayout<T$n>.size"
|
||||||
|
done
|
||||||
|
echo
|
||||||
|
echo " return self.writeWithUnsafeMutableBytes(minimumWritableBytes: spaceNeeded) { ptr -> Int in"
|
||||||
|
echo " assert(ptr.count >= spaceNeeded)"
|
||||||
|
echo " var offset = 0"
|
||||||
|
echo " let basePtr = ptr.baseAddress! // safe: pointer is non zero length"
|
||||||
|
for n in $(seq 1 "$how_many"); do
|
||||||
|
echo " (basePtr + offset).copyMemory(from: &v$n, byteCount: MemoryLayout<T$n>.size)"
|
||||||
|
echo " offset = offset &+ MemoryLayout<T$n>.size"
|
||||||
|
done
|
||||||
|
echo " assert(offset == spaceNeeded)"
|
||||||
|
echo " return offset"
|
||||||
|
echo " }"
|
||||||
|
echo " }"
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
grep -q "ByteBuffer" "${BASH_SOURCE[0]}" || {
|
||||||
|
echo >&2 "ERROR: ${BASH_SOURCE[0]}: file or directory not found (this should be this script)"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
cat <<"EOF"
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// This source file is part of the SwiftNIO open source project
|
||||||
|
//
|
||||||
|
// Copyright (c) 2021 Apple Inc. and the SwiftNIO project authors
|
||||||
|
// Licensed under Apache License v2.0
|
||||||
|
//
|
||||||
|
// See LICENSE.txt for license information
|
||||||
|
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
/// NOTE: THIS FILE IS AUTO-GENERATED BY dev/generate-bytebuffer-multi-int.sh
|
||||||
|
EOF
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "extension ByteBuffer {"
|
||||||
|
|
||||||
|
# note:
|
||||||
|
# - widening the inverval below (eg. going from {2..15} to {2..25}) is Semver minor
|
||||||
|
# - narrowing the interval below is SemVer _MAJOR_!
|
||||||
|
for n in {2..15}; do
|
||||||
|
gen "$n"
|
||||||
|
done
|
||||||
|
echo "}"
|
||||||
|
} > "$here/../Sources/NIOCore/ByteBuffer-multi-int.swift"
|
Loading…
Reference in New Issue