Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make most of the API @inlinable #43

Merged
merged 2 commits into from
Mar 25, 2020
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
## [Unreleased]
### Added
- New `DivisibleArithmetic` protocol which easily extends `average()` to Collections of `Double`, `Float` and `CGFloat`.
- Make most of the API `@inlinable` for increased real-time performance.
### Changed
- None.
### Deprecated
Expand Down
9 changes: 8 additions & 1 deletion Sources/HandySwift/Extensions/ArrayExt.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ extension Array {
/// - Parameters:
/// - other: Other array to combine the elements with.
/// - Returns: An array of tuples with the elements of both arrays combined.
@inlinable
public func combinations<T>(with other: [T]) -> [Combination<T>] {
var combinations = [(Element, T)]()
forEach { elem in other.forEach { otherElem in combinations.append((elem, otherElem)) } }
Expand All @@ -27,6 +28,7 @@ extension Array {
/// - Parameters:
/// - stable: Speifies if the sorting algorithm should be stable.
/// - areInIncreasingOrder: The closure to specify the order of the elements to be sorted by.
@inlinable
public mutating func sort(by areInIncreasingOrder: @escaping (Element, Element) -> Bool, stable: Bool) {
guard stable else { sort(by: areInIncreasingOrder); return }
stableMergeSort(by: areInIncreasingOrder)
Expand All @@ -39,6 +41,7 @@ extension Array {
/// - Parameters:
/// - stable: Speifies if the sorting algorithm should be stable.
/// - areInIncreasingOrder: The closure to specify the order of the elements to be sorted by.
@inlinable
public func sorted(by areInIncreasingOrder: @escaping (Element, Element) -> Bool, stable: Bool) -> [Element] {
guard stable else { return sorted(by: areInIncreasingOrder) }

Expand All @@ -49,6 +52,7 @@ extension Array {
}

/// Sorts the array in-place using a stable merge sort algorithm.
@inlinable
mutating func stableMergeSort(by areInIncreasingOrder: @escaping (Element, Element) -> Bool) {
var tmp = [Element]()
tmp.reserveCapacity(numericCast(count))
Expand Down Expand Up @@ -91,7 +95,7 @@ extension RandomAccessCollection where Index == Int {
/// Returns a random element from the `Array`.
///
/// - Returns: A random element from the array or `nil` if empty.
public var sample: Element? {
@inlinable public var sample: Element? {
guard let randomIndex = Int(randomBelow: count) else { return nil }
return self[randomIndex]
}
Expand All @@ -101,6 +105,7 @@ extension RandomAccessCollection where Index == Int {
/// - Parameters:
/// - size: The number of random elements wanted.
/// - Returns: An array with the given number of random elements or `nil` if empty.
@inlinable
public func sample(size: Int) -> [Element]? {
guard !isEmpty else { return nil }

Expand All @@ -118,6 +123,7 @@ extension Array where Element: Comparable {
///
/// - Parameters:
/// - stable: Speifies if the sorting algorithm should be stable.
@inlinable
public mutating func sort(stable: Bool) {
sort(by: { lhs, rhs in lhs < rhs }, stable: stable)
}
Expand All @@ -128,6 +134,7 @@ extension Array where Element: Comparable {
///
/// - Parameters:
/// - stable: Speifies if the sorting algorithm should be stable.
@inlinable
public func sorted(stable: Bool) -> [Element] {
sorted(by: { lhs, rhs in lhs < rhs }, stable: stable)
}
Expand Down
4 changes: 4 additions & 0 deletions Sources/HandySwift/Extensions/CollectionExt.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,31 @@ extension Collection {
///
/// - Parameters:
/// - try: The index of the element.
@inlinable
public subscript(try index: Index) -> Element? {
indices.contains(index) ? self[index] : nil
}
}

extension Sequence where Element: Numeric {
/// Returns the sum of all elements.
@inlinable
public func sum() -> Element {
reduce(0, +)
}
}

extension Collection where Element: DivisibleArithmetic {
/// Returns the average of all elements.
@inlinable
public func average() -> Element {
sum() / Element(count)
}
}

extension Collection where Element == Int {
/// Returns the average of all elements as a Double value.
@inlinable
public func average<ReturnType: DivisibleArithmetic>() -> ReturnType {
ReturnType(sum()) / ReturnType(count)
}
Expand Down
6 changes: 6 additions & 0 deletions Sources/HandySwift/Extensions/ComparableExt.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ extension Comparable {
/// - `self`, if it is inside the given limits.
/// - `lowerBound` of the given limits, if `self` is smaller than it.
/// - `upperBound` of the given limits, if `self` is greater than it.
@inlinable
public func clamped(to limits: ClosedRange<Self>) -> Self {
if limits.lowerBound > self {
return limits.lowerBound
Expand All @@ -27,6 +28,7 @@ extension Comparable {
/// - Returns:
/// - `self`, if it is inside the given limits.
/// - `lowerBound` of the given limits, if `self` is smaller than it.
@inlinable
public func clamped(to limits: PartialRangeFrom<Self>) -> Self {
if limits.lowerBound > self {
return limits.lowerBound
Expand All @@ -41,6 +43,7 @@ extension Comparable {
/// - Returns:
/// - `self`, if it is inside the given limits.
/// - `upperBound` of the given limits, if `self` is greater than it.
@inlinable
public func clamped(to limits: PartialRangeThrough<Self>) -> Self {
if limits.upperBound < self {
return limits.upperBound
Expand All @@ -57,6 +60,7 @@ extension Comparable {
/// - `upperBound` of the given limits, if `self` is greater than it.
///
/// - Parameter limits: The closed range determining minimum & maxmimum value.
@inlinable
public mutating func clamp(to limits: ClosedRange<Self>) {
self = clamped(to: limits)
}
Expand All @@ -67,6 +71,7 @@ extension Comparable {
/// - `lowerBound` of the given limits, if `self` is smaller than it.
///
/// - Parameter limits: The partial range (from) determining the minimum value.
@inlinable
public mutating func clamp(to limits: PartialRangeFrom<Self>) {
self = clamped(to: limits)
}
Expand All @@ -77,6 +82,7 @@ extension Comparable {
/// - `upperBound` of the given limits, if `self` is greater than it.
///
/// - Parameter limits: The partial range (through) determining the maximum value.
@inlinable
public mutating func clamp(to limits: PartialRangeThrough<Self>) {
self = clamped(to: limits)
}
Expand Down
3 changes: 3 additions & 0 deletions Sources/HandySwift/Extensions/DictionaryExt.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ extension Dictionary {
/// - Parameters:
/// - keys: The `Array` of keys.
/// - values: The `Array` of values.
@inlinable
public init?(keys: [Key], values: [Value]) {
guard keys.count == values.count else { return nil }
self.init()
Expand All @@ -18,6 +19,7 @@ extension Dictionary {
///
/// - Parameters:
/// - otherDictionary: The other `Dictionary` to merge into this `Dictionary`.
@inlinable
public mutating func merge(_ other: [Key: Value]) {
for (key, value) in other { self[key] = value }
}
Expand All @@ -28,6 +30,7 @@ extension Dictionary {
/// - Parameters:
/// - otherDictionary: The other `Dictionary` to merge into this `Dictionary`.
/// - Returns: The new Dictionary with merged keys and values from this and the other `Dictionary`.
@inlinable
public func merged(with other: [Key: Value]) -> [Key: Value] {
var newDict: [Key: Value] = [:]
[self, other].forEach { dict in for (key, value) in dict { newDict[key] = value } }
Expand Down
2 changes: 2 additions & 0 deletions Sources/HandySwift/Extensions/IntExt.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ extension Int {
///
/// - Parameters:
/// - closure: The code to be run multiple times.
@inlinable
public func times(_ closure: () -> Void) {
guard self > 0 else { return }
for _ in 0 ..< self { closure() }
Expand All @@ -26,6 +27,7 @@ extension Int {
///
/// - Parameters:
/// - closure: The code to deliver a return value multiple times.
@inlinable
public func timesMake<ReturnType>(_ closure: () -> ReturnType) -> [ReturnType] {
guard self > 0 else { return [] }
return (0 ..< self).map { _ in closure() }
Expand Down
1 change: 1 addition & 0 deletions Sources/HandySwift/Extensions/StringExt.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ extension String {
/// - Parameters:
/// - size: The number of random characters wanted.
/// - Returns: A String with the given number of random characters or `nil` if empty.
@inlinable
public func sample(size: Int) -> String? {
guard !isEmpty else { return nil }

Expand Down
33 changes: 20 additions & 13 deletions Sources/HandySwift/Extensions/TimeIntervalExt.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,81 +7,88 @@ public typealias Timespan = TimeInterval

extension TimeInterval {
// MARK: - Computed Type Properties
internal static var secondsPerDay: Double { 24 * 60 * 60 }
internal static var secondsPerHour: Double { 60 * 60 }
internal static var secondsPerMinute: Double { 60 }
internal static var millisecondsPerSecond: Double { 1_000 }
internal static var microsecondsPerSecond: Double { 1_000 * 1_000 }
internal static var nanosecondsPerSecond: Double { 1_000 * 1_000 * 1_000 }
@usableFromInline internal static var secondsPerDay: Double { 24 * 60 * 60 }
@usableFromInline internal static var secondsPerHour: Double { 60 * 60 }
@usableFromInline internal static var secondsPerMinute: Double { 60 }
@usableFromInline internal static var millisecondsPerSecond: Double { 1_000 }
@usableFromInline internal static var microsecondsPerSecond: Double { 1_000 * 1_000 }
@usableFromInline internal static var nanosecondsPerSecond: Double { 1_000 * 1_000 * 1_000 }

// MARK: - Computed Instance Properties
/// - Returns: The `TimeInterval` in days.
public var days: Double {
@inlinable public var days: Double {
self / TimeInterval.secondsPerDay
}

/// - Returns: The `TimeInterval` in hours.
public var hours: Double {
@inlinable public var hours: Double {
self / TimeInterval.secondsPerHour
}

/// - Returns: The `TimeInterval` in minutes.
public var minutes: Double {
@inlinable public var minutes: Double {
self / TimeInterval.secondsPerMinute
}

/// - Returns: The `TimeInterval` in seconds.
public var seconds: Double {
@inlinable public var seconds: Double {
self
}

/// - Returns: The `TimeInterval` in milliseconds.
public var milliseconds: Double {
@inlinable public var milliseconds: Double {
self * TimeInterval.millisecondsPerSecond
}

/// - Returns: The `TimeInterval` in microseconds.
public var microseconds: Double {
@inlinable public var microseconds: Double {
self * TimeInterval.microsecondsPerSecond
}

/// - Returns: The `TimeInterval` in nanoseconds.
public var nanoseconds: Double {
@inlinable public var nanoseconds: Double {
self * TimeInterval.nanosecondsPerSecond
}

// MARK: - Type Methods
/// - Returns: The time in days using the `TimeInterval` type.
@inlinable
public static func days(_ value: Double) -> TimeInterval {
value * secondsPerDay
}

/// - Returns: The time in hours using the `TimeInterval` type.
@inlinable
public static func hours(_ value: Double) -> TimeInterval {
value * secondsPerHour
}

/// - Returns: The time in minutes using the `TimeInterval` type.
@inlinable
public static func minutes(_ value: Double) -> TimeInterval {
value * secondsPerMinute
}

/// - Returns: The time in seconds using the `TimeInterval` type.
@inlinable
public static func seconds(_ value: Double) -> TimeInterval {
value
}

/// - Returns: The time in milliseconds using the `TimeInterval` type.
@inlinable
public static func milliseconds(_ value: Double) -> TimeInterval {
value / millisecondsPerSecond
}

/// - Returns: The time in microseconds using the `TimeInterval` type.
@inlinable
public static func microseconds(_ value: Double) -> TimeInterval {
value / microsecondsPerSecond
}

/// - Returns: The time in nanoseconds using the `TimeInterval` type.
@inlinable
public static func nanoseconds(_ value: Double) -> TimeInterval {
value / nanosecondsPerSecond
}
Expand Down
2 changes: 2 additions & 0 deletions Sources/HandySwift/Protocols/Withable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ public protocol Withable {

extension Withable {
/// Construct a new instance, setting an arbitrary subset of properties.
@inlinable
public init(with config: (inout Self) -> Void) {
self.init()
config(&self)
}

/// Create a copy, overriding an arbitrary subset of properties.
@inlinable
public func with(_ config: (inout Self) -> Void) -> Self {
var copy = self
config(&copy)
Expand Down
9 changes: 6 additions & 3 deletions Sources/HandySwift/Structs/FrequencyTable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,26 @@ import Foundation
/// Data structure to retrieve random values with their frequency taken into account.
public struct FrequencyTable<T> {
// MARK: - Sub Types
@usableFromInline
typealias Entry = (value: T, frequency: Int)

// MARK: - Stored Instance Properties
private let valuesWithFrequencies: [Entry]
@usableFromInline internal let valuesWithFrequencies: [Entry]

/// Contains all values the amount of time of their frequencies.
private let frequentValues: [T]
@usableFromInline internal let frequentValues: [T]

// MARK: - Computed Instance Properties
/// - Returns: A random value taking frequencies into account or nil if values empty.
public var sample: T? { frequentValues.sample }
@inlinable public var sample: T? { frequentValues.sample }

// MARK: - Initializers
/// Creates a new FrequencyTable instance with values and their frequencies provided.
///
/// - Parameters:
/// - values: An array full of values to be saved into the frequency table.
/// - frequencyClosure: The closure to specify the frequency for a specific value.
@inlinable
public init(values: [T], frequencyClosure: (T) -> Int) {
valuesWithFrequencies = values.map { ($0, frequencyClosure($0)) }
frequentValues = valuesWithFrequencies.reduce(into: []) { memo, entry in
Expand All @@ -37,6 +39,7 @@ public struct FrequencyTable<T> {
/// - size: The size of the resulting array of random values.
///
/// - Returns: An array of random values or nil if values empty.
@inlinable
public func sample(size: Int) -> [T]? {
guard size > 0 && !frequentValues.isEmpty else { return nil }
return Array(0 ..< size).map { _ in sample! }
Expand Down
Loading