How do I perform a circular shift in Swift?
You can achieve this with two bit shift operators and a bitwise OR:
func circularRightShift(_ input: UInt8, _ amount: UInt8) -> UInt8 {
let amount = amount % 8 // Reduce to the range 0...7
return (input >> amount) | (input << (8 - amount))
}
Example (amount=5):
abcdefgh <- bits of input
00000abc <- bits of input >> amount
defgh000 <- bits of input << (8 - amount)
defghabc <- bits of result
Shifting behavior for variable bits in Swift
those are the overloaded operators in Swift basically† for operator >>
, as you see there is no such operator overloading which works on UInt32
with Int
:
you can overload this operator anytime for your wish, like
func >>(lhs: UInt32, rhs: Int) -> UInt32 {
return lhs >> UInt32(rhs);
}
and your second code snippet will work without any issue in the future:
let shiftMe: UInt32 = 0xFF0000
let shiftValue: Int = 16
let shiftedConst = shiftMe >> shiftValue
you will find more information about custom operators in Swift here.
† in Xcode6 beta, beta2, beta3
What does shift left () actually do in Swift?
That's the bitwise left shift operator
Basically it's doing this
// moves 0 bits to left for 00000001
let birdCategory: UInt32 = 1 << 0
// moves 1 bits to left for 00000001 then you have 00000010
let worldCategory: UInt32 = 1 << 1
// moves 2 bits to left for 00000001 then you have 00000100
let pipeCategory: UInt32 = 1 << 2
// moves 3 bits to left for 00000001 then you have 00001000
let scoreCategory: UInt32 = 1 << 3
You end up having
birdCategory = 1
worldCategory = 2
pipeCategory = 4
scoreCategory= 8
Zero fill right shift in swift
If you use the truncatingBitPattern
initializer of integer types
to extract a byte then you don't have to mask the value and it does not matter if the shift operator fills with zeros or ones (which depends on whether the source
type is unsigned or signed).
Choose Int8
or UInt8
depending
on whether the byte should be interpreted as a signed or
unsigned number.
let value = 0xABCD
let signedByte = Int8(truncatingBitPattern: value >> 8)
print(signedByte) // -85
let unsignedByte = UInt8(truncatingBitPattern: value >> 8)
print(unsignedByte) // 171
Unsigned right shift operator '' in Swift
One sure way to do it is using the unsigned shift operation of unsigned integer type:
infix operator >>> : BitwiseShiftPrecedence
func >>> (lhs: Int64, rhs: Int64) -> Int64 {
return Int64(bitPattern: UInt64(bitPattern: lhs) >> UInt64(rhs))
}
print(-7 >>> 16) //->281474976710655
(Using -7
for testing with bit count 16
does not seem to be a good example, it loses all significant bits with 16-bit right shift.)
If you want to do it in your way, the bitwise-ORed missing sign bit cannot be a constant 0x4000000000000000
. It needs to be 0x8000_0000_0000_0000 (this constant overflows in Swift Int64
) when bit count == 0, and needs to be logically shifted with the same bits.
So, you need to write something like this:
infix operator >>>> : BitwiseShiftPrecedence
func >>>> (lhs: Int64, rhs: Int64) -> Int64 {
if lhs >= 0 {
return lhs >> rhs
} else {
return (Int64.max + lhs + 1) >> rhs | (1 << (63-rhs))
}
}
print(-7 >>>> 16) //->281474976710655
It seems far easier to work with unsigned integer types when you need unsigned shift operation.
How to break up expressions involve bitwise shift operators? Swift
hashValue
is already an Int
, so the Int(...)
constructors are not
needed. This compiles in Xcode 9:
let value = topLeft.hashValue | (topRight.hashValue << 1) | (bottomLeft.hashValue << 2) | (bottomRight.hashValue << 3)
But that is a bad idea! It relies on the hash value of booleans having specific values:
false.hashValue == 0
true.hashValue == 1
which is nowhere guaranteed. (The only guarantee is that identical elements have the same hash value. One must not even assume that hash
values are equal across different executions of your program,
see Hashable
).
A better solution would be
let value = (topLeft ? 1 : 0) + (topRight ? 2 : 0) + (bottomLeft ? 4 : 0) + (bottomRight ? 8 : 0)
Alternatively, use a switch-statement. Example:
switch (topLeft, topRight, bottomLeft, bottomRight) {
case (false, false, false, false):
// ... all false ...
case (false, true, true, false):
// ... topRight and bottomLeft are true ...
case (true, false, false, true):
// ... topLeft and bottomRight are true ...
default:
// ... all other cases ...
}
Bit shifting in swift generic function
I have a blog post on this topic that goes into more detail, but essentially there are three steps:
Create a new protocol with the bitshift operators and a constructor from
UInt8
:protocol BitshiftOperationsType {
func <<(lhs: Self, rhs: Self) -> Self
func >>(lhs: Self, rhs: Self) -> Self
init(_ val: UInt8)
}Declare conformance with an extension on each of the integer types - easy since they already implement everything in
BitshiftOperationsType
:extension Int : BitshiftOperationsType {}
extension Int8 : BitshiftOperationsType {}
extension Int16 : BitshiftOperationsType {}
extension Int32 : BitshiftOperationsType {}
extension Int64 : BitshiftOperationsType {}
extension UInt : BitshiftOperationsType {}
extension UInt8 : BitshiftOperationsType {}
extension UInt16 : BitshiftOperationsType {}
extension UInt32 : BitshiftOperationsType {}
extension UInt64 : BitshiftOperationsType {}Add a generic constraint so
T
conforms to your new protocol:func testBytes<T: IntegerType where T: BitshiftOperationsType>(bytesIn: [UInt8], inout dataOut: T){
let outputSize = sizeof(T)
var temp: T = 0
dataOut = 0
temp = T(bytesIn[0])
temp = temp << 1
}
Thanks to Martin R. for the fix for the gross bit I had here before!
Related Topics
Why Do I Have to Explicitly Unwrap My String in This Case
Access Parent Project Other_Swift_Flags from Pod
Alamofire Post Request with JSON Encoding
Swift - Boundingbox Cause Exc_Bad_Access (Code=1)
How to Byte Reverse Nsdata Output in Swift The Littleendian Way
Nsjsonserialization Error. Code=3840 "Invalid Value Around Character 0
Why Does Cabasicanimation Try to Initialize Another Instance of My Custom Calayer
Nsdatepicker in Nsstatusbar Nssmenuitem Not Receiving Input
Enum Initialized with a Non-Existent Rawvalue Does Not Fail and Return Nil
Swift Protocol Extension Implementing Another Protocol with Shared Associated Type
Pfobject Unable to Be Cast to Custom Subclass
How to Solve This Error: Thread 1: Exc_Resource Resource_Type_Memory (Limit=650 Mb, Unused=0X0)
Swift: Binary Operator '==' Cannot Be Applied to Operands of Type "Protocol"
iOS App Extension - Action - Custom Data