1

I am writing an iOS app in Swift. My class has below functions for reading bytebuffer. Below all functions do same task but work on different number types. So, how to convert these functions into a single function using generics?

var array = [UInt8]()
private var currentIndex: Int = 0
private let hostEndianness: Endianness = OSHostByteOrder() == OSLittleEndian ? .little : .big
private var currentEndianness: Endianness = .big
  
public func getUInt16() -> UInt16 {
        let check=(currentIndex + MemoryLayout<UInt16>.size) - 1
        if array.indices.contains(check){
            let result = from(Array(array[currentIndex..<currentIndex + MemoryLayout<UInt16>.size]), UInt16.self)
            currentIndex += MemoryLayout<UInt16>.size
            return result.littleEndian
        }else{
            return 0
        }
    }

    
public func getInt32() -> Int32 {
    let check=(currentIndex + MemoryLayout<Int32>.size) - 1
    if array.indices.contains(check){
        let result = from(Array(array[currentIndex..<currentIndex + MemoryLayout<Int32>.size]), Int32.self)
        currentIndex += MemoryLayout<Int32>.size
        return result.littleEndian
    }else{
        return 0
    }
}

    public func getFloat() -> Float {
       let check=(currentIndex + MemoryLayout<UInt32>.size) - 1
       if array.indices.contains(check){
           let result = from(Array(array[currentIndex..<currentIndex + MemoryLayout<UInt32>.size]), UInt32.self)
           currentIndex += MemoryLayout<UInt32>.size
           return Float(bitPattern: result.littleEndian)
       }else{
           return 0.0
       }
   }

   public func getDouble() -> Double {
    
    let check=(currentIndex + MemoryLayout<UInt64>.size) - 1
    if array.indices.contains(check){
        let result = from(Array(array[currentIndex..<currentIndex + MemoryLayout<UInt64>.size]), UInt64.self)
        currentIndex += MemoryLayout<UInt64>.size
        return Double(bitPattern: result.bigEndian)
    }else{
        return 0.0
    }
}

The only difference in the above functions is types: Float, double, UInt16, Int32.

From Function:

private func from<T>(_ value: [UInt8], _: T.Type) -> T {
        return value.withUnsafeBytes {
            $0.load(fromByteOffset: 0, as: T.self)
        }
    }

My Solution:

    public func getNumber<T:Numeric>() -> T {
    let check=(currentIndex + MemoryLayout<T>.size) - 1
    if array.indices.contains(check){
        let result = from(Array(array[currentIndex..<currentIndex + MemoryLayout<T>.size]), T.self)
        currentIndex += MemoryLayout<T>.size
        return result.bigEndian
    }else{
        return 0
    }
}

Error:

Value of type 'T' has no member 'bigEndian'

S A
  • 29
  • 1
  • 4
  • You need to [edit] your question to include all relevant code in the form of a [mcve]. What's `from`? What's `currentEndianness`? – Dávid Pásztor Jul 28 '20 at 14:15
  • 1
    Also add your own attempt at solving this. – Joakim Danielson Jul 28 '20 at 14:16
  • @DávidPásztor done – S A Jul 28 '20 at 14:17
  • @SA that code still does not compile. What's `Endianness`? Where's the `from` method declared? – Dávid Pásztor Jul 28 '20 at 14:24
  • @DávidPásztor. Added from the method. littleEndian and bigEndian are already in Swift SDK Integer – S A Jul 28 '20 at 14:26
  • @JoakimDanielson, done. added my solution but i am getting error, Value of type 'T' has no member 'bigEndian' – S A Jul 28 '20 at 14:32
  • @SA Only integers have bigEndian property – Leo Dabus Jul 28 '20 at 14:38
  • @LeoDabus, does Float, double, UInt16 and Int32 come under 'Integer'? also, if I try , it shows Use of undeclared type 'Integer' – S A Jul 28 '20 at 14:41
  • You can use `FixedWidthInteger` protocol https://developer.apple.com/documentation/swift/fixedwidthinteger thats where bigEndian property is declared – Leo Dabus Jul 28 '20 at 14:41
  • @LeoDabus, FixedWidthInteger includes Float, double, UInt16 and Int32 ? – S A Jul 28 '20 at 14:44
  • Only integers. Double and float are FloatingPoint types – Leo Dabus Jul 28 '20 at 14:45
  • This might help. https://stackoverflow.com/a/43244973/2303865 I don't know if the endianness will fit your purpose – Leo Dabus Jul 28 '20 at 14:46
  • @LeoDabus but double and float have bigEndian property as: DOUBLE.bitPattern.bigEndian, FLOAT.bitPattern.bigEndian – S A Jul 28 '20 at 14:59
  • @SA the default is littleEndian you can always reverse the byte order before initializing your numeric type – Leo Dabus Jul 28 '20 at 15:02
  • the .bigEndian property is on its integer representation (UInt64) not on Double itself – Leo Dabus Jul 28 '20 at 15:04
  • "The only difference in the above functions is types: Float, double, UInt16, Int32." - that's clearly NOT the only difference. You're using `UInt64`/`UInt32` for `Double`/`Float`, and the return statement is different. Not sure whether it's a copy-paste bug, but you're also using sometimes `.littleEndian` and sometimes `.bigEndian`. Generics might not be what you need here – New Dev Jul 28 '20 at 16:26

0 Answers0