Do not use @inline(__always)

Use @inlinable instead, or let the compiler be smart.
Also make more public things @inlinable for speedz.
This commit is contained in:
Helge Heß 2021-03-08 16:27:49 +01:00
parent d1119047d0
commit ad70fc06ca
No known key found for this signature in database
GPG Key ID: 0A3825768D88C07D
6 changed files with 87 additions and 88 deletions

View File

@ -1,6 +1,5 @@
# SwiftNIO Redis # SwiftNIO Redis
![Swift4](https://img.shields.io/badge/swift-4-blue.svg)
![Swift5](https://img.shields.io/badge/swift-5-blue.svg) ![Swift5](https://img.shields.io/badge/swift-5-blue.svg)
![macOS](https://img.shields.io/badge/os-macOS-green.svg?style=flat) ![macOS](https://img.shields.io/badge/os-macOS-green.svg?style=flat)
![tuxOS](https://img.shields.io/badge/os-tuxOS-green.svg?style=flat) ![tuxOS](https://img.shields.io/badge/os-tuxOS-green.svg?style=flat)

View File

@ -133,7 +133,7 @@ open class RESPChannelHandler : ChannelDuplexHandler {
context.write(wrapOutboundOut(out), promise: promise) context.write(wrapOutboundOut(out), promise: promise)
} }
@inline(__always) @inlinable
final func encode<S: Collection>(simpleString bytes: S, final func encode<S: Collection>(simpleString bytes: S,
out: inout ByteBuffer) out: inout ByteBuffer)
where S.Element == UInt8 where S.Element == UInt8
@ -143,7 +143,7 @@ open class RESPChannelHandler : ChannelDuplexHandler {
out.writeBytes(eol) out.writeBytes(eol)
} }
@inline(__always) @inlinable
final func encode(simpleString bytes: ByteBuffer, out: inout ByteBuffer) { final func encode(simpleString bytes: ByteBuffer, out: inout ByteBuffer) {
var s = bytes var s = bytes
out.writeInteger(UInt8(43)) // + out.writeInteger(UInt8(43)) // +
@ -151,7 +151,7 @@ open class RESPChannelHandler : ChannelDuplexHandler {
out.writeBytes(eol) out.writeBytes(eol)
} }
@inline(__always) @inlinable
final func encode(bulkString bytes: ByteBuffer?, out: inout ByteBuffer) { final func encode(bulkString bytes: ByteBuffer?, out: inout ByteBuffer) {
if var s = bytes { if var s = bytes {
out.writeInteger(UInt8(36)) // $ out.writeInteger(UInt8(36)) // $
@ -165,7 +165,7 @@ open class RESPChannelHandler : ChannelDuplexHandler {
} }
} }
@inline(__always) @inlinable
final func encode<S: Collection>(bulkString bytes: S?, final func encode<S: Collection>(bulkString bytes: S?,
out: inout ByteBuffer) out: inout ByteBuffer)
where S.Element == UInt8 where S.Element == UInt8
@ -182,14 +182,14 @@ open class RESPChannelHandler : ChannelDuplexHandler {
} }
} }
@inline(__always) @inlinable
final func encode(integer i: Int, out: inout ByteBuffer) { final func encode(integer i: Int, out: inout ByteBuffer) {
out.writeInteger(UInt8(58)) // : out.writeInteger(UInt8(58)) // :
out.write(integerAsString : i) out.write(integerAsString : i)
out.writeBytes(eol) out.writeBytes(eol)
} }
@inline(__always) @inlinable
final func encode(error: RESPError, out: inout ByteBuffer) { final func encode(error: RESPError, out: inout ByteBuffer) {
out.writeInteger(UInt8(45)) // - out.writeInteger(UInt8(45)) // -
out.writeString(error.code) out.writeString(error.code)
@ -241,8 +241,10 @@ open class RESPChannelHandler : ChannelDuplexHandler {
} }
} }
private let eol : ContiguousArray<UInt8> = [ 13, 10 ] // \r\n @usableFromInline
private let nilString : ContiguousArray<UInt8> = [ 36, 45, 49, 13, 10 ] // $-1\r\n let eol : ContiguousArray<UInt8> = [ 13, 10 ] // \r\n
@usableFromInline
let nilString : ContiguousArray<UInt8> = [ 36, 45, 49, 13, 10 ] // $-1\r\n
private let nilArray : ContiguousArray<UInt8> = [ 42, 45, 49, 13, 10 ] // *-1\r\n private let nilArray : ContiguousArray<UInt8> = [ 42, 45, 49, 13, 10 ] // *-1\r\n
fileprivate enum ConstantBuffers { fileprivate enum ConstantBuffers {

View File

@ -2,7 +2,7 @@
// //
// This source file is part of the swift-nio-redis open source project // This source file is part of the swift-nio-redis open source project
// //
// Copyright (c) 2018 ZeeZide GmbH. and the swift-nio-redis project authors // Copyright (c) 2018-2021 ZeeZide GmbH. and the swift-nio-redis project authors
// Licensed under Apache License v2.0 // Licensed under Apache License v2.0
// //
// See LICENSE.txt for license information // See LICENSE.txt for license information
@ -18,68 +18,58 @@ import struct NIO.ByteBuffer
public protocol RESPEncodable { public protocol RESPEncodable {
func toRESPValue() -> RESPValue func toRESPValue() -> RESPValue
} }
extension RESPValue : RESPEncodable { extension RESPValue : RESPEncodable {
public func toRESPValue() -> RESPValue { @inlinable
return self public func toRESPValue() -> RESPValue { return self }
}
} }
extension RESPError : RESPEncodable { extension RESPError : RESPEncodable {
public func toRESPValue() -> RESPValue {
return .error(self)
}
@inlinable
public func toRESPValue() -> RESPValue { return .error(self) }
} }
extension Int : RESPEncodable { extension Int : RESPEncodable {
public func toRESPValue() -> RESPValue { @inlinable
return .integer(self) public func toRESPValue() -> RESPValue { return .integer(self) }
}
} }
extension Bool : RESPEncodable { extension Bool : RESPEncodable {
public func toRESPValue() -> RESPValue { @inlinable
return .integer(self ? 1 : 0) public func toRESPValue() -> RESPValue { return .integer(self ? 1 : 0) }
}
} }
extension String : RESPEncodable { extension String : RESPEncodable {
@inlinable
public func toRESPValue() -> RESPValue { public func toRESPValue() -> RESPValue {
return .bulkString(self.utf8.asByteBuffer) return .bulkString(self.utf8.asByteBuffer)
} }
} }
extension Data : RESPEncodable { extension Data : RESPEncodable {
@inlinable
public func toRESPValue() -> RESPValue { public func toRESPValue() -> RESPValue {
return .bulkString(self.asByteBuffer) return .bulkString(self.asByteBuffer)
} }
} }
extension ByteBuffer : RESPEncodable { extension ByteBuffer : RESPEncodable {
public func toRESPValue() -> RESPValue { @inlinable
return .bulkString(self) public func toRESPValue() -> RESPValue { return .bulkString(self) }
}
} }
extension Array where Element: RESPEncodable { extension Array where Element: RESPEncodable {
@inlinable
public func toRESPValue() -> RESPValue { public func toRESPValue() -> RESPValue {
let arrayOfRedisValues = self.map { $0.toRESPValue() } let arrayOfRedisValues = self.map { $0.toRESPValue() }
return .array(ContiguousArray(arrayOfRedisValues)) return .array(ContiguousArray(arrayOfRedisValues))
@ -89,6 +79,7 @@ extension Array where Element: RESPEncodable {
extension Array: RESPEncodable { extension Array: RESPEncodable {
@inlinable
public func toRESPValue() -> RESPValue { public func toRESPValue() -> RESPValue {
let array : [ RESPValue ] = self.map { v in let array : [ RESPValue ] = self.map { v in
if let rv = (v as? RESPEncodable) { if let rv = (v as? RESPEncodable) {

View File

@ -2,7 +2,7 @@
// //
// This source file is part of the swift-nio-redis open source project // This source file is part of the swift-nio-redis open source project
// //
// Copyright (c) 2018-2020 ZeeZide GmbH. and the swift-nio-redis project authors // Copyright (c) 2018-2021 ZeeZide GmbH. and the swift-nio-redis project authors
// Licensed under Apache License v2.0 // Licensed under Apache License v2.0
// //
// See LICENSE.txt for license information // See LICENSE.txt for license information
@ -35,7 +35,6 @@ public struct RESPParser {
let count = bp.count let count = bp.count
var i = 0 var i = 0
@inline(__always)
func doSkipNL() { func doSkipNL() {
if i >= count { if i >= count {
overflowSkipNL = true overflowSkipNL = true
@ -238,7 +237,6 @@ public struct RESPParser {
// MARK: - Parsing // MARK: - Parsing
@inline(__always)
private mutating func pushArrayContext(expectedCount: Int) { private mutating func pushArrayContext(expectedCount: Int) {
if ctxIndex == ctxCapacity { if ctxIndex == ctxCapacity {
for _ in 0..<4 { for _ in 0..<4 {
@ -252,7 +250,6 @@ public struct RESPParser {
arrayContextBuffer[ctxIndex].values.reserveCapacity(expectedCount) arrayContextBuffer[ctxIndex].values.reserveCapacity(expectedCount)
} }
@inline(__always)
private mutating func decoded(value: RESPValue, yield: Yield) { private mutating func decoded(value: RESPValue, yield: Yield) {
if ctxIndex < 0 { if ctxIndex < 0 {
return yield(value) return yield(value)
@ -313,11 +310,8 @@ public struct RESPParser {
values.reserveCapacity(expectedCount + 1) values.reserveCapacity(expectedCount + 1)
} }
var isDone : Bool { var isDone : Bool { return expectedCount <= values.count }
@inline(__always) get { return expectedCount <= values.count }
}
@inline(__always)
mutating func append(value v: RESPValue) -> Bool { mutating func append(value v: RESPValue) -> Bool {
assert(!isDone, "attempt to add to a context which is not TL or done") assert(!isDone, "attempt to add to a context which is not TL or done")
values.append(v) values.append(v)
@ -331,5 +325,4 @@ public struct RESPParser {
private var countValue = 0 private var countValue = 0
private var overflowSkipNL = false private var overflowSkipNL = false
private var overflowBuffer : ByteBuffer? private var overflowBuffer : ByteBuffer?
} }

View File

@ -2,7 +2,7 @@
// //
// This source file is part of the swift-nio-redis open source project // This source file is part of the swift-nio-redis open source project
// //
// Copyright (c) 2018-2020 ZeeZide GmbH. and the swift-nio-redis project authors // Copyright (c) 2018-2021 ZeeZide GmbH. and the swift-nio-redis project authors
// Licensed under Apache License v2.0 // Licensed under Apache License v2.0
// //
// See LICENSE.txt for license information // See LICENSE.txt for license information
@ -17,6 +17,7 @@ import class NIO.EventLoopFuture
public extension ChannelPipeline { public extension ChannelPipeline {
@inlinable
func configureRedisPipeline(first : Bool = false, func configureRedisPipeline(first : Bool = false,
name : String = "de.zeezide.nio.RESP") name : String = "de.zeezide.nio.RESP")
-> EventLoopFuture<Void> -> EventLoopFuture<Void>

View File

@ -49,14 +49,14 @@ public struct RESPError : Error, CustomStringConvertible {
// MARK: - Initializers // MARK: - Initializers
fileprivate let sharedAllocator = ByteBufferAllocator() @usableFromInline let sharedAllocator = ByteBufferAllocator()
public extension RESPValue { public extension RESPValue {
init(_ v: Int) { @inlinable
self = .integer(v) init(_ v: Int) { self = .integer(v) }
}
@inlinable
init(bulkString s: String?) { init(bulkString s: String?) {
if let s = s { if let s = s {
let utf8 = s.utf8 let utf8 = s.utf8
@ -68,12 +68,14 @@ public extension RESPValue {
self = .bulkString(nil) self = .bulkString(nil)
} }
} }
@inlinable
init(bulkString s: Data) { init(bulkString s: Data) {
var buffer = sharedAllocator.buffer(capacity: s.count) var buffer = sharedAllocator.buffer(capacity: s.count)
buffer.writeBytes(s) buffer.writeBytes(s)
self = .bulkString(buffer) self = .bulkString(buffer)
} }
@inlinable
init(bulkString s: Int) { init(bulkString s: Int) {
let s = String(s) let s = String(s)
let utf8 = s.utf8 let utf8 = s.utf8
@ -82,45 +84,48 @@ public extension RESPValue {
self = .bulkString(buffer) self = .bulkString(buffer)
} }
@inlinable
init(simpleString s: String) { init(simpleString s: String) {
self = .simpleString(s.utf8.asByteBuffer) self = .simpleString(s.utf8.asByteBuffer)
} }
@inlinable
init(errorCode code: String, message: String? = nil) { init(errorCode code: String, message: String? = nil) {
self = .error(RESPError(code: code, message: message ?? "Failed: \(code)")) self = .error(RESPError(code: code, message: message ?? "Failed: \(code)"))
} }
@inlinable
init<T: Sequence>(array: T) where T.Element == RESPValue { init<T: Sequence>(array: T) where T.Element == RESPValue {
self = .array(ContiguousArray(array)) self = .array(ContiguousArray(array))
} }
}
public extension RESPValue { // MARK: - Content Accessors
@inlinable
var byteBuffer : ByteBuffer? { var byteBuffer : ByteBuffer? {
@inline(__always) switch self {
get { case .simpleString(let cs), .bulkString(.some(let cs)): return cs
switch self { default: return nil
case .simpleString(let cs), .bulkString(.some(let cs)): return cs
default: return nil
}
} }
} }
@inlinable
var stringValue : String? { var stringValue : String? {
@inline(__always) switch self {
get { case .simpleString(let cs), .bulkString(.some(let cs)):
switch self { return cs.getString(at: cs.readerIndex, length: cs.readableBytes)
case .simpleString(let cs), .bulkString(.some(let cs)):
return cs.getString(at: cs.readerIndex, length: cs.readableBytes) case .integer(let i):
return String(i)
case .integer(let i):
return String(i) default: return nil
default: return nil
}
} }
} }
@inlinable
var dataValue : Data? { var dataValue : Data? {
@inline(__always)
get { get {
switch self { switch self {
case .simpleString(let cs), .bulkString(.some(let cs)): case .simpleString(let cs), .bulkString(.some(let cs)):
@ -131,12 +136,10 @@ public extension RESPValue {
} }
} }
var keyValue : Data? { @inlinable
@inline(__always) var keyValue : Data? { return self.dataValue }
get { return self.dataValue }
}
@inline(__always) @inlinable
func withKeyValue(_ cb: ( Data? ) throws -> Void) rethrows { func withKeyValue(_ cb: ( Data? ) throws -> Void) rethrows {
// SR-7378 // SR-7378
switch self { switch self {
@ -154,28 +157,27 @@ public extension RESPValue {
} }
} }
@inlinable
var intValue : Int? { var intValue : Int? {
@inline(__always) switch self {
get { case .integer(let i):
switch self { return i
case .integer(let i):
return i case .simpleString(let cs), .bulkString(.some(let cs)):
// PERF: inline atoi instead of constructing a string!
case .simpleString(let cs), .bulkString(.some(let cs)): guard let s = cs.getString(at: cs.readerIndex,
// PERF: inline atoi instead of constructing a string! length: cs.readableBytes) else {
guard let s = cs.getString(at: cs.readerIndex,
length: cs.readableBytes) else {
return nil
}
return Int(s)
default:
return nil return nil
} }
return Int(s)
default:
return nil
} }
} }
} }
@inlinable
public func ==(lhs: RESPValue, rhs: String) -> Bool { public func ==(lhs: RESPValue, rhs: String) -> Bool {
switch lhs { switch lhs {
case .simpleString, .bulkString: case .simpleString, .bulkString:
@ -191,6 +193,8 @@ public func ==(lhs: RESPValue, rhs: String) -> Bool {
// MARK: - Parse Literals // MARK: - Parse Literals
extension RESPValue : ExpressibleByIntegerLiteral { extension RESPValue : ExpressibleByIntegerLiteral {
@inlinable
public init(integerLiteral value: IntegerLiteralType) { public init(integerLiteral value: IntegerLiteralType) {
self = .integer(value) self = .integer(value)
} }
@ -199,6 +203,8 @@ extension RESPValue : ExpressibleByIntegerLiteral {
import NIOFoundationCompat import NIOFoundationCompat
extension Data { extension Data {
@usableFromInline
var asByteBuffer : ByteBuffer { var asByteBuffer : ByteBuffer {
var bb = sharedAllocator.buffer(capacity: count) var bb = sharedAllocator.buffer(capacity: count)
bb.writeBytes(self) bb.writeBytes(self)
@ -207,6 +213,8 @@ extension Data {
} }
extension String.UTF8View { extension String.UTF8View {
@usableFromInline
var asByteBuffer : ByteBuffer { var asByteBuffer : ByteBuffer {
var bb = sharedAllocator.buffer(capacity: count) var bb = sharedAllocator.buffer(capacity: count)
bb.writeBytes(self) bb.writeBytes(self)
@ -216,20 +224,23 @@ extension String.UTF8View {
extension RESPValue : ExpressibleByStringLiteral { extension RESPValue : ExpressibleByStringLiteral {
@inlinable
public init(stringLiteral value: String) { public init(stringLiteral value: String) {
self = .bulkString(value.utf8.asByteBuffer) self = .bulkString(value.utf8.asByteBuffer)
} }
@inlinable
public init(extendedGraphemeClusterLiteral value: StringLiteralType) { public init(extendedGraphemeClusterLiteral value: StringLiteralType) {
self = .bulkString(value.utf8.asByteBuffer) self = .bulkString(value.utf8.asByteBuffer)
} }
@inlinable
public init(unicodeScalarLiteral value: StringLiteralType) { public init(unicodeScalarLiteral value: StringLiteralType) {
self = .bulkString(value.utf8.asByteBuffer) self = .bulkString(value.utf8.asByteBuffer)
} }
} }
extension RESPValue : CustomStringConvertible { extension RESPValue : CustomStringConvertible {
@inlinable
public var description : String { public var description : String {
switch self { switch self {
case .simpleString(let cs): return stringValue ?? "\(cs)" case .simpleString(let cs): return stringValue ?? "\(cs)"
@ -249,12 +260,14 @@ extension RESPValue : CustomStringConvertible {
extension String { extension String {
// FIXME: we can probably do this in the buffer // FIXME: we can probably do this in the buffer
@inlinable
static func decode<I: Collection>(utf8 ba: I) -> String? static func decode<I: Collection>(utf8 ba: I) -> String?
where I.Iterator.Element == UInt8 where I.Iterator.Element == UInt8
{ {
return decode(units: ba, decoder: UTF8()) return decode(units: ba, decoder: UTF8())
} }
@inlinable
static func decode<Codec: UnicodeCodec, I: Collection> static func decode<Codec: UnicodeCodec, I: Collection>
(units b: I, decoder d: Codec) -> String? (units b: I, decoder d: Codec) -> String?
where I.Iterator.Element == Codec.CodeUnit where I.Iterator.Element == Codec.CodeUnit