Skip to content

Commit 84474a3

Browse files
committed
Initial setup of IntegerUtilities module.
Seeded with rotate(right:) and rotate(left:) on FixedWidthInteger. These implementations are basically sane, but need documentation written for users who are not already familiar with bitwise rotation.
1 parent 97dfcff commit 84474a3

File tree

3 files changed

+119
-0
lines changed

3 files changed

+119
-0
lines changed

Package.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ let package = Package(
2222
targets: [
2323
// User-facing modules
2424
.target(name: "ComplexModule", dependencies: ["RealModule"]),
25+
.target(name: "IntegerUtilities", dependencies: []),
2526
.target(name: "Numerics", dependencies: ["ComplexModule", "RealModule"]),
2627
.target(name: "RealModule", dependencies: ["_NumericsShims"]),
2728

@@ -31,6 +32,7 @@ let package = Package(
3132

3233
// Unit test bundles
3334
.testTarget(name: "ComplexTests", dependencies: ["_TestSupport"]),
35+
.testTarget(name: "IntegerUtilitiesTests", dependencies: ["IntegerUtilities"]),
3436
.testTarget(name: "RealTests", dependencies: ["_TestSupport"]),
3537

3638
// Test executables

Sources/IntegerUtilities/Rotate.swift

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//===--- Rotate.swift -----------------------------------------*- swift -*-===//
2+
//
3+
// This source file is part of the Swift Numerics open source project
4+
//
5+
// Copyright (c) 2021 Apple Inc. and the Swift Numerics project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
//
10+
//===----------------------------------------------------------------------===//
11+
12+
extension FixedWidthInteger {
13+
@_transparent @usableFromInline
14+
internal func rotateImplementation(right count: Int) -> Self {
15+
// We don't have an unsigned right shift operation for signed values, so
16+
// we need to convert to an unsigned type. The only unsigned type that's
17+
// guaranteed to be able to represent the bit pattern of any Self value
18+
// is Magnitude. It would be possible to have Magnitude be _wider_ than
19+
// Self, but that's OK as long as we're careful to complement the shift
20+
// count using Self.bitWidth and not Magnitude.bitWidth or zero.
21+
let bitPattern = Magnitude(truncatingIfNeeded: self)
22+
let countComplement = Self.bitWidth &- count
23+
return Self(truncatingIfNeeded:
24+
bitPattern &>> count | bitPattern &<< countComplement
25+
)
26+
}
27+
28+
/// `self` rotated bitwise right by `count` bits.
29+
///
30+
/// Equivalent to `rotated(left: 0 &- count)`.
31+
@inlinable
32+
public func rotated<Count: BinaryInteger>(right count: Count) -> Self {
33+
rotateImplementation(right: Int(truncatingIfNeeded: count))
34+
}
35+
36+
/// `self` rotated bitwise left by `count` bits.
37+
///
38+
/// Equivalent to `rotated(right: 0 &- count)`.
39+
@inlinable
40+
public func rotated<Count: BinaryInteger>(left count: Count) -> Self {
41+
rotateImplementation(right: 0 &- Int(truncatingIfNeeded: count))
42+
}
43+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
//===--- RotateTests.swift ------------------------------------*- swift -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2021 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import IntegerUtilities
14+
import XCTest
15+
16+
final class IntegerUtilitiesTests: XCTestCase {
17+
func testRotateUInt8() {
18+
let x: UInt8 = 0b10011100
19+
XCTAssertEqual(0b01001110, x.rotated(right:-7))
20+
XCTAssertEqual(0b00100111, x.rotated(right:-6))
21+
XCTAssertEqual(0b10010011, x.rotated(right:-5))
22+
XCTAssertEqual(0b11001001, x.rotated(right:-4))
23+
XCTAssertEqual(0b11100100, x.rotated(right:-3))
24+
XCTAssertEqual(0b01110010, x.rotated(right:-2))
25+
XCTAssertEqual(0b00111001, x.rotated(right:-1))
26+
XCTAssertEqual(0b10011100, x.rotated(right: 0))
27+
XCTAssertEqual(0b01001110, x.rotated(right: 1))
28+
XCTAssertEqual(0b00100111, x.rotated(right: 2))
29+
XCTAssertEqual(0b10010011, x.rotated(right: 3))
30+
XCTAssertEqual(0b11001001, x.rotated(right: 4))
31+
XCTAssertEqual(0b11100100, x.rotated(right: 5))
32+
XCTAssertEqual(0b01110010, x.rotated(right: 6))
33+
XCTAssertEqual(0b00111001, x.rotated(right: 7))
34+
XCTAssertEqual(0b10011100, x.rotated(right: 8))
35+
}
36+
37+
func testRotateInt16() {
38+
let x = Int16(bitPattern: 0b1001110000111110)
39+
XCTAssertEqual(Int16(bitPattern: 0b1001110000111110), x.rotated(left:-16))
40+
XCTAssertEqual(Int16(bitPattern: 0b0011100001111101), x.rotated(left:-15))
41+
XCTAssertEqual(Int16(bitPattern: 0b0111000011111010), x.rotated(left:-14))
42+
XCTAssertEqual(Int16(bitPattern: 0b1110000111110100), x.rotated(left:-13))
43+
XCTAssertEqual(Int16(bitPattern: 0b1100001111101001), x.rotated(left:-12))
44+
XCTAssertEqual(Int16(bitPattern: 0b1000011111010011), x.rotated(left:-11))
45+
XCTAssertEqual(Int16(bitPattern: 0b0000111110100111), x.rotated(left:-10))
46+
XCTAssertEqual(Int16(bitPattern: 0b0001111101001110), x.rotated(left:-9))
47+
XCTAssertEqual(Int16(bitPattern: 0b0011111010011100), x.rotated(left:-8))
48+
XCTAssertEqual(Int16(bitPattern: 0b0111110100111000), x.rotated(left:-7))
49+
XCTAssertEqual(Int16(bitPattern: 0b1111101001110000), x.rotated(left:-6))
50+
XCTAssertEqual(Int16(bitPattern: 0b1111010011100001), x.rotated(left:-5))
51+
XCTAssertEqual(Int16(bitPattern: 0b1110100111000011), x.rotated(left:-4))
52+
XCTAssertEqual(Int16(bitPattern: 0b1101001110000111), x.rotated(left:-3))
53+
XCTAssertEqual(Int16(bitPattern: 0b1010011100001111), x.rotated(left:-2))
54+
XCTAssertEqual(Int16(bitPattern: 0b0100111000011111), x.rotated(left:-1))
55+
XCTAssertEqual(Int16(bitPattern: 0b1001110000111110), x.rotated(left: 0))
56+
XCTAssertEqual(Int16(bitPattern: 0b0011100001111101), x.rotated(left: 1))
57+
XCTAssertEqual(Int16(bitPattern: 0b0111000011111010), x.rotated(left: 2))
58+
XCTAssertEqual(Int16(bitPattern: 0b1110000111110100), x.rotated(left: 3))
59+
XCTAssertEqual(Int16(bitPattern: 0b1100001111101001), x.rotated(left: 4))
60+
XCTAssertEqual(Int16(bitPattern: 0b1000011111010011), x.rotated(left: 5))
61+
XCTAssertEqual(Int16(bitPattern: 0b0000111110100111), x.rotated(left: 6))
62+
XCTAssertEqual(Int16(bitPattern: 0b0001111101001110), x.rotated(left: 7))
63+
XCTAssertEqual(Int16(bitPattern: 0b0011111010011100), x.rotated(left: 8))
64+
XCTAssertEqual(Int16(bitPattern: 0b0111110100111000), x.rotated(left: 9))
65+
XCTAssertEqual(Int16(bitPattern: 0b1111101001110000), x.rotated(left: 10))
66+
XCTAssertEqual(Int16(bitPattern: 0b1111010011100001), x.rotated(left: 11))
67+
XCTAssertEqual(Int16(bitPattern: 0b1110100111000011), x.rotated(left: 12))
68+
XCTAssertEqual(Int16(bitPattern: 0b1101001110000111), x.rotated(left: 13))
69+
XCTAssertEqual(Int16(bitPattern: 0b1010011100001111), x.rotated(left: 14))
70+
XCTAssertEqual(Int16(bitPattern: 0b0100111000011111), x.rotated(left: 15))
71+
XCTAssertEqual(Int16(bitPattern: 0b1001110000111110), x.rotated(left: 16))
72+
}
73+
}
74+

0 commit comments

Comments
 (0)