-
-
Save krzyzanowskim/c84d039d1542c1a82731 to your computer and use it in GitHub Desktop.
// Playground - noun: a place where people can play | |
import Foundation | |
typealias Byte = UInt8 | |
protocol GenericIntegerType: IntegerType { | |
init(_ v: Int) | |
init(_ v: UInt) | |
init(_ v: Int8) | |
init(_ v: UInt8) | |
init(_ v: Int16) | |
init(_ v: UInt16) | |
init(_ v: Int32) | |
init(_ v: UInt32) | |
init(_ v: Int64) | |
init(_ v: UInt64) | |
} | |
protocol GenericSignedIntegerBitPattern { | |
init(bitPattern: UIntMax) | |
init(truncatingBitPattern: IntMax) | |
} | |
protocol GenericUnsignedIntegerBitPattern { | |
init(truncatingBitPattern: UIntMax) | |
} | |
extension Int:GenericIntegerType, GenericSignedIntegerBitPattern { | |
init(bitPattern: UIntMax) { | |
self.init(bitPattern: UInt(truncatingBitPattern: bitPattern)) | |
} | |
} | |
extension UInt:GenericIntegerType, GenericUnsignedIntegerBitPattern {} | |
extension Int8:GenericIntegerType, GenericSignedIntegerBitPattern { | |
init(bitPattern: UIntMax) { | |
self.init(bitPattern: UInt8(truncatingBitPattern: bitPattern)) | |
} | |
} | |
extension UInt8:GenericIntegerType, GenericUnsignedIntegerBitPattern {} | |
extension Int16:GenericIntegerType, GenericSignedIntegerBitPattern { | |
init(bitPattern: UIntMax) { | |
self.init(bitPattern: UInt16(truncatingBitPattern: bitPattern)) | |
} | |
} | |
extension UInt16:GenericIntegerType, GenericUnsignedIntegerBitPattern {} | |
extension Int32:GenericIntegerType, GenericSignedIntegerBitPattern { | |
init(bitPattern: UIntMax) { | |
self.init(bitPattern: UInt32(truncatingBitPattern: bitPattern)) | |
} | |
} | |
extension UInt32:GenericIntegerType, GenericUnsignedIntegerBitPattern {} | |
extension Int64:GenericIntegerType, GenericSignedIntegerBitPattern { | |
// init(bitPattern: UInt64) already defined | |
init(truncatingBitPattern: IntMax) { | |
self.init(truncatingBitPattern) | |
} | |
} | |
extension UInt64:GenericIntegerType, GenericUnsignedIntegerBitPattern { | |
// init(bitPattern: Int64) already defined | |
init(truncatingBitPattern: UIntMax) { | |
self.init(truncatingBitPattern) | |
} | |
} | |
func integerWithBytes<T: GenericIntegerType where T: UnsignedIntegerType, T: GenericUnsignedIntegerBitPattern>(bytes:[UInt8]) -> T? { | |
if (bytes.count < sizeof(T)) { | |
return nil | |
} | |
let maxBytes = sizeof(T) | |
var i:UIntMax = 0 | |
for (var j = 0; j < maxBytes; j++) { | |
i = i | T(bytes[j]).toUIntMax() << UIntMax(j * 8) | |
} | |
return T(truncatingBitPattern: i) | |
} | |
func integerWithBytes<T: GenericIntegerType where T: SignedIntegerType, T: GenericSignedIntegerBitPattern>(bytes:[UInt8]) -> T? { | |
if (bytes.count < sizeof(T)) { | |
return nil | |
} | |
let maxBytes = sizeof(T) | |
var i:IntMax = 0 | |
for (var j = 0; j < maxBytes; j++) { | |
i = i | T(bitPattern: UIntMax(bytes[j].toUIntMax())).toIntMax() << (j * 8).toIntMax() | |
} | |
return T(truncatingBitPattern: i) | |
} | |
let bytes:[UInt8] = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF] | |
integerWithBytes(bytes) as Int8? | |
integerWithBytes(bytes) as UInt8? | |
integerWithBytes(bytes) as Int16? | |
integerWithBytes(bytes) as UInt16? | |
integerWithBytes(bytes) as Int32? | |
integerWithBytes(bytes) as UInt32? | |
integerWithBytes(bytes) as Int64? | |
integerWithBytes(bytes) as UInt64? |
Thanks! this is more exercise than anything else, but yes It's worth to know how the things getting complicated when it comes to types.
Hi Krzyzanowskim,
Great effort and useful area through!
I am doing some encryption algorithm and trying to do some shift operation using swift 2.0 like this but it always throws crash error (EXC_BAD_INSTRUCTION). It is a signed number. How to solve this issue, please assist. In Java and C it gives me this number : -2147483646
let n : Int = 10
let s : Int = 2
let sh = (n >> s) | (n << -s) //error
Hi @krzyzanowskim ,
I've found your gist and your blog article very useful, thanks!
While working on some bit representation, I think it's better to change the
T(bytes[j])
to
T(bytes[maxBytes - j - 1])
because the input array does not represent the correct byte order of the returned integer IMHO.
For example, with a decimal number 43605, having this binary representation
1010 1010 0101 0101
I think the correct byte array that integerWithBytes should accept is
[170, 85]
and not the reversed one
[85, 170]
Thank you,
Gabriele.
This is ridiculous. You've apparently gone to great lengths to do this as complicated as possible. It's a hell of a lot simpler just to say
func integerWithBytes<T: IntegerType>(bytes: [UInt8]) -> T? {
guard bytes.count >= sizeof(T) else { return nil }
return bytes.withUnsafeBufferPointer({ UnsafePointer<T>($0.baseAddress).memory })
}
@kballard , could you please elaborate on how to use that function with a practical example please?
I had to do this shudder https://gist.github.com/jcampbell05/f6b5611bd7f61840edb10500fa69fd09
This just works now: http://swift.sandbox.bluemix.net/#/repl/59ed541e3d125e6782506f1e
Thanks for this! Moving bytes between types of integers in Java is hard enough. Just having a reliable conversion module is incredibly helpful for any language.