Skip to content

Commit

Permalink
Improve the performance of sum
Browse files Browse the repository at this point in the history
Motivation:

`sum(where:)` defined its complexity of O(n) while the implementation was O(2n). An implementation is possible to do the filtering inlined.

In addition, all overloads of `sum` should be inlinable to provide the compiler the most opportunity to optimize these style of calculations.

Modifications:

- Add `@inlinable` attributes to both overloads of `sum`
- Update `sum(where:)` to assert the `isIncluded` predicate and calculating the sum in a single traversal

Result:

Calculating a sum of currencies that pass a filter predicate should be twice as fast.
  • Loading branch information
Mordil committed Jan 21, 2020
1 parent 46f75f0 commit 71285fe
Showing 1 changed file with 10 additions and 5 deletions.
15 changes: 10 additions & 5 deletions Sources/Currency/AnyCurrency+Sequence.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ extension Sequence where Element: AnyCurrency {
/// If the sequence has no elements, you will receive a currency with a value of "0".
/// - Complexity: O(*n*) , where *n* is the length of the sequence.
/// - Returns: A currency value representing the sum total of all the amounts in the sequence.
@inlinable
public func sum() -> Element {
return self.reduce(into: .init(.zero), { $0 += $1 })
}
Expand All @@ -35,15 +36,19 @@ extension Sequence where Element: AnyCurrency {
/// For example:
///
/// let amounts: [USD] = [304.98, 19.02, 30.21]
/// let sumTotal = amounts.sum(where: { $0.roundedAmount > 20 })
/// let sumTotal = amounts.sum(where: { $0.amount > 20 })
/// print(sumTotal)
/// // prints "335.19"
///
/// - Complexity: O(*n*), where *n* is the length of the sequence.
/// - Parameter predicate: A closure that takes a currency element as its argument
/// - Parameter isIncluded: A closure that takes a currency element as its argument
/// and returns a Boolean value that indicates whether the passed element should be included in the sum.
/// - Returns:A currency value representing the sum total of all the amounts in the sequence that satisfies `predicate`.
public func sum(where predicate: (Element) throws -> Bool) rethrows -> Element {
return try self.filter(predicate).sum()
/// - Returns: A currency value representing the sum total of all the amounts `isIncluded` allowed.
@inlinable
public func sum(where isIncluded: (Element) throws -> Bool) rethrows -> Element {
return try self.reduce(into: Element(0)) { result, next in
guard try isIncluded(next) else { return }
result += next
}
}
}

0 comments on commit 71285fe

Please sign in to comment.