[swift-evolution] [Proposal] Introduces endianness specific type

Susan Cheng susan.doggie at gmail.com
Mon Jul 10 07:21:23 CDT 2017


Thanks, but we can implement Codable for BEInteger and LEInteger types.


public struct BEInteger<BitPattern : FixedWidthInteger> : FixedWidthInteger
{



    public var bitPattern: BitPattern



    public init(bitPattern: BitPattern)



    public var bigEndian: BEInteger { get }



    public var littleEndian: LEInteger<BitPattern> { get }

}


public struct LEInteger<BitPattern : FixedWidthInteger> : FixedWidthInteger
{



    public var bitPattern: BitPattern



    public init(bitPattern: BitPattern)



    public var bigEndian: BEInteger<BitPattern> { get }



    public var littleEndian: LEInteger { get }

}


extension BEInteger : Encodable where BitPattern : Encodable {



    public func encode(to encoder: Encoder) throws {

        try self.bitPattern.encode(to: encoder)

    }

}


extension BEInteger : Decodable where BitPattern : Decodable {



    public init(from decoder: Decoder) throws {

        self.init(bitPattern: try BitPattern(from: decoder))

    }

}


extension LEInteger : Encodable where BitPattern : Encodable {



    public func encode(to encoder: Encoder) throws {

        try self.bitPattern.encode(to: encoder)

    }

}


extension LEInteger : Decodable where BitPattern : Decodable {



    public init(from decoder: Decoder) throws {

        self.init(bitPattern: try BitPattern(from: decoder))

    }

}


2017-07-09 0:27 GMT+08:00 Chris Lattner <clattner at nondot.org>:

> Hi Susan,
>
> Swift does not currently specify a layout for Swift structs.  You
> shouldn’t be using them for memory mapped i/o or writing to a file, because
> their layout can change.  When ABI stability for fragile structs lands, you
> will be able to count on it, but until then something like this is probably
> a bad idea.
>
> -Chris
>
> On Jul 7, 2017, at 6:16 PM, Susan Cheng via swift-evolution <
> swift-evolution at swift.org> wrote:
>
> Here are two problems being fixed.
>
> First, considering the example:
>
> struct MyRawDataStruct {
>
>       var size: UInt32
>       var signature: UInt32
>       var width: UInt32
>       var height: UInt32
> }
>
> The type UInt32 doesn't tall us the endianness of the value. Also, if we
> read the value of it, the value is being byte-swapped when endianness is
> not matching with the system.
>
> This causes us have to manual convert the value from/to correct endianness.
>
> struct MyRawDataStruct {
>
>       var size: BEInteger<UInt32>
>       var signature: BEInteger<UInt32>
>       var width: BEInteger<UInt32>
>       var height: BEInteger<UInt32>
> }
>
> So, my proposal fix the problem. We can easily to get the value.
>
> let header: MyRawDataStruct = data.withUnsafePointer { $0.pointee }
>
> print(header.size)      // print the representing value
>
> Second, it's misleading means of bigEndian and littleEndian from
> FixedWidthInteger
>
> if we do this
>
> let a = 1
>
> print(a.bigEndian.bigEndian)
>
> It's just swap bytes twice but not converting value to big-endian
>
> My proposal solves the problem
>
> let b = a.bigEndian       //    BEInteger<Int>
>
> b.bigEndian        // remain big-endian of a
>
> Max Moiseev <moiseev at apple.com> 於 2017年7月8日 上午1:48 寫道:
>
> Hi Susan,
>
> Was there any motivation for this proposal that I missed? If not then, can
> you please provide it in a few sentences? Otherwise it’s not clear to me
> what problem it is supposed to fix.
>
> Thanks,
> Max
>
>
> On Jul 6, 2017, at 8:21 PM, Susan Cheng via swift-evolution <
> swift-evolution at swift.org> wrote:
>
> IMO, it has unclear representation when FixedWidthInteger working with
> endianness specific type.
>
> so I want to introduce the endianness specific wrapper:
>
> public struct BEInteger<Base : FixedWidthInteger> : FixedWidthInteger {
>
>     public var bigEndian: BEInteger { get }
>
>     public var littleEndian: LEInteger<Base> { get }
> }
>
> public struct LEInteger<Base : FixedWidthInteger> : FixedWidthInteger {
>
>     public var bigEndian: BEInteger<Base> { get }
>
>     public var littleEndian: LEInteger { get }
> }
>
> also, we should change the FixedWidthInteger as follow:
>
> public protocol FixedWidthInteger : BinaryInteger {
>
>     /// deprecated, we should use value.bigEndian instead
>     init(bigEndian value: Self)
>
>     /// deprecated, we should use value.littleEndian instead
>     init(littleEndian value: Self)
>
>     associatedtype EndianRepresentingValue : FixedWidthInteger
>
>     var bigEndian: BEInteger<EndianRepresentingValue> { get }
>
>     var littleEndian: LEInteger<EndianRepresentingValue> { get }
>
> }
>
> =============================
>
> this is my working alternative implementation:
>
>
> @_versioned
> protocol EndianInteger : FixedWidthInteger {
>
>     associatedtype BitPattern : FixedWidthInteger
>
>     associatedtype RepresentingValue : FixedWidthInteger
>
>     var bitPattern: BitPattern { get }
>
>     init(bitPattern: BitPattern)
>
>     var representingValue : RepresentingValue { get set }
>
>     init(representingValue: RepresentingValue)
> }
>
> extension EndianInteger {
>
>     @_transparent
>     public init(integerLiteral value: RepresentingValue.IntegerLiteralType)
> {
>         self.init(representingValue: RepresentingValue(integerLiteral:
> value))
>     }
>
>     @_transparent
>     public init?<T>(exactly source: T) where T : BinaryInteger {
>         guard let value = RepresentingValue(exactly: source) else { return
>  nil }
>         self.init(representingValue: value)
>     }
>
>     @_transparent
>     public init?<T>(exactly source: T) where T : FloatingPoint {
>         guard let value = RepresentingValue(exactly: source) else { return
>  nil }
>         self.init(representingValue: value)
>     }
>
>     @_transparent
>     public init(_ value: RepresentingValue) {
>         self.init(representingValue: value)
>     }
>
>     @_transparent
>     public init<T>(_ source: T) where T : FloatingPoint {
>         self.init(representingValue: RepresentingValue(source))
>     }
>
>     @_transparent
>     public init<T>(_ source: T) where T : BinaryInteger {
>         self.init(representingValue: RepresentingValue(source))
>     }
>
>     @_transparent
>     public init<T>(extendingOrTruncating source: T) where T : BinaryInt
> eger {
>         self.init(representingValue: RepresentingValue(extendingOrTruncating:
> source))
>     }
>
>     @_transparent
>     public init<T>(clamping source: T) where T : BinaryInteger {
>         self.init(representingValue: RepresentingValue(clamping: source))
>     }
>
>     @_transparent
>     public init(_truncatingBits bits: UInt) {
>         self.init(representingValue: RepresentingValue(_truncatingBits:
> bits))
>     }
> }
>
> extension EndianInteger {
>
>     @_transparent
>     public static var isSigned: Bool {
>         return RepresentingValue.isSigned
>     }
>
>     @_transparent
>     public static var bitWidth: Int {
>         return RepresentingValue.bitWidth
>     }
>
>     @_transparent
>     public static var max: Self {
>         return Self(representingValue: RepresentingValue.max)
>     }
>
>     @_transparent
>     public static var min: Self {
>         return Self(representingValue: RepresentingValue.min)
>     }
> }
>
> extension EndianInteger {
>
>     @_transparent
>     public var hashValue: Int {
>         return representingValue.hashValue
>     }
>
>     @_transparent
>     public var description: String {
>         return representingValue.description
>     }
>
>     @_transparent
>     public var bitWidth: Int {
>         return representingValue.bitWidth
>     }
>
>     @_transparent
>     public var magnitude: RepresentingValue.Magnitude {
>         return representingValue.magnitude
>     }
>
>     @_transparent
>     public var trailingZeroBitCount: Int {
>         return representingValue.trailingZeroBitCount
>     }
>
>     @_transparent
>     public var nonzeroBitCount: Int {
>         return representingValue.nonzeroBitCount
>     }
>
>     @_transparent
>     public var leadingZeroBitCount: Int {
>         return representingValue.leadingZeroBitCount
>     }
>
>     @_transparent
>     public var byteSwapped: Self {
>         return Self(representingValue: representingValue.byteSwapped)
>     }
> }
>
> extension EndianInteger {
>
>     @_transparent
>     public func _word(at n: Int) -> UInt {
>         return representingValue._word(at: n)
>     }
>
>     @_transparent
>     public func distance(to other: Self) -> RepresentingValue.Stride {
>         return self.representingValue.distance(to: other.representingValue
> )
>     }
>
>     @_transparent
>     public func advanced(by n: RepresentingValue.Stride) -> Self {
>         return Self(representingValue: self.representingValue.advanced(by:
> n))
>     }
>
>     @_transparent
>     public func addingReportingOverflow(_ rhs: Self) -> (partialValue:
> Self, overflow: ArithmeticOverflow) {
>         let (partialValue, overflow) = representingValue.addingRepo
> rtingOverflow(rhs.representingValue)
>         return (Self(representingValue: partialValue), overflow)
>     }
>
>     @_transparent
>     public func subtractingReportingOverflow(_ rhs: Self) ->
> (partialValue: Self, overflow: ArithmeticOverflow) {
>         let (partialValue, overflow) = representingValue.subtractin
> gReportingOverflow(rhs.representingValue)
>         return (Self(representingValue: partialValue), overflow)
>     }
>
>     @_transparent
>     public func multipliedReportingOverflow(by rhs: Self) ->
> (partialValue: Self, overflow: ArithmeticOverflow) {
>         let (partialValue, overflow) = representingValue.multiplied
> ReportingOverflow(by: rhs.representingValue)
>         return (Self(representingValue: partialValue), overflow)
>     }
>
>     @_transparent
>     public func dividedReportingOverflow(by rhs: Self) -> (partialValue:
> Self, overflow: ArithmeticOverflow) {
>         let (partialValue, overflow) = representingValue.dividedRep
> ortingOverflow(by: rhs.representingValue)
>         return (Self(representingValue: partialValue), overflow)
>     }
>
>     @_transparent
>     public func remainderReportingOverflow(dividingBy rhs: Self) ->
> (partialValue: Self, overflow: ArithmeticOverflow) {
>         let (partialValue, overflow) = representingValue.remainderR
> eportingOverflow(dividingBy: rhs.representingValue)
>         return (Self(representingValue: partialValue), overflow)
>     }
>
>     @_transparent
>     public func multipliedFullWidth(by other: Self) -> (high: Self, low:
> RepresentingValue.Magnitude) {
>         let (high, low) = representingValue.multipliedFullWidth(by: other.
> representingValue)
>         return (Self(representingValue: high), low)
>     }
>
>     @_transparent
>     public func dividingFullWidth(_ dividend: (high: Self, low:
> RepresentingValue.Magnitude)) -> (quotient: Self, remainder: Self) {
>         let (quotient, remainder) = representingValue.dividingFullWidth
> ((dividend.high.representingValue, dividend.low))
>         return (Self(representingValue: quotient), Self(representingValue:
> remainder))
>     }
> }
>
> extension EndianInteger {
>
>     @_transparent
>     public static prefix func +(x: Self) -> Self {
>         return x
>     }
>
>     @_transparent
>     public static func +(lhs: Self, rhs: Self) -> Self {
>         return Self(representingValue: lhs.representingValue + rhs.
> representingValue)
>     }
>
>     @_transparent
>     public static func +=(lhs: inout Self, rhs: Self) {
>         lhs.representingValue += rhs.representingValue
>     }
>
>     @_transparent
>     public static func -(lhs: Self, rhs: Self) -> Self {
>         return Self(representingValue: lhs.representingValue - rhs.
> representingValue)
>     }
>
>     @_transparent
>     public static func -=(lhs: inout Self, rhs: Self) {
>         lhs.representingValue -= rhs.representingValue
>     }
>
>     @_transparent
>     public static func *(lhs: Self, rhs: Self) -> Self {
>         return Self(representingValue: lhs.representingValue * rhs.
> representingValue)
>     }
>
>     @_transparent
>     public static func *=(lhs: inout Self, rhs: Self) {
>         lhs.representingValue *= rhs.representingValue
>     }
>
>     @_transparent
>     public static func /(lhs: Self, rhs: Self) -> Self {
>         return Self(representingValue: lhs.representingValue / rhs.
> representingValue)
>     }
>
>     @_transparent
>     public static func /=(lhs: inout Self, rhs: Self) {
>         lhs.representingValue /= rhs.representingValue
>     }
>
>     @_transparent
>     public static func %(lhs: Self, rhs: Self) -> Self {
>         return Self(representingValue: lhs.representingValue % rhs.
> representingValue)
>     }
>
>     @_transparent
>     public static func %=(lhs: inout Self, rhs: Self) {
>         lhs.representingValue %= rhs.representingValue
>     }
>
>     @_transparent
>     public static func &(lhs: Self, rhs: Self) -> Self {
>         return Self(representingValue: lhs.representingValue & rhs.
> representingValue)
>     }
>
>     @_transparent
>     public static func &=(lhs: inout Self, rhs: Self) {
>         lhs.representingValue &= rhs.representingValue
>     }
>
>     @_transparent
>     public static func |(lhs: Self, rhs: Self) -> Self {
>         return Self(representingValue: lhs.representingValue | rhs.
> representingValue)
>     }
>
>     @_transparent
>     public static func |=(lhs: inout Self, rhs: Self) {
>         lhs.representingValue |= rhs.representingValue
>     }
>
>     @_transparent
>     public static func ^(lhs: Self, rhs: Self) -> Self {
>         return Self(representingValue: lhs.representingValue ^ rhs.
> representingValue)
>     }
>
>     @_transparent
>     public static func ^=(lhs: inout Self, rhs: Self) {
>         lhs.representingValue ^= rhs.representingValue
>     }
>
>     @_transparent
>     prefix public static func ~(x: Self) -> Self {
>         return Self(representingValue: ~x.representingValue)
>     }
>
>     @_transparent
>     public static func &>>(lhs: Self, rhs: Self) -> Self {
>         return Self(representingValue: lhs.representingValue &>> rhs.
> representingValue)
>     }
>
>     @_transparent
>     public static func &<<(lhs: Self, rhs: Self) -> Self {
>         return Self(representingValue: lhs.representingValue &<< rhs.
> representingValue)
>     }
>
>     @_transparent
>     public static func ==(lhs: Self, rhs: Self) -> Bool {
>         return lhs.bitPattern == rhs.bitPattern
>     }
>
>     @_transparent
>     public static func !=(lhs: Self, rhs: Self) -> Bool {
>         return lhs.bitPattern != rhs.bitPattern
>     }
>
>     @_transparent
>     public static func >(lhs: Self, rhs: Self) -> Bool {
>         return lhs.representingValue > rhs.representingValue
>     }
>
>     @_transparent
>     public static func <(lhs: Self, rhs: Self) -> Bool {
>         return lhs.representingValue < rhs.representingValue
>     }
>
>     @_transparent
>     public static func >=(lhs: Self, rhs: Self) -> Bool {
>         return lhs.representingValue >= rhs.representingValue
>     }
>
>     @_transparent
>     public static func <=(lhs: Self, rhs: Self) -> Bool {
>         return lhs.representingValue <= rhs.representingValue
>     }
> }
>
> public struct BEInteger<Base : FixedWidthInteger> : FixedWidthInteger,
> EndianInteger {
>
>     public var bitPattern: Base
>
>     @_transparent
>     public init(bitPattern: Base) {
>         self.bitPattern = bitPattern
>     }
>
>     @_versioned
>     @_transparent
>     init(representingValue: Base) {
>         self.bitPattern = representingValue.bigEndian
>     }
>
>     @_versioned
>     @_transparent
>     var representingValue: Base {
>         get {
>             return Base(bigEndian: bitPattern)
>         }
>         set {
>             bitPattern = newValue.bigEndian
>         }
>     }
>
>     @_transparent
>     public init(bigEndian value: BEInteger) {
>         self.bitPattern = value.bitPattern
>     }
>
>     @_transparent
>     public init(littleEndian value: BEInteger) {
>         self.bitPattern = value.bitPattern.byteSwapped
>     }
>
>     @_transparent
>     public var bigEndian: BEInteger {
>         return self
>     }
>
>     @_transparent
>     public var littleEndian: BEInteger {
>         return BEInteger(littleEndian: self)
>     }
> }
>
> public struct LEInteger<Base : FixedWidthInteger> : FixedWidthInteger,
> EndianInteger {
>
>     public var bitPattern: Base
>
>     @_transparent
>     public init(bitPattern: Base) {
>         self.bitPattern = bitPattern
>     }
>
>     @_versioned
>     @_transparent
>     init(representingValue: Base) {
>         self.bitPattern = representingValue.littleEndian
>     }
>
>     @_versioned
>     @_transparent
>     var representingValue: Base {
>         get {
>             return Base(littleEndian: bitPattern)
>         }
>         set {
>             bitPattern = newValue.littleEndian
>         }
>     }
>
>     @_transparent
>     public init(bigEndian value: LEInteger) {
>         self.bitPattern = value.bitPattern.byteSwapped
>     }
>
>     @_transparent
>     public init(littleEndian value: LEInteger) {
>         self.bitPattern = value.bitPattern
>     }
>
>     @_transparent
>     public var bigEndian: LEInteger {
>         return LEInteger(bigEndian: self)
>     }
>
>     @_transparent
>     public var littleEndian: LEInteger {
>         return self
>     }
>
> }
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170710/106b85b6/attachment.html>


More information about the swift-evolution mailing list