my first protocol


(Frank Swarbrick) #1

I am aware of the OptionSet protocol, that is used to represent a
"mathematical bit set". But I found it too be a bit "too much" for a simple
bitmap. So I created my own, called RawBits. This is the first protocol
I've written in Swift, so I'd be interested in any constructive criticism
anyone might have.

Thanks!

extension String {

    public func pad(with padding: Character, toLength length: Int) -> String
{

        let paddingWidth = length - self.count

        guard 0 < paddingWidth else { return self }

        return String(repeating: padding, count: paddingWidth) + self

    }

}

extension Bool: ExpressibleByIntegerLiteral {

    public init(integerLiteral value: Int) {

        self = value != 0

    }

}

public enum Bit: Bool {

    case off = 0

    case on = 1

}

public protocol RawBits: RawRepresentable, CustomStringConvertible {

    associatedtype Element = Self

    init(rawValue: RawValue)

}

extension RawBits {

    public init(_ rawValue: RawValue) {

        self.init(rawValue: rawValue)

    }

}

extension RawBits where RawValue: FixedWidthInteger, RawValue:
UnsignedInteger {

    public init() {

        self.init(rawValue: 0)

    }

    public func asRadix(_ radix: Int) -> String {

        let s = String(self.rawValue, radix: radix, uppercase: true)

        var x: Int

        switch radix {

        case 16: x = 4

        case 2: x = 1

        default: x = 0

        }

        return x == 0 ? s : s.pad(with: "0", toLength: rawValue.bitWidth /
x)

    }

    public var asBinary: String { return asRadix(2) }

    public var asDecimal: String { return asRadix(10) }

    public var asHex: String { return asRadix(16) }

    public var description: String { return asBinary }

    public var bitWidth: Int { return rawValue.bitWidth }

    private func rangeCheck(_ bit: UInt) {

        guard bit < rawValue.bitWidth else { fatalError("Index out of
range") }

    }

    public func get(bit: UInt) -> Bool {

        rangeCheck(bit)

        return (rawValue >> bit) & 1 == 1

    }

    public func setOn(bit: UInt) -> RawValue {

        rangeCheck(bit)

        return rawValue | 1 << bit

    }

    public func setOff(bit: UInt) -> RawValue {

        rangeCheck(bit)

        return rawValue & ~(1 << bit)

    }

    public subscript(x: UInt) -> Bit {

        get { return Bit(rawValue: get(bit: x))! }

        set { self = Self(newValue == .on ? setOn(bit: x) : setOff(bit: x))
}

    }

}

struct RawBits64: RawBits {

    let rawValue: UInt64

}

var bitmap = RawBits64(0xF33AC401A8E08062)

print(bitmap.bitWidth)

print(bitmap)

print(bitmap.asHex)

print(bitmap.asDecimal)

bitmap[0] = Bit.on

print(bitmap[0])

print(bitmap)

print(bitmap.asHex)

bitmap[0] = Bit.off

print(bitmap[0])

print(bitmap)

bitmap[7] = .on

print(bitmap[7])

print(bitmap)

bitmap[7] = .off

print(bitmap[7])

print(bitmap)

bitmap[63] = .off

print(bitmap)

#if OOR

    print(bitmap[64]) // fatal error, out of range

#endif