Last active
October 9, 2019 20:17
-
-
Save krzyzanowskim/20669eb99fc4eca32572 to your computer and use it in GitHub Desktop.
Bit shifting with overflow protection using overflow operator "&"
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 characters
// | |
// IntExtension.swift | |
// CryptoSwift | |
// | |
// Created by Marcin Krzyzanowski on 12/08/14. | |
// Copyright (C) 2014 Marcin Krzyżanowski <[email protected]> | |
// This software is provided 'as-is', without any express or implied warranty. | |
// | |
// In no event will the authors be held liable for any damages arising from the use of this software. | |
// | |
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: | |
// | |
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. | |
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |
// - This notice may not be removed or altered from any source or binary distribution. | |
/* | |
Bit shifting with overflow protection using overflow operator "&". | |
Approach is consistent with standard overflow operators &+, &-, &*, &/ | |
and introduce new overflow operators for shifting: &<<, &>> | |
Note: Works with unsigned integers values only | |
Usage | |
var i = 1 // init | |
var j = i &<< 2 //shift left | |
j &<<= 2 //shift left and assign | |
@see: https://medium.com/@krzyzanowskim/swiftly-shift-bits-and-protect-yourself-be33016ce071 | |
*/ | |
extension Int { | |
/** Shift bits to the left. All bits are shifted (including sign bit) */ | |
private mutating func shiftLeft(count: Int) -> Int { | |
if (self == 0) { | |
return self; | |
} | |
let bitsCount = sizeof(Int) * 8 | |
let shiftCount = Swift.min(count, bitsCount - 1) | |
var shiftedValue:Int = 0; | |
for bitIdx in 0..<bitsCount { | |
// if bit is set then copy to result and shift left 1 | |
let bit = 1 << bitIdx | |
if ((self & bit) == bit) { | |
shiftedValue = shiftedValue | (bit << shiftCount) | |
} | |
} | |
self = shiftedValue | |
return self | |
} | |
/** Shift bits to the right. All bits are shifted (including sign bit) */ | |
private mutating func shiftRight(count: UInt32) -> UInt32 { | |
if (self == 0) { | |
return self; | |
} | |
var bitsCount = UInt32(sizeofValue(self) * 8) | |
if (count >= bitsCount) { | |
return 0 | |
} | |
var maxBitsForValue = UInt32(floor(log2(Double(self)) + 1)) | |
var shiftCount = Swift.min(count, maxBitsForValue - 1) | |
var shiftedValue:UInt32 = 0; | |
for bitIdx in 0..<bitsCount { | |
// if bit is set then copy to result and shift left 1 | |
var bit = 1 << bitIdx | |
if ((self & bit) == bit) { | |
shiftedValue = shiftedValue | (bit >> shiftCount) | |
} | |
} | |
self = shiftedValue | |
return self | |
} | |
} | |
// Left operator | |
infix operator &<<= { | |
associativity none | |
precedence 160 | |
} | |
/** shift left and assign with bits truncation */ | |
func &<<= (inout lhs: Int, rhs: Int) { | |
lhs.shiftLeft(rhs) | |
} | |
infix operator &<< { | |
associativity none | |
precedence 160 | |
} | |
/** shift left with bits truncation */ | |
func &<< (lhs: Int, rhs: Int) -> Int { | |
var l = lhs; | |
l.shiftLeft(rhs) | |
return l | |
} | |
// Right operator | |
infix operator &>>= { | |
associativity none | |
precedence 160 | |
} | |
/** shift right and assign with bits truncation */ | |
func &>>= (inout lhs: Int, rhs: Int) { | |
lhs.shiftRight(rhs) | |
} | |
infix operator &>> { | |
associativity none | |
precedence 160 | |
} | |
/** shift right and assign with bits truncation */ | |
func &>> (lhs: Int, rhs: Int) -> Int { | |
var l = lhs; | |
l.shiftRight(rhs) | |
return l | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment