Skip to content

Instantly share code, notes, and snippets.

@krzyzanowskim
Last active May 30, 2018 03:36
Show Gist options
  • Save krzyzanowskim/c84d039d1542c1a82731 to your computer and use it in GitHub Desktop.
Save krzyzanowskim/c84d039d1542c1a82731 to your computer and use it in GitHub Desktop.
integerWithBytes Swift way
// 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?
@mplewis
Copy link

mplewis commented Mar 4, 2015

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.

@krzyzanowskim
Copy link
Author

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.

@prashantjv
Copy link

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

@gpongelli
Copy link

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.

@lilyball
Copy link

lilyball commented Jan 4, 2016

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 })
}

@JuanPabloBoero
Copy link

@kballard , could you please elaborate on how to use that function with a practical example please?

@jcampbell05
Copy link

@Nobody1707
Copy link

Nobody1707 commented Oct 18, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment