Last active
January 8, 2022 18:14
-
-
Save sp4c38/4bf17bb6c5d479ee85a7611604d0c13d to your computer and use it in GitHub Desktop.
Revisions
-
sp4c38 revised this gist
Jan 8, 2022 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -26,7 +26,7 @@ exampleData >>>= 10 // ["00000000", "00001010", "00011111"] You can use following function to print the values of `Data` as binary for testing. ```swift func printData(_ data: Data) { let result: [String] = data.map { byte in var byteString = String(byte, radix: 2) (0..<(8-byteString.count)).forEach { _ in byteString = "0"+byteString } return byteString -
sp4c38 renamed this gist
Jan 8, 2022 . 1 changed file with 0 additions and 0 deletions.There are no files selected for viewing
File renamed without changes. -
sp4c38 revised this gist
Jan 8, 2022 . 2 changed files with 1 addition and 1 deletion.There are no files selected for viewing
File renamed without changes.This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -19,7 +19,7 @@ exampleData >>>= 10 // ["00000000", "00001010", "00011111"] ### Note: - For left shift use either `<<` or `<<=`. - For right shift use either `>>>` or `>>>=`. Right shifts are always logical right shifts, arithmetic right shifts _are not_ supported. - The above operators don't overwrite the built-in Swift bitwise operators like `<<` or `<<=`. They are only used if the left side of the expression is of type `Data`. ### Testing: -
sp4c38 created this gist
Jan 8, 2022 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,93 @@ infix operator >>>=: AssignmentPrecedence infix operator >>>: BitwiseShiftPrecedence extension Data { private static let countBit: [Int: UInt8] = [ 1: 0b10000000, 2: 0b11000000, 3: 0b11100000, 4: 0b11110000, 5: 0b11111000, 6: 0b11111100, 7: 0b11111110, 8: 0b11111111 ] /// Performs a left shift. mutating private func leftShift(by shiftCount: Int) { guard self.count > 0, shiftCount > 0 else { return } guard self.count >= 2 else { self[0] <<= shiftCount; return } var truncateBytes: Int = shiftCount / 8 truncateBytes = truncateBytes > self.count ? self.count : truncateBytes if truncateBytes >= 1 { self.indices.forEach { if $0 <= (truncateBytes-1) { self.remove(at: 0) } } } let truncateBits = shiftCount-(truncateBytes*8) if truncateBits >= 1 { for index in 0..<self.endIndex { self[index] <<= truncateBits guard index != self.endIndex-1 else { continue } var switchingBits = self[index+1] & Data.countBit[truncateBits]! switchingBits >>= 8-truncateBits self[index] |= switchingBits } } if truncateBytes >= 1 { (1...truncateBytes).forEach { _ in self.append(0) } } } private static let reverseCountBit: [Int: UInt8] = [ 1: 0b00000001, 2: 0b00000011, 3: 0b00000111, 4: 0b00001111, 5: 0b00011111, 6: 0b00111111, 7: 0b01111111, 8: 0b11111111 ] /// Performs a logical right shift. mutating private func rightShift(by shiftCount: Int) { guard self.count > 0, shiftCount > 0 else { return } guard self.count >= 2 else { self[0] >>= shiftCount; return } var truncateBytes: Int = shiftCount / 8 // Ignore decimal places truncateBytes = truncateBytes > self.count ? self.count : truncateBytes if truncateBytes >= 1 { let maxIndex = self.endIndex-1 self.indices.reversed().forEach { if $0 > maxIndex-truncateBytes { self.remove(at: $0) } } } let truncateBits = shiftCount-(truncateBytes*8) if truncateBits >= 1 { for index in (0..<self.endIndex).reversed() { self[index] >>= truncateBits guard index != 0 else { continue } var switchingBits = self[index-1] & Data.reverseCountBit[truncateBits]! switchingBits <<= 8-truncateBits self[index] |= switchingBits } } if truncateBytes >= 1 { (1...truncateBytes).forEach { _ in self.insert(0, at: 0) } } } /// Performs a left shift. static func <<= (data: inout Data, shiftCount: Int) { data.leftShift(by: shiftCount) } /// Performs a left shift. static func << (data: Data, shiftCount: Int) -> Data { var copiedData = data copiedData.leftShift(by: shiftCount) return copiedData } /// Performs a logical right shift. static func >>>= (data: inout Data, shiftCount: Int) { data.rightShift(by: shiftCount) } /// Performs a logical right shift. static func >>> (data: Data, shiftCount: Int) -> Data { var copiedData = data copiedData.rightShift(by: shiftCount) return copiedData } } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,38 @@ ## Bitwise shift multiple bytes in `Data` **Why?** Swift doesn't have a built-in way of shifting the bits from multiple bytes inside [`Data`](https://developer.apple.com/documentation/foundation/data). The below extension on `Data` allows you to do exactly that: ```swift var exampleData = Data([40, 127, 67]) // ["00101000", "01111111", "01000011"] // Left shift: exampleData << 10 // ["11111101", "00001100", "00000000"] // Left shift and set: exampleData <<= 10 // ["11111101", "00001100", "00000000"] exampleData = Data([40, 127, 67]) // ["00101000", "01111111", "01000011"] // Right shift: exampleData >>> 10 // ["00000000", "00001010", "00011111"] // Right shift and set exampleData >>>= 10 // ["00000000", "00001010", "00011111"] ``` ### Note: - For left shift use either `<<` or `<<=`. - For right shift use either `>>>` or `>>>=`. Right shifts are always a logical right shift, arithmetic right shifts _are not_ supported. - The above operators don't overwrite the built-in Swift bitwise operators like `<<` or `<<=`. They are only used if the left side of the expression is of type `Data`. ### Testing: You can use following function to print the values of `Data` as binary for testing. ```swift func printData(_ data: Data) { var result: [String] = data.map { byte in var byteString = String(byte, radix: 2) (0..<(8-byteString.count)).forEach { _ in byteString = "0"+byteString } return byteString } print(result) } printData(exampleData) ```