diff --git a/Sources/OTCore/Abstractions/Collection Set-Like Methods.swift b/Sources/OTCore/Abstractions/Collection Set-Like Methods.swift index fc6a088..b1be7f6 100644 --- a/Sources/OTCore/Abstractions/Collection Set-Like Methods.swift +++ b/Sources/OTCore/Abstractions/Collection Set-Like Methods.swift @@ -35,12 +35,12 @@ extension Collection where Self: RangeReplaceableCollection, func insert(_ element: Element, position: CollectionPosition = .default) { - if !self.contains(element) { + if !contains(element) { switch position { case .start: - self.insert(element, at: startIndex) + insert(element, at: startIndex) case .end, .default: - self.append(element) + append(element) } } @@ -52,23 +52,23 @@ extension Collection where Self: RangeReplaceableCollection, @inlinable public mutating func update(with newMember: Element, position: CollectionPosition = .default) { - if let index = self.firstIndex(of: newMember) { + if let index = firstIndex(of: newMember) { switch position { case .default: self[index] = newMember case .start: - self.remove(at: index) - self.insert(newMember, at: startIndex) + remove(at: index) + insert(newMember, at: startIndex) case .end: - self.remove(at: index) - self.append(newMember) + remove(at: index) + append(newMember) } } else { switch position { case .start: - self.insert(newMember, at: startIndex) + insert(newMember, at: startIndex) case .end, .default: - self.append(newMember) + append(newMember) } } @@ -78,7 +78,7 @@ extension Collection where Self: RangeReplaceableCollection, /// Similar behavior to a Set, but removes all instances of the element. @inlinable public mutating func removeAll(_ member: Element) { - self.removeAll(where: { $0 == member }) + removeAll(where: { $0 == member }) } @@ -101,8 +101,8 @@ extension Collection where Self: RangeReplaceableCollection, @inlinable public mutating func formUnion(_ other: S) where Element == S.Element, S : Sequence { other.forEach { - if !self.contains($0) { - self.append($0) + if !contains($0) { + append($0) } } @@ -125,7 +125,7 @@ extension Collection where Self: RangeReplaceableCollection, @inlinable public mutating func formUnion(updating other: S) where Element == S.Element, S : Sequence { other.forEach { - self.update(with: $0) + update(with: $0) } } diff --git a/Sources/OTCore/Abstractions/String Title Case.swift b/Sources/OTCore/Abstractions/String Title Case.swift index 2325261..8384058 100644 --- a/Sources/OTCore/Abstractions/String Title Case.swift +++ b/Sources/OTCore/Abstractions/String Title Case.swift @@ -33,7 +33,7 @@ extension String { public var titleCased: String { var words = - self.localizedCapitalized + localizedCapitalized .split(separator: " ") .map({ String($0) }) diff --git a/Sources/OTCore/Abstractions/String Wrapped.swift b/Sources/OTCore/Abstractions/String Wrapped.swift index 08d280a..6020d5c 100644 --- a/Sources/OTCore/Abstractions/String Wrapped.swift +++ b/Sources/OTCore/Abstractions/String Wrapped.swift @@ -57,7 +57,7 @@ extension String { /// Same as `self.wrapped(with: .parentheses)` @inlinable public var parens: Self { - self.wrapped(with: .parentheses) + wrapped(with: .parentheses) } @@ -66,7 +66,7 @@ extension String { /// Same as `self.wrapped(with: .singleQuotes)` @inlinable public var singleQuoted: Self { - self.wrapped(with: .singleQuotes) + wrapped(with: .singleQuotes) } @@ -75,7 +75,7 @@ extension String { /// Same as `self.wrapped(with: .quotes)` @inlinable public var quoted: Self { - self.wrapped(with: .quotes) + wrapped(with: .quotes) } diff --git a/Sources/OTCore/Extensions/AppKit/URL and AppKit.swift b/Sources/OTCore/Extensions/AppKit/URL and AppKit.swift index 5313b1d..25d41d9 100644 --- a/Sources/OTCore/Extensions/AppKit/URL and AppKit.swift +++ b/Sources/OTCore/Extensions/AppKit/URL and AppKit.swift @@ -19,7 +19,7 @@ extension URL { guard isFileURL, fileExists else { return nil } - return NSWorkspace.shared.icon(forFile: self.path) + return NSWorkspace.shared.icon(forFile: path) } diff --git a/Sources/OTCore/Extensions/CoreGraphics/CGPoint.swift b/Sources/OTCore/Extensions/CoreGraphics/CGPoint.swift index 8af55cc..5b6bd6f 100644 --- a/Sources/OTCore/Extensions/CoreGraphics/CGPoint.swift +++ b/Sources/OTCore/Extensions/CoreGraphics/CGPoint.swift @@ -53,7 +53,7 @@ extension CGPoint { /// Returns the distance between two coordinate points. @inlinable public func distance(to other: CGPoint) -> CGFloat { - hypot(other.x - self.x, other.y - self.y) + hypot(other.x - x, other.y - y) } @@ -65,7 +65,7 @@ extension CGPoint { /// To calculate the where cardinal North is the origin (0°), use `cardinalAngle(to:)` instead. @inlinable public func angle(to other: CGPoint) -> CGFloat { - let calc = atan2(other.y - self.y, other.x - self.x).radiansToDegrees + let calc = atan2(other.y - y, other.x - x).radiansToDegrees if calc < 0 { return calc + 360.0 diff --git a/Sources/OTCore/Extensions/Darwin/FloatingPoint and Darwin.swift b/Sources/OTCore/Extensions/Darwin/FloatingPoint and Darwin.swift index 5593c91..d9f6289 100644 --- a/Sources/OTCore/Extensions/Darwin/FloatingPoint and Darwin.swift +++ b/Sources/OTCore/Extensions/Darwin/FloatingPoint and Darwin.swift @@ -88,14 +88,14 @@ extension FloatingPoint where Self : FloatingPointPowerComputable { /// If `decimalPlaces` <= 0, then `trunc(self)` is returned. public mutating func truncate(decimalPlaces: Int) { - self = self.truncated(decimalPlaces: decimalPlaces) + self = truncated(decimalPlaces: decimalPlaces) } /// **OTCore:** /// Truncates decimal places to `decimalPlaces` number of decimal places. /// - /// If `decimalPlaces` <= 0, then trunc(self) is returned. + /// If `decimalPlaces` <= 0, then `trunc(self)` is returned. public func truncated(decimalPlaces: Int) -> Self { if decimalPlaces < 1 { diff --git a/Sources/OTCore/Extensions/Foundation/Data.swift b/Sources/OTCore/Extensions/Foundation/Data.swift index a45b05c..3199997 100644 --- a/Sources/OTCore/Extensions/Foundation/Data.swift +++ b/Sources/OTCore/Extensions/Foundation/Data.swift @@ -45,7 +45,7 @@ extension Data { /// Returns nil if Data is not the correct length. public func toInt8() -> Int8? { - guard self.count == 1 else { return nil } + guard count == 1 else { return nil } var int = UInt8() withUnsafeMutablePointer(to: &int) { @@ -131,8 +131,8 @@ extension Data { /// Returns nil if Data is not the correct length. public func toUInt8() -> UInt8? { - guard self.count == 1 else { return nil } - return self.first + guard count == 1 else { return nil } + return first } @@ -243,7 +243,7 @@ extension Data { /// Returns nil if Data is != 4 bytes. public func toFloat32(from endianness: NumberEndianness = .platformDefault) -> Float32? { - guard self.count == 4 else { return nil } + guard count == 4 else { return nil } // define conversions @@ -359,7 +359,7 @@ extension Data { /// Returns nil if Data is != 8 bytes. public func toDouble(from endianness: NumberEndianness = .platformDefault) -> Double? { - guard self.count == 8 else { return nil } + guard count == 8 else { return nil } // define conversions @@ -432,8 +432,8 @@ extension FixedWidthInteger { switch endianness { case .platformDefault: int = self - case .littleEndian: int = self.littleEndian - case .bigEndian: int = self.bigEndian + case .littleEndian: int = littleEndian + case .bigEndian: int = bigEndian } withUnsafeBytes(of: &int) { rawBuffer in @@ -510,7 +510,7 @@ extension String { /// Returns a Data representation of a String, defaulting to utf8 encoding. public func toData(using encoding: String.Encoding = .utf8) -> Data? { - self.data(using: encoding) + data(using: encoding) } diff --git a/Sources/OTCore/Extensions/Foundation/Decimal.swift b/Sources/OTCore/Extensions/Foundation/Decimal.swift index 8c1700a..23e5b7a 100644 --- a/Sources/OTCore/Extensions/Foundation/Decimal.swift +++ b/Sources/OTCore/Extensions/Foundation/Decimal.swift @@ -217,7 +217,7 @@ extension Decimal { public mutating func round(_ rule: NSDecimalNumber.RoundingMode = .plain, decimalPlaces: Int) { - self = self.rounded(rule, decimalPlaces: decimalPlaces) + self = rounded(rule, decimalPlaces: decimalPlaces) } @@ -226,7 +226,7 @@ extension Decimal { /// Replaces this value by truncating it to `decimalPlaces` number of decimal places. public mutating func truncate(decimalPlaces: Int) { - self = self.truncated(decimalPlaces: decimalPlaces) + self = truncated(decimalPlaces: decimalPlaces) } diff --git a/Sources/OTCore/Extensions/Foundation/NSAttributedString.swift b/Sources/OTCore/Extensions/Foundation/NSAttributedString.swift index 9fe23c4..1cfc221 100644 --- a/Sources/OTCore/Extensions/Foundation/NSAttributedString.swift +++ b/Sources/OTCore/Extensions/Foundation/NSAttributedString.swift @@ -20,14 +20,14 @@ extension NSAttributedString { let paragraph = NSMutableParagraphStyle() paragraph.alignment = alignment - guard let copy = self.mutableCopy() as? NSMutableAttributedString + guard let copy = mutableCopy() as? NSMutableAttributedString else { print("Could not create mutable NSAttributedString copy.") return self } - copy.addAttributes([ .paragraphStyle : paragraph ], - range: NSRange(location: 0, length: self.length)) + copy.addAttributes([.paragraphStyle : paragraph], + range: NSRange(location: 0, length: length)) return copy @@ -44,8 +44,8 @@ extension NSMutableAttributedString { let paragraph = NSMutableParagraphStyle() paragraph.alignment = alignment - self.addAttributes([ .paragraphStyle : paragraph ], - range: NSRange(location: 0, length: self.length)) + addAttributes([.paragraphStyle : paragraph], + range: NSRange(location: 0, length: length)) } diff --git a/Sources/OTCore/Extensions/Foundation/String and CharacterSet.swift b/Sources/OTCore/Extensions/Foundation/String and CharacterSet.swift index f410ca8..a097590 100644 --- a/Sources/OTCore/Extensions/Foundation/String and CharacterSet.swift +++ b/Sources/OTCore/Extensions/Foundation/String and CharacterSet.swift @@ -27,10 +27,10 @@ extension StringProtocol { // iterate over characters - var currentGroupingStartIndex: Self.Index? = self.indices.first + var currentGroupingStartIndex: Self.Index? = indices.first var lastCharSetIndex: Int? = nil - for idx in self.indices { + for idx in indices { // helper @@ -53,13 +53,13 @@ extension StringProtocol { let firstMatchingCharSetIndex = characterSets.firstIndex(where: { $0.contains(scalar) }) if lastCharSetIndex != firstMatchingCharSetIndex - && idx != self.indices.first { + && idx != indices.first { // grouping separator here // close off previous grouping and append to result array - closeGrouping(closingIdx: self.index(before: idx)) + closeGrouping(closingIdx: index(before: idx)) // start new grouping @@ -69,8 +69,8 @@ extension StringProtocol { // close off if we've reached the end of the string - if idx == self.indices.last { - if idx == self.indices.first { + if idx == indices.last { + if idx == indices.first { lastCharSetIndex = firstMatchingCharSetIndex } @@ -103,7 +103,7 @@ extension StringProtocol { /// public func only(_ characterSet: CharacterSet) -> String { - self.map { characterSet.contains(UnicodeScalar("\($0)")!) ? "\($0)" : "" } + map { characterSet.contains(UnicodeScalar("\($0)")!) ? "\($0)" : "" } .joined() } @@ -112,7 +112,7 @@ extension StringProtocol { /// Returns a string preserving only characters from the passed string and removing all other characters. public func only(characters: String) -> String { - self.only(CharacterSet(charactersIn: characters)) + only(CharacterSet(charactersIn: characters)) } @@ -120,7 +120,7 @@ extension StringProtocol { /// Returns a string containing only alphanumeric characters and removing all other characters. public var onlyAlphanumerics: String { - self.only(.alphanumerics) + only(.alphanumerics) } @@ -128,7 +128,7 @@ extension StringProtocol { /// Returns a string removing all characters from the passed CharacterSet. public func removing(_ characterSet: CharacterSet) -> String { - self.components(separatedBy: characterSet) + components(separatedBy: characterSet) .joined() } @@ -137,7 +137,7 @@ extension StringProtocol { /// Returns a string removing all characters from the passed string. public func removing(characters: String) -> String { - self.components(separatedBy: CharacterSet(charactersIn: characters)) + components(separatedBy: CharacterSet(charactersIn: characters)) .joined() } diff --git a/Sources/OTCore/Extensions/Foundation/URL.swift b/Sources/OTCore/Extensions/Foundation/URL.swift index ca9726f..5e6dc79 100644 --- a/Sources/OTCore/Extensions/Foundation/URL.swift +++ b/Sources/OTCore/Extensions/Foundation/URL.swift @@ -19,7 +19,7 @@ extension URL { /// - Will still return `true` if used on an alias and the alias' original file does not exist. public var fileExists: Bool { - FileManager.default.fileExists(atPath: self.path) + FileManager.default.fileExists(atPath: path) } @@ -29,7 +29,7 @@ extension URL { /// - Will return `nil` if the URL is not a properly formatted file URL, or there was a problem querying the URL's file system attributes. public var isFolder: Bool? { - try? self.resourceValues(forKeys: Set([URLResourceKey.isDirectoryKey])) + try? resourceValues(forKeys: Set([URLResourceKey.isDirectoryKey])) .isDirectory } @@ -118,7 +118,7 @@ extension URL { /// Convenience method to test if a file URL is a Finder alias. public var isFinderAlias: Bool { - guard self.isFileURL else { return false } + guard isFileURL else { return false } return (try? URL.bookmarkData(withContentsOf: self)) != nil @@ -129,7 +129,7 @@ extension URL { public func createFinderAlias(at url: URL) throws { let data = try - self.bookmarkData( + bookmarkData( options: .suitableForBookmarkFile, includingResourceValuesForKeys: nil, relativeTo: nil @@ -148,7 +148,7 @@ extension URL { /// - does not exist. public var resolvedFinderAlias: URL? { - guard self.isFileURL else { return nil } + guard isFileURL else { return nil } guard let data = try? URL.bookmarkData(withContentsOf: self) else { return nil } @@ -176,11 +176,11 @@ extension URL { /// - Returns `nil` if the URL is not a properly formatted file URL, or there was a problem querying the URL's file system attributes. public var isSymLink: Bool? { - guard self.isFileURL + guard isFileURL else { return nil } guard let getAttr = try? FileManager.default - .attributesOfItem(atPath: self.path) + .attributesOfItem(atPath: path) else { return nil } guard let getFileType = getAttr[.type] @@ -200,7 +200,7 @@ extension URL { guard file.isFileURL else { return nil } - return self.isSymLinkOf(file: file.path) + return isSymLinkOf(file: file.path) } @@ -211,12 +211,12 @@ extension URL { /// - Returns `nil` if the URL is not a properly formatted file URL. public func isSymLinkOf(file: String) -> Bool? { - guard self.isFileURL + guard isFileURL else { return nil } // returns path of original file, even if original file no longer exists guard let dest = try? FileManager.default - .destinationOfSymbolicLink(atPath: self.path) + .destinationOfSymbolicLink(atPath: path) else { return false } return file == dest diff --git a/Sources/OTCore/Extensions/Foundation/UserDefaults.swift b/Sources/OTCore/Extensions/Foundation/UserDefaults.swift index e569c0e..d2ab2c4 100644 --- a/Sources/OTCore/Extensions/Foundation/UserDefaults.swift +++ b/Sources/OTCore/Extensions/Foundation/UserDefaults.swift @@ -15,8 +15,8 @@ extension UserDefaults { /// Convenience method to wrap the built-in `.integer(forKey:)` method in an optional returning nil if the key doesn't exist. public func integerOptional(forKey key: String) -> Int? { - guard self.object(forKey: key) != nil else { return nil } - return self.integer(forKey: key) + guard object(forKey: key) != nil else { return nil } + return integer(forKey: key) } @@ -24,8 +24,8 @@ extension UserDefaults { /// Convenience method to wrap the built-in `.double(forKey:)` method in an optional returning nil if the key doesn't exist. public func doubleOptional(forKey key: String) -> Double? { - guard self.object(forKey: key) != nil else { return nil } - return self.double(forKey: key) + guard object(forKey: key) != nil else { return nil } + return double(forKey: key) } @@ -33,8 +33,8 @@ extension UserDefaults { /// Convenience method to wrap the built-in `.float(forKey:)` method in an optional returning nil if the key doesn't exist. public func floatOptional(forKey key: String) -> Float? { - guard self.object(forKey: key) != nil else { return nil } - return self.float(forKey: key) + guard object(forKey: key) != nil else { return nil } + return float(forKey: key) } @@ -42,8 +42,8 @@ extension UserDefaults { /// Convenience method to wrap the built-in `.bool(forKey:)` method in an optional returning nil if the key doesn't exist. public func boolOptional(forKey key: String) -> Bool? { - guard self.object(forKey: key) != nil else { return nil } - return self.bool(forKey: key) + guard object(forKey: key) != nil else { return nil } + return bool(forKey: key) } @@ -53,7 +53,7 @@ extension UserDefaults { /// This method is only useful when you don't care about extracting a value from the key and merely want to check for the key's existence. public func exists(key: String) -> Bool { - self.object(forKey: key) != nil + object(forKey: key) != nil } diff --git a/Sources/OTCore/Extensions/Foundation/XMLNode.swift b/Sources/OTCore/Extensions/Foundation/XMLNode.swift index 4d42a77..295e214 100644 --- a/Sources/OTCore/Extensions/Foundation/XMLNode.swift +++ b/Sources/OTCore/Extensions/Foundation/XMLNode.swift @@ -31,7 +31,7 @@ extension Collection where Element : XMLNode { /// Filters by the given XML element name @inlinable public func filter(elementName: String) -> [XMLNode] { - self.filter { $0.name == elementName } + filter { $0.name == elementName } } @@ -40,7 +40,7 @@ extension Collection where Element : XMLNode { @inlinable public func filter(attribute: String, value: String) -> [XMLNode] { - self.filter { + filter { $0.asElement? .attribute(forName: attribute)? .stringValue == value @@ -53,7 +53,7 @@ extension Collection where Element : XMLNode { @inlinable public func filter(attribute: String, _ isIncluded: (String) throws -> Bool) rethrows -> [XMLNode] { - try self.filter { + try filter { let filtered = try [$0.attributeStringValue(forName: attribute)] .compactMap{$0} .filter(isIncluded) @@ -72,7 +72,7 @@ extension XMLNode { /// Gets an attribute value. If attribute name does not exist or does not have a value, nil will be returned. public func attributeStringValue(forName: String) -> String? { - self.asElement?.attribute(forName: forName)?.stringValue + asElement?.attribute(forName: forName)?.stringValue } @@ -80,7 +80,7 @@ extension XMLNode { /// Gets an attribute value. If attribute name does not exist or does not have a value, nil will be returned. public func attributeObjectValue(forName: String) -> Any? { - self.asElement?.attribute(forName: forName)?.objectValue + asElement?.attribute(forName: forName)?.objectValue } @@ -92,7 +92,7 @@ extension XMLNode { attr.name = withName attr.stringValue = value - self.asElement?.addAttribute(attr) + asElement?.addAttribute(attr) } @@ -111,7 +111,7 @@ extension XMLElement { self.init(name: name) - self.addAttributes(attributes) + addAttributes(attributes) } @@ -121,7 +121,7 @@ extension XMLElement { public func addAttributes(_ attributes: [(name: String, value: String)]) { attributes.forEach { - self.addAttribute(withName: $0.name, value: $0.value) + addAttribute(withName: $0.name, value: $0.value) } } diff --git a/Sources/OTCore/Extensions/Swift/Collections.swift b/Sources/OTCore/Extensions/Swift/Collections.swift index f86a4d1..a3f5e79 100644 --- a/Sources/OTCore/Extensions/Swift/Collections.swift +++ b/Sources/OTCore/Extensions/Swift/Collections.swift @@ -147,7 +147,7 @@ extension RangeReplaceableCollection { @inlinable public mutating func remove(safeAt index: Index) -> Element? { if indices.contains(index) { - return self.remove(at: index) + return remove(at: index) } return nil @@ -179,7 +179,7 @@ extension Array { /// @inlinable public subscript(wrapping index: Index) -> Iterator.Element { - let max = self.count + let max = count var newIndex: Int if index >= 0 { @@ -205,7 +205,7 @@ extension Collection where Element : Hashable { /// - complexity: O(*n*) @inlinable public func count(of element: Element) -> Int { - self.filter{$0 == element}.count + filter{$0 == element}.count } @@ -220,7 +220,7 @@ extension Collection where Element: BinaryInteger { /// Returns a string of integer literals, useful for generating Swift array declarations when debugging. @inlinable public var stringValueArrayLiteral: String { - self.map { "\($0)" } + map { "\($0)" } .joined(separator: ", " ) .wrapped(with: .brackets) @@ -258,11 +258,11 @@ extension Collection where Element: Strideable, /// - complexity: O(*n*), where *n* represents index of first gap in the array @inlinable public func firstGapValue(after: Element? = nil) -> Element? { - guard self.count > 0 else { return nil } + guard count > 0 else { return nil } - for idx in self.startIndex..= self.endIndex.advanced(by: -1) { continue } + if idx >= endIndex.advanced(by: -1) { continue } if self[idx.advanced(by: 1)] > (self[idx].advanced(by: 1)) { // found a gap @@ -304,7 +304,7 @@ extension Set { @inlinable public mutating func formUnion(updating other: S) where Element == S.Element, S : Sequence { - self = self.union(updating: other) + self = union(updating: other) } @@ -341,3 +341,38 @@ extension Sequence { } } + +// MARK: - Dictionary map + +extension Dictionary { + + // Swift Standard Library provides `mapValues`, + // so `mapKeys` and `mapDictionary` methods are useful accompaniments + + /// **OTCore:** + /// Returns a new dictionary containing the values of this dictionary with the keys transformed by the given closure. + public func mapKeys( + _ transform: (Key) throws -> K + ) rethrows -> Dictionary { + + try reduce(into: [:]) { partialResult, keyValuePair in + let transformedKey = try transform(keyValuePair.0) + partialResult[transformedKey] = keyValuePair.1 + } + + } + + /// **OTCore:** + /// Returns a new dictionary with key/value pairs transformed by the given closure. + public func mapDictionary( + _ transform: (Key, Value) throws -> (K, V) + ) rethrows -> Dictionary { + + try reduce(into: [:]) { partialResult, keyValuePair in + let transformedKeyPair = try transform(keyValuePair.0, keyValuePair.1) + partialResult[transformedKeyPair.0] = transformedKeyPair.1 + } + + } + +} diff --git a/Sources/OTCore/Extensions/Swift/FloatingPoint.swift b/Sources/OTCore/Extensions/Swift/FloatingPoint.swift index 5ac2dd3..32b57e8 100644 --- a/Sources/OTCore/Extensions/Swift/FloatingPoint.swift +++ b/Sources/OTCore/Extensions/Swift/FloatingPoint.swift @@ -176,7 +176,7 @@ extension FloatingPoint where Self : FloatingPointPowerComputable { ) -> Self { if decimalPlaces < 1 { - return self.rounded(rule) + return rounded(rule) } let offset = Self(10).power(Self(decimalPlaces)) @@ -194,7 +194,7 @@ extension FloatingPoint where Self : FloatingPointPowerComputable { decimalPlaces: Int ) { - self = self.rounded(rule, decimalPlaces: decimalPlaces) + self = rounded(rule, decimalPlaces: decimalPlaces) } @@ -228,7 +228,7 @@ extension FloatingPoint { /// - parameter range: integer range, allowing negative and positive bounds. @inlinable public func wrapped(around range: ClosedRange) -> Self { - guard !self.isNaN, !self.isInfinite else { return self } + guard !isNaN, !isInfinite else { return self } let min = range.lowerBound let max = range.upperBound + 1 @@ -249,14 +249,14 @@ extension FloatingPoint { /// If the number underflows or overflows the range, it is wrapped around the range's bounds continuously. @inlinable public func wrapped(around range: Range) -> Self { - guard !self.isNaN, !self.isInfinite else { return self } + guard !isNaN, !isInfinite else { return self } let min = range.lowerBound var max = range.upperBound - 1 if max < min { max = min } - return self.wrapped(around: min...max) + return wrapped(around: min...max) } diff --git a/Sources/OTCore/Extensions/Swift/Integers.swift b/Sources/OTCore/Extensions/Swift/Integers.swift index 6c70b18..e8adcf8 100644 --- a/Sources/OTCore/Extensions/Swift/Integers.swift +++ b/Sources/OTCore/Extensions/Swift/Integers.swift @@ -343,10 +343,10 @@ extension RangeReplaceableCollection where Element : FixedWidthInteger { count: Int) { self.init() - self.reserveCapacity(count) + reserveCapacity(count) for _ in 0.. { - self.bindMemory(to: UInt8.self) + bindMemory(to: UInt8.self) } diff --git a/Sources/OTCore/Extensions/Swift/Ranges.swift b/Sources/OTCore/Extensions/Swift/Ranges.swift index 4eb64c7..5867dfa 100644 --- a/Sources/OTCore/Extensions/Swift/Ranges.swift +++ b/Sources/OTCore/Extensions/Swift/Ranges.swift @@ -294,10 +294,10 @@ extension ClosedRange where Bound: SignedInteger, Bound.Stride: SignedInteger { public func first(excluding: ArraySlice) -> Bound? { guard excluding.count > 0 else { - return self.first + return first } - return self.first(where: { !excluding.contains($0) } ) + return first(where: { !excluding.contains($0) } ) } @@ -327,24 +327,24 @@ extension ClosedRange where Bound: SignedInteger, Bound.Stride: SignedInteger { public func first(presortedExcluding: ArraySlice) -> Bound? { guard presortedExcluding.count > 0 else { - return self.first + return first } // optimization: check to see if entire excluding value set is < or > first base value; if so, just return first value - if self.lowerBound < presortedExcluding.first! { return self.lowerBound } // do excluding values start > first base value? - if self.lowerBound > presortedExcluding.last! { return self.lowerBound } // do excluding values end < first base value? + if lowerBound < presortedExcluding.first! { return lowerBound } // do excluding values start > first base value? + if lowerBound > presortedExcluding.last! { return lowerBound } // do excluding values end < first base value? var trimmedSortedExcluding: ArraySlice? // optimization: trim exclusions, if exclusions start before first base value - if self.lowerBound > presortedExcluding.first! { - if let minExclusion = presortedExcluding.binarySearch(forValue: self.lowerBound) { + if lowerBound > presortedExcluding.first! { + if let minExclusion = presortedExcluding.binarySearch(forValue: lowerBound) { trimmedSortedExcluding = presortedExcluding[minExclusion.lowerBound..) -> Bound? { // optimization: if not excluding anything, just return first value - if sortingAndExcluding.count == 0 { return self.lowerBound } + if sortingAndExcluding.count == 0 { return lowerBound } let sortedExcluding = sortingAndExcluding.sorted() - return self.first(excluding: sortedExcluding) + return first(excluding: sortedExcluding) } @@ -412,12 +412,15 @@ extension ClosedRange where Bound.Stride: SignedInteger, Bound: Strideable { /// - complexity: O(1) or slightly higher public func first(excluding: ClosedRange) -> Bound? { - if excluding.lowerBound > self.lowerBound { return self.lowerBound } + if excluding.lowerBound > lowerBound { return lowerBound } - if excluding.upperBound < self.lowerBound { return self.lowerBound } // no overlaps in ranges; return first + // no overlaps in ranges; return first + if excluding.upperBound < lowerBound { return lowerBound } - if excluding.upperBound >= self.lowerBound && - excluding.upperBound < self.upperBound { return excluding.upperBound.advanced(by: 1) } + if excluding.upperBound >= lowerBound && + excluding.upperBound < upperBound { + return excluding.upperBound.advanced(by: 1) + } return nil @@ -429,12 +432,15 @@ extension ClosedRange where Bound.Stride: SignedInteger, Bound: Strideable { /// - complexity: O(1) or slightly higher public func first(excluding: Range) -> Bound? { - if excluding.lowerBound > self.lowerBound { return self.lowerBound } + if excluding.lowerBound > lowerBound { return lowerBound } - if excluding.upperBound <= self.lowerBound { return self.lowerBound } // no overlaps in ranges; return first + // no overlaps in ranges; return first + if excluding.upperBound <= lowerBound { return lowerBound } - if excluding.upperBound > self.lowerBound && - excluding.upperBound <= self.upperBound { return excluding.upperBound } + if excluding.upperBound > lowerBound && + excluding.upperBound <= upperBound { + return excluding.upperBound + } return nil @@ -446,9 +452,9 @@ extension ClosedRange where Bound.Stride: SignedInteger, Bound: Strideable { /// - complexity: O(1) or slightly higher public func first(excluding: PartialRangeFrom) -> Bound? { - if excluding.lowerBound <= self.lowerBound { return nil } + if excluding.lowerBound <= lowerBound { return nil } - return self.lowerBound + return lowerBound } @@ -458,9 +464,9 @@ extension ClosedRange where Bound.Stride: SignedInteger, Bound: Strideable { /// - complexity: O(1) or slightly higher public func first(excluding: PartialRangeThrough) -> Bound? { - if excluding.upperBound < self.lowerBound { return self.lowerBound } + if excluding.upperBound < lowerBound { return lowerBound } - if excluding.upperBound < self.upperBound { return excluding.upperBound.advanced(by: 1) } + if excluding.upperBound < upperBound { return excluding.upperBound.advanced(by: 1) } return nil @@ -472,9 +478,9 @@ extension ClosedRange where Bound.Stride: SignedInteger, Bound: Strideable { /// - complexity: O(1) or slightly higher public func first(excluding: PartialRangeUpTo) -> Bound? { - if excluding.upperBound <= self.lowerBound { return self.lowerBound } + if excluding.upperBound <= lowerBound { return lowerBound } - if excluding.upperBound <= self.upperBound { return excluding.upperBound } + if excluding.upperBound <= upperBound { return excluding.upperBound } return nil @@ -499,10 +505,10 @@ extension Range where Bound: SignedInteger, Bound.Stride: SignedInteger { return self.first } - if self.upperBound == self.lowerBound { return nil } + if upperBound == lowerBound { return nil } // Form ClosedRange and call .first(...) on it - return (self.lowerBound...self.upperBound-1) + return (lowerBound...upperBound-1) .first(excluding: excluding) } @@ -529,10 +535,10 @@ extension Range where Bound: SignedInteger, Bound.Stride: SignedInteger { /// - complexity: O(*n1* * *n2*), where *n1* == self.count, *n2* == excluding.count; lazily over `self.count`. public func first(presortedExcluding: ArraySlice) -> Bound? { - if self.upperBound == self.lowerBound { return nil } + if upperBound == lowerBound { return nil } // Form ClosedRange and call .first(...) on it - return (self.lowerBound...self.upperBound-1) + return (lowerBound...upperBound-1) .first(presortedExcluding: presortedExcluding) } @@ -548,10 +554,10 @@ extension Range where Bound: SignedInteger, Bound.Stride: SignedInteger { /// - complexity: O(*n1* * *n2*), where *n1* == self.count, *n2* == excluding.count; lazily over `self.count`. public func first(presortedExcluding: [Bound]) -> Bound? { - if self.upperBound == self.lowerBound { return nil } + if upperBound == lowerBound { return nil } // Form ClosedRange and call .first(...) on it - return (self.lowerBound...self.upperBound-1) + return (lowerBound...upperBound-1) .first(presortedExcluding: ArraySlice(presortedExcluding)) } @@ -565,10 +571,10 @@ extension Range where Bound: SignedInteger, Bound.Stride: SignedInteger { /// - complexity: Varies, somewhere between O(`sortingAndExcluding.count`) and O(`self.count * excluding.count`). public func first(sortingAndExcluding: ArraySlice) -> Bound? { - if self.upperBound == self.lowerBound { return nil } + if upperBound == lowerBound { return nil } // Form ClosedRange and call .first(...) on it - return (self.lowerBound...self.upperBound-1) + return (lowerBound...upperBound-1) .first(sortingAndExcluding: sortingAndExcluding) } @@ -595,12 +601,13 @@ extension Range where Bound : Strideable, Bound.Stride : SignedInteger { /// - complexity: O(1) or slightly higher public func first(excluding: ClosedRange) -> Bound? { - if excluding.lowerBound > self.lowerBound { return self.lowerBound } + if excluding.lowerBound > lowerBound { return lowerBound } - if excluding.upperBound < self.lowerBound { return self.lowerBound } // no overlaps in ranges; return first + // no overlaps in ranges; return first + if excluding.upperBound < lowerBound { return lowerBound } - if excluding.upperBound >= self.lowerBound && - excluding.upperBound < self.upperBound.advanced(by: -1) { + if excluding.upperBound >= lowerBound && + excluding.upperBound < upperBound.advanced(by: -1) { return excluding.upperBound.advanced(by: 1) } @@ -613,12 +620,13 @@ extension Range where Bound : Strideable, Bound.Stride : SignedInteger { /// - complexity: O(1) or slightly higher public func first(excluding: Range) -> Bound? { - if excluding.lowerBound > self.lowerBound { return self.lowerBound } + if excluding.lowerBound > lowerBound { return lowerBound } - if excluding.upperBound <= self.lowerBound { return self.lowerBound } // no overlaps in ranges; return first + // no overlaps in ranges; return first + if excluding.upperBound <= lowerBound { return lowerBound } - if excluding.upperBound >= self.lowerBound && - excluding.upperBound.advanced(by: -1) < self.upperBound.advanced(by: -1) { + if excluding.upperBound >= lowerBound && + excluding.upperBound.advanced(by: -1) < upperBound.advanced(by: -1) { return excluding.upperBound } @@ -631,9 +639,9 @@ extension Range where Bound : Strideable, Bound.Stride : SignedInteger { /// - complexity: O(1) or slightly higher public func first(excluding: PartialRangeFrom) -> Bound? { - if excluding.lowerBound <= self.lowerBound { return nil } + if excluding.lowerBound <= lowerBound { return nil } - return self.lowerBound + return lowerBound } @@ -642,9 +650,9 @@ extension Range where Bound : Strideable, Bound.Stride : SignedInteger { /// - complexity: O(1) or slightly higher public func first(excluding: PartialRangeThrough) -> Bound? { - if excluding.upperBound < self.lowerBound { return self.lowerBound } + if excluding.upperBound < lowerBound { return lowerBound } - if excluding.upperBound < self.upperBound.advanced(by: -1) { + if excluding.upperBound < upperBound.advanced(by: -1) { return excluding.upperBound.advanced(by: 1) } @@ -657,9 +665,9 @@ extension Range where Bound : Strideable, Bound.Stride : SignedInteger { /// - complexity: O(1) or slightly higher public func first(excluding: PartialRangeUpTo) -> Bound? { - if excluding.upperBound <= self.lowerBound { return self.lowerBound } + if excluding.upperBound <= lowerBound { return lowerBound } - if excluding.upperBound < self.upperBound { return excluding.upperBound } + if excluding.upperBound < upperBound { return excluding.upperBound } return nil @@ -681,7 +689,7 @@ extension PartialRangeFrom where Bound.Stride: SignedInteger, Bound: Strideable // should always succeed since PartialRangeFrom values ascend infinitely // however, we provide a fallback - self.first(where: { !excluding.contains($0) } ) + first(where: { !excluding.contains($0) } ) ?? lowerBound } @@ -704,12 +712,12 @@ extension PartialRangeFrom where Bound.Stride: SignedInteger, Bound: Strideable /// - complexity: O(*n*), where *n* is the length of the exclusion array. public func first(presortedExcluding: ArraySlice) -> Bound { - if presortedExcluding.isEmpty { return self.lowerBound } + if presortedExcluding.isEmpty { return lowerBound } - if presortedExcluding.last! < self.lowerBound { return self.lowerBound } + if presortedExcluding.last! < lowerBound { return lowerBound } return presortedExcluding - .firstGapValue(after: self.lowerBound.advanced(by: -1)) + .firstGapValue(after: lowerBound.advanced(by: -1)) ?? presortedExcluding.last!.advanced(by: 1) } @@ -734,14 +742,14 @@ extension PartialRangeFrom where Bound.Stride: SignedInteger, Bound: Strideable /// - complexity: O(*n*), where *n* is the length of the exclusion array. public func first(sortingAndExcluding: ArraySlice) -> Bound { - if sortingAndExcluding.isEmpty { return self.lowerBound } + if sortingAndExcluding.isEmpty { return lowerBound } let sortedExcluding = sortingAndExcluding.sorted() - if sortedExcluding.last! < self.lowerBound { return self.lowerBound } + if sortedExcluding.last! < lowerBound { return lowerBound } return sortedExcluding - .firstGapValue(after: self.lowerBound.advanced(by: -1)) + .firstGapValue(after: lowerBound.advanced(by: -1)) ?? sortedExcluding.last!.advanced(by: 1) } @@ -767,9 +775,10 @@ extension PartialRangeFrom where Bound.Stride: SignedInteger, Bound: Strideable /// - complexity: O(1) or slightly higher public func first(excluding: ClosedRange) -> Bound { - if self.lowerBound < excluding.lowerBound { return self.lowerBound } + if lowerBound < excluding.lowerBound { return lowerBound } - if excluding.upperBound < self.lowerBound { return self.lowerBound } // no overlaps in ranges; return first + // no overlaps in ranges; return first + if excluding.upperBound < lowerBound { return lowerBound } return excluding.upperBound.advanced(by: 1) @@ -781,9 +790,10 @@ extension PartialRangeFrom where Bound.Stride: SignedInteger, Bound: Strideable /// - complexity: O(1) or slightly higher public func first(excluding: Range) -> Bound { - if self.lowerBound < excluding.lowerBound { return self.lowerBound } + if lowerBound < excluding.lowerBound { return lowerBound } - if excluding.upperBound < self.lowerBound { return self.lowerBound } // no overlaps in ranges; return first + // no overlaps in ranges; return first + if excluding.upperBound < lowerBound { return lowerBound } return excluding.upperBound @@ -795,9 +805,9 @@ extension PartialRangeFrom where Bound.Stride: SignedInteger, Bound: Strideable /// - complexity: O(1) or slightly higher public func first(excluding: PartialRangeFrom) -> Bound? { - if excluding.lowerBound <= self.lowerBound { return nil } + if excluding.lowerBound <= lowerBound { return nil } - return self.lowerBound + return lowerBound } @@ -807,7 +817,7 @@ extension PartialRangeFrom where Bound.Stride: SignedInteger, Bound: Strideable /// - complexity: O(1) or slightly higher public func first(excluding: PartialRangeThrough) -> Bound { - if excluding.upperBound < self.lowerBound { return self.lowerBound } + if excluding.upperBound < lowerBound { return lowerBound } return excluding.upperBound.advanced(by: 1) @@ -819,7 +829,7 @@ extension PartialRangeFrom where Bound.Stride: SignedInteger, Bound: Strideable /// - complexity: O(1) or slightly higher public func first(excluding: PartialRangeUpTo) -> Bound { - if excluding.upperBound <= self.lowerBound { return self.lowerBound } + if excluding.upperBound <= lowerBound { return lowerBound } return excluding.upperBound diff --git a/Sources/OTCore/Extensions/Swift/String.swift b/Sources/OTCore/Extensions/Swift/String.swift index 05d1a50..f57d2cd 100644 --- a/Sources/OTCore/Extensions/Swift/String.swift +++ b/Sources/OTCore/Extensions/Swift/String.swift @@ -97,7 +97,7 @@ extension StringProtocol { /// (Functional convenience method) public func range(backwards find: Self) -> Range? { - self.range(of: find, options: .backwards) + range(of: find, options: .backwards) } @@ -106,7 +106,7 @@ extension StringProtocol { /// (Functional convenience method) public func range(backwardsCaseInsensitive find: Self) -> Range? { - self.range(of: find, options: [.caseInsensitive, .backwards]) + range(of: find, options: [.caseInsensitive, .backwards]) } @@ -114,7 +114,7 @@ extension StringProtocol { /// Convenience method: returns `true` if contains string. Case-insensitive. public func contains(caseInsensitive find: Self) -> Bool { - self.range(of: find, options: .caseInsensitive) != nil + range(of: find, options: .caseInsensitive) != nil ? true : false @@ -124,7 +124,7 @@ extension StringProtocol { /// Convenience method: returns `true` if starts with the specified string. Case-insensitive. public func starts(withCaseInsensitive prefix: Self) -> Bool { - self.uppercased() + uppercased() .starts(with: prefix.uppercased()) } @@ -154,7 +154,7 @@ extension Substring { /// (Functional convenience method) public func repeating(_ count: Int) -> String { - String(repeating: self.string, count: count) + String(repeating: string, count: count) } @@ -166,7 +166,7 @@ extension StringProtocol { /// Convenience function to return a new string with whitespaces and newlines trimmed off start and end. @inlinable public var trimmed: String { - self.trimmingCharacters(in: .whitespacesAndNewlines) + trimmingCharacters(in: .whitespacesAndNewlines) } @@ -178,7 +178,7 @@ extension String { /// Convenience function to trim whitespaces and newlines off start and end. @inlinable public mutating func trim() { - self = self.trimmed + self = trimmed } @@ -192,26 +192,26 @@ extension StringProtocol { var result: [Self.SubSequence] = [] - for i in stride(from: 0, to: self.count, by: every) { + for i in stride(from: 0, to: count, by: every) { switch backwards { case true: - let endIndex = self.index(self.endIndex, offsetBy: -i) - let startIndex = self.index(endIndex, - offsetBy: -every, - limitedBy: self.startIndex) - ?? self.startIndex + let offsetEndIndex = index(endIndex, offsetBy: -i) + let offsetStartIndex = index(offsetEndIndex, + offsetBy: -every, + limitedBy: startIndex) + ?? startIndex - result.insert(self[startIndex.. String { - if self.hasPrefix(prefix) { - return String(self.dropFirst(prefix.count)) + if hasPrefix(prefix) { + return String(dropFirst(prefix.count)) } return self @@ -244,8 +244,8 @@ extension String { /// Removes the prefix of a String if it exists. public mutating func removePrefix(_ prefix: String) { - if self.hasPrefix(prefix) { - self.removeFirst(prefix.count) + if hasPrefix(prefix) { + removeFirst(prefix.count) } } @@ -254,8 +254,8 @@ extension String { /// Removes the suffix of a String if it exists and returns a new String. public func removingSuffix(_ suffix: String) -> String { - if self.hasSuffix(suffix) { - return String(self.dropLast(suffix.count)) + if hasSuffix(suffix) { + return String(dropLast(suffix.count)) } return self @@ -266,8 +266,8 @@ extension String { /// Removes the suffix of a String if it exists. public mutating func removeSuffix(_ suffix: String) { - if self.hasSuffix(suffix) { - self.removeLast(suffix.count) + if hasSuffix(suffix) { + removeLast(suffix.count) } } @@ -328,7 +328,8 @@ extension DefaultStringInterpolation { extension Substring { /// **OTCore:** - /// Return a new `String`. + /// Same as `String(self)` + /// (Functional convenience method) @inlinable public var string: String { String(self) @@ -340,7 +341,7 @@ extension Substring { extension Character { /// **OTCore:** - /// Same as `String()` + /// Same as `String(self)` /// (Functional convenience method) @inlinable public var string: String { diff --git a/Tests/OTCoreTests/Extensions/Swift/Collections Tests.swift b/Tests/OTCoreTests/Extensions/Swift/Collections Tests.swift index 68892a3..a05b2d5 100644 --- a/Tests/OTCoreTests/Extensions/Swift/Collections Tests.swift +++ b/Tests/OTCoreTests/Extensions/Swift/Collections Tests.swift @@ -291,6 +291,79 @@ class Extensions_Swift_Collections_Tests: XCTestCase { ) } + func testDictionary_mapKeys_SameTypes() { + + let dict = ["One": 1, + "Two": 2] + + let mapped = dict.mapKeys { + $0 + " Key" + } + + XCTAssertEqual(mapped, + ["One Key": 1, + "Two Key": 2] + ) + + } + + func testDictionary_mapKeys_DifferentTypes() { + + struct MyKey: Equatable, Hashable { + var name: String + } + + let dict = ["One": 1, + "Two": 2] + + let mapped = dict.mapKeys { + MyKey(name: $0 + " Key") + } + + XCTAssertEqual(mapped, + [MyKey(name: "One Key"): 1, + MyKey(name: "Two Key"): 2] + ) + + } + + + func testDictionary_mapDictionary_SameTypes() { + + let dict = ["One": 1, + "Two": 2] + + let mapped = dict.mapDictionary { + ($0 + " plus Two", $1 + 2) + } + + XCTAssertEqual(mapped, + ["One plus Two": 3, + "Two plus Two": 4] + ) + + } + + func testDictionary_mapDictionary_DifferentTypes() { + + struct MyKey: Equatable, Hashable { + var name: String + } + + let dict = ["One": 1, + "Two": 2] + + let mapped = dict.mapDictionary { + (MyKey(name: $0 + " plus 2.5"), Double($1) + 2.5) + } + + XCTAssertEqual(mapped, + [MyKey(name: "One plus 2.5"): 3.5, + MyKey(name: "Two plus 2.5"): 4.5] + ) + + } + } #endif