Skip to content

Commit f82db8f

Browse files
committed
Added @inlinable to most functions (and computed properties).
Also added @inline(__always) to some, where they're particularly trivial (e.g. just aliases, in essence, for another function). Most of these functions probably aren't performance sensitive - though some are, so the benefit for them is most obvious - but even for those that aren't, being inlinable apparently allows the optimiser to make better decisions (like omitting redundant calls entirely) which could be an aid to reducing malloc activity.
1 parent fe880c6 commit f82db8f

File tree

10 files changed

+38
-2
lines changed

10 files changed

+38
-2
lines changed

Sources/FoundationExtensions/AsyncSequence.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ public extension AsyncSequence {
66
/// - terminator: A subsequence to look for, that will terminate collection. Should not be empty.
77
/// - stripTerminator: Whether to include the terminator in the returned collection.
88
/// - Returns: A collection of zero or more elements.
9+
@inlinable
910
func collect<C: RangeReplaceableCollection>(
1011
upTo terminator: some Collection<Element>,
1112
stripTerminator: Bool = true

Sources/FoundationExtensions/BidirectionalCollection.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public extension BidirectionalCollection {
99
///
1010
/// - Parameter transform: The transform to apply, returning a value if successful or nil otherwise. This _must_ have a single transition point (where it goes from returning values to returning nil, for increasingly long prefixes), else the result is undefined.
1111
/// - Returns: The result of a transformation closure on the longest prefix for which the transform succeeds, or nil if there is no [non-empty] prefix for which this is the case.
12+
@inlinable
1213
func longestPrefix<T>(where transform: (SubSequence) throws -> T?) rethrows -> T? {
1314
var lowerBound = self.startIndex
1415
var lowerBoundResult: T? = nil

Sources/FoundationExtensions/BinaryInteger.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ public extension BinaryInteger {
66
/// Returns the individual bits of the integer, split out into an array.
77
///
88
/// Not to be confused with ``bitIndices``, which is similar but the resulting array has the index of each bit that is set in the integer (`self`), not the value of that bit.
9+
@inlinable
910
var bits: [Self] {
1011
var remainder = self
1112
var result = [Self]()
@@ -24,6 +25,7 @@ public extension BinaryInteger {
2425
/// Returns the indices of each `1` bit of the integer.
2526
///
2627
/// Not to be confused with ``bits``, which is similar but the resulting array contains the component numbers themselves.
28+
@inlinable
2729
var bitIndices: IndexSet {
2830
var remainder = self
2931
var result = IndexSet()

Sources/FoundationExtensions/CollectionOfUInt8.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ public extension Collection where Element == UInt8 {
5858
/// An ASCII representation of the given collection's ``UInt8`` contents, in uppercase and without any spaces.
5959
///
6060
/// This is equivalent to calling ``asHexString(uppercase:delimiterEvery:delimiter:)`` with default arguments. It is provided as a convenience so that the parentheses may be omitted.
61+
@inlinable
62+
@inline(__always)
6163
var asHexString: String {
6264
asHexString()
6365
}

Sources/FoundationExtensions/Comparable.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ extension Comparable {
44
/// Conforms the value to the given range.
55
///
66
/// i.e. if it is below the range's lower bound, it is set to that lower bound. Otherwise it is not modified.
7+
@inlinable
78
mutating func clamp(_ range: PartialRangeFrom<Self>) {
89
if self < range.lowerBound {
910
self = range.lowerBound
@@ -13,6 +14,7 @@ extension Comparable {
1314
/// Returns the value conformed to the given range.
1415
///
1516
/// i.e. if it is below the range's lower bound, that lower bound is returned instead. Otherwise it is returned as-is.
17+
@inlinable
1618
func clamped(_ range: PartialRangeFrom<Self>) -> Self {
1719
if self < range.lowerBound {
1820
range.lowerBound
@@ -24,6 +26,7 @@ extension Comparable {
2426
/// Conforms the value to the given range.
2527
///
2628
/// i.e. if it is above the range's upper bound, it is set to that upper bound. Otherwise it is not modified.
29+
@inlinable
2730
mutating func clamp(_ range: PartialRangeThrough<Self>) {
2831
if self > range.upperBound {
2932
self = range.upperBound
@@ -33,6 +36,7 @@ extension Comparable {
3336
/// Returns the value conformed to the given range.
3437
///
3538
/// i.e. if it is above the range's upper bound, that upper bound is returned instead. Otherwise it is returned as-is.
39+
@inlinable
3640
func clamped(_ range: PartialRangeThrough<Self>) -> Self {
3741
if self > range.upperBound {
3842
range.upperBound
@@ -48,6 +52,7 @@ extension Comparable {
4852
/// If it is above the range's upper bound, it is set to that upper bound.
4953
///
5054
/// Otherwise it is not modified.
55+
@inlinable
5156
mutating func clamp(_ range: ClosedRange<Self>) {
5257
if self < range.lowerBound {
5358
self = range.lowerBound
@@ -63,6 +68,7 @@ extension Comparable {
6368
/// If it is above the range's upper bound, that upper bound is returned instead.
6469
///
6570
/// Otherwise it is returned as-is.
71+
@inlinable
6672
func clamped(_ range: ClosedRange<Self>) -> Self {
6773
if self < range.lowerBound {
6874
range.lowerBound
@@ -82,6 +88,7 @@ extension Comparable where Self: Strideable {
8288
/// If it is above the range's upper bound, it is set to that upper bound.
8389
///
8490
/// Otherwise it is not modified.
91+
@inlinable
8592
mutating func clamp(_ range: Range<Self>) {
8693
if self < range.lowerBound {
8794
self = range.lowerBound
@@ -97,6 +104,7 @@ extension Comparable where Self: Strideable {
97104
/// If it is above the range's upper bound, that upper bound is returned instead.
98105
///
99106
/// Otherwise it is returned as-is.
107+
@inlinable
100108
func clamped(_ range: Range<Self>) -> Self {
101109
if self < range.lowerBound {
102110
range.lowerBound
@@ -110,6 +118,7 @@ extension Comparable where Self: Strideable {
110118
/// Conforms the value to the given range.
111119
///
112120
/// i.e. if it is above the range's upper bound, it is set to that upper bound. Otherwise it is not modified.
121+
@inlinable
113122
mutating func clamp(_ range: PartialRangeUpTo<Self>) {
114123
if self >= range.upperBound {
115124
self = range.upperBound.advanced(by: -1)
@@ -119,6 +128,7 @@ extension Comparable where Self: Strideable {
119128
/// Returns the value conformed to the given range.
120129
///
121130
/// i.e. if it is above the range's upper bound, that upper bound is returned instead. Otherwise it is returned as-is.
131+
@inlinable
122132
func clamped(_ range: PartialRangeUpTo<Self>) -> Self {
123133
if self >= range.upperBound {
124134
range.upperBound.advanced(by: -1)

Sources/FoundationExtensions/Data.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,15 @@ public extension Data {
77
/// A convenience wrapper over ``String(data:encoding:)``, to make it usable with optional chaining.
88
/// - Parameter encoding: The encoding method that the data should be compliant with.
99
/// - Returns: The decoded string, or nil if the data is not compliant with the given string encoding.
10+
@inlinable
11+
@inline(__always)
1012
func asString(encoding: String.Encoding) -> String? {
1113
String(data: self, encoding: encoding)
1214
}
1315

1416
// The data as a valid UTF-8 string, or nil if the data is not a valid UTF-8 string.
17+
@inlinable
18+
@inline(__always)
1519
var asString: String? {
1620
asString(encoding: .utf8)
1721
}

Sources/FoundationExtensions/Date.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
import Foundation
55

66
public extension Date {
7-
private static let relativeDateTimeFormatter = {
7+
@usableFromInline
8+
internal static let relativeDateTimeFormatter = {
89
var formatter = RelativeDateTimeFormatter()
910
formatter.dateTimeStyle = .named
1011
formatter.unitsStyle = .full
@@ -15,6 +16,7 @@ public extension Date {
1516
/// Returns a human-readable, localised description of how long ago the date was, e.g. "2 hours ago".
1617
///
1718
/// The description may be approximate, typically limited to only the first significant date & time component (e.g. just "2 hours ago" for deltas ranging from 1.5 to 2.5 hours ago).
19+
@inlinable
1820
var timeAgo: String {
1921
Date.relativeDateTimeFormatter.localizedString(for: self, relativeTo: Date.now)
2022
}

Sources/FoundationExtensions/IteratorProtocol.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@ public extension IteratorProtocol {
44
/// Returns a type-erased version of the iterator (an `AnyIterator`).
55
///
66
/// This is a 'convenience' property to make `AnyIterator` more accessible, such as when using optional chaining.
7+
@inlinable
8+
@inline(__always)
79
var typeErased: AnyIterator<Element> {
810
AnyIterator(self)
911
}
1012

1113
/// Returns an async iterator wrapper over the iterator.
1214
///
1315
/// Be careful in how you use this - Swift Concurrency contexts (async functions, inside Tasks, etc) basically do not support blocking code (their performance suffers, and it can lead to deadlock). You should only use this for iterators that do not block (i.e. do not do any I/O, do not take any locks, etc), such as simple enumeration of `Array`s and the like.
16+
@inlinable
17+
@inline(__always)
1418
var async: AsyncIteratorOverSyncIterator<Self> {
1519
AsyncIteratorOverSyncIterator(self)
1620
}
@@ -22,12 +26,17 @@ public extension IteratorProtocol {
2226
public struct AsyncIteratorOverSyncIterator<I: IteratorProtocol>: AsyncIteratorProtocol {
2327
public typealias Element = I.Element
2428

25-
private var source: I
29+
@usableFromInline
30+
internal var source: I
2631

32+
@inlinable
33+
@inline(__always)
2734
public mutating func next() async -> I.Element? {
2835
source.next()
2936
}
3037

38+
@inlinable
39+
@inline(__always)
3140
public init(_ source: I) {
3241
self.source = source
3342
}

Sources/FoundationExtensions/Locale.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import Foundation
55

66
public extension Locale {
77
/// The POSIX locale (en\_US\_POSIX).
8+
@inlinable
9+
@inline(__always)
810
static var POSIX: Locale {
911
Locale(identifier: "en_US_POSIX")
1012
}

Sources/FoundationExtensions/Optional.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import Foundation
55

66
public extension Optional {
77
/// Returns the description (from ``String(describing:)``) of the value if it is non-nil, else the string "nil".
8+
@inlinable
89
var orNilString: String {
910
if let value = self {
1011
return String(describing: value)
@@ -16,6 +17,8 @@ public extension Optional {
1617

1718
public extension Optional where Wrapped == String {
1819
/// Returns the string if it is non-nil, else the string "nil".
20+
@inlinable
21+
@inline(__always)
1922
var orNilString: String {
2023
if let self {
2124
return self

0 commit comments

Comments
 (0)