Recommended way to write conditional compilation for 32- or 64-bit?


(Jens Persson) #1

I need to define some datatypes differently depending on if the target is
32- or 64-bit.
The code should compile on any 32- or 64-bit platform.
Is the following the recommended way to do this?

#if arch(x86_64) || arch(arm64)
    // Define the types, knowing that we're on a 64-bit platform.
#elseif arch(i386) || arch(arm)
    // Define the types, knowing that we're on a 32-bit platform.
#else
    // Is ending up here possible?
#endif

PS
I might as well throw this somewhat related question in here:

What would be a good name for a protocol that is adopted *only* by these
four most primitive/basic types:
UInt8, UInt16, UInt32, UInt64
?
The protocol is called PrimitiveBitPatternProtocol in the code below and
its purpose is something like this:
Every type that can be represented as a sequence of 8, 16, 32 or 64 bits
can be formally associated with one of the above four
PrimitiveBitPatternProtocol-conforming types, so for example the Double
type conforms to PrimitiveBitPatternRepresentable by having UInt64 as its
associated "PrimitiveBitPattern" type.

Or perhaps less confusingly formulated: I would like the following code
(which compiles in Swift 4) to have shorter and better names:

protocol PrimitiveBitPatternProtocol : UnsignedInteger, FixedWidthInteger {}
extension UInt8 : PrimitiveBitPatternProtocol {}
extension UInt16 : PrimitiveBitPatternProtocol {}
extension UInt32 : PrimitiveBitPatternProtocol {}
extension UInt64 : PrimitiveBitPatternProtocol {}

protocol PrimitiveBitPatternRepresentable {
    associatedtype PrimitiveBitPattern: PrimitiveBitPatternProtocol
    init(bitPattern: PrimitiveBitPattern)
    var bitPattern: PrimitiveBitPattern { get }
}

// Double and Float already satisfies the requirements of
// PrimitiveBitPatternRepresentable so:
extension Double : PrimitiveBitPatternRepresentable {}
extension Float : PrimitiveBitPatternRepresentable {}

// Each of the four primitive types is its own PrimitiveBitPattern:
extension UInt8 : PrimitiveBitPatternRepresentable {
    init(bitPattern: UInt8) { self = bitPattern }
    var bitPattern: UInt8 { return self }
}
extension UInt16 : PrimitiveBitPatternRepresentable {
    init(bitPattern: UInt16) { self = bitPattern }
    var bitPattern: UInt16 { return self }
}
extension UInt32 : PrimitiveBitPatternRepresentable {
    init(bitPattern: UInt32) { self = bitPattern }
    var bitPattern: UInt32 { return self }
}
extension UInt64 : PrimitiveBitPatternRepresentable {
    init(bitPattern: UInt64) { self = bitPattern }
    var bitPattern: UInt64 { return self }
}
// And their signed counterparts already have the required init, so we only
// have to add the computed property:
extension Int8 : PrimitiveBitPatternRepresentable {
    var bitPattern: UInt8 { return UInt8(bitPattern: self) }
}
extension Int16 : PrimitiveBitPatternRepresentable {
    var bitPattern: UInt16 { return UInt16(bitPattern: self) }
}
extension Int32 : PrimitiveBitPatternRepresentable {
    var bitPattern: UInt32 { return UInt32(bitPattern: self) }
}
extension Int64 : PrimitiveBitPatternRepresentable {
    var bitPattern: UInt64 { return UInt64(bitPattern: self) }
}
// The platform-dependent Int and UInt:
#if arch(x86_64) || arch(arm64)
extension Int : PrimitiveBitPatternRepresentable {
    init(bitPattern: UInt64) { self = Int(Int64(bitPattern: bitPattern)) }
    var bitPattern: UInt64 { return UInt64(UInt(bitPattern: self)) }
}
extension UInt : PrimitiveBitPatternRepresentable {
    init(bitPattern: UInt64) { self = UInt(bitPattern) }
    var bitPattern: UInt64 { return UInt64(self) }
}
#elseif arch(i386) || arch(arm)
extension Int : PrimitiveBitPatternRepresentable {
    init(bitPattern: UInt32) { self = Int(Int32(bitPattern: bitPattern)) }
    var bitPattern: UInt32 { return UInt32(UInt(bitPattern: self)) }
}
extension UInt : PrimitiveBitPatternRepresentable {
    init(bitPattern: UInt32) { self = UInt(bitPattern) }
    var bitPattern: UInt32 { return UInt32(self) }
}
#endif

/Jens