๐Ÿ–ผ๏ธBinaryBitPatternView

โฌ†๏ธ ้œ€่ฆ๏ผš .binary(digits:)

// 2022.02.12 / (no wrap)  apply .fixedSize() to all `Text`s 
//            + (refactor) .bitsView()
//            / (refactor) .nowrapText() + `modify` closure

import SwiftUI

// T: BinaryFloatingPoint & CustomStringConvertible
struct BinaryBitPatternView<T: BinaryFloatingPoint>: View where T: CustomStringConvertible {
    
    // (binary) floating-point number
    let x: T                            // variable
    var optionalName: String? = nil     // optional variable name
    
    // view body
    var body: some View {
        
        let t = type(of: x)
        let sign = x.sign == .plus ? "+" : "-"
        let signBit = x.sign == .plus ? "0" : "1"
        
        // ๐ŸŒ€BinaryInteger + .binary(digits:)
        // integer -> array of bits ([string])
        let exp = x.exponentBitPattern.binary(digits: t.exponentBitCount)
        let significand = x.significandBitPattern.binary(digits: t.significandBitCount)
        
        // container view
        VStack(spacing: 8) {
            
            // title
            HStack(alignment: .firstTextBaseline, spacing: 24) {
                let bits = 1 + t.exponentBitCount + t.significandBitCount
                nowrapText("\(t)") { $0.font(.largeTitle).bold() }
                nowrapText("floating-point representation", .secondary)
                nowrapText("(\(bits)-bit)")
            }
            
            // floating-point representation
            HStack(alignment: .top, spacing: 1) {
                // sign bit
                bitsView([signBit], "\(sign)", .pink)
                // exponent bits
                bitsView(exp, "exponent (\(t.exponentBitCount)-bit)", .blue)
                // significand bits
                bitsView(significand, "significand (\(t.significandBitCount)-bit)", .green)
            }
            
            // calculation
            HStack() {
                
                // variable name (optional view)
                // name = 
                optionalName.map { name in
                    HStack {
                        nowrapText(name, .blue) { $0.bold() }
                        nowrapText("=", .secondary)
                    }
                }
                
                // x = 
                nowrapText(x, .orange)
                nowrapText("=", .secondary)
                
                // (sign) (significand) ร— (radix)^(exponent)
                nowrapText(sign, .purple)
                nowrapText(x.significand)
                nowrapText("ร—", .purple)
                nowrapText(t.radix)
                nowrapText(x.exponent)
                    .scaleEffect(0.6, anchor: .leading)
                    .offset(x: -8, y: -10)
            }
            .padding()
            .border(.pink)
            .padding(.top)
        }
        
    }
}

extension BinaryBitPatternView {
    
    /// a little square view for each bit
    func bit(_ b: String, bg: Color = .green, size: CGFloat = 25) -> some View {
        Text("\(b)").font(.system(.caption, design: .monospaced))
            .foregroundColor(.black)
            .frame(width: size, height: size)
            .background(bg)
            .border(.primary, width: 1)
    }
    
    /// bits view
    func bitsView(_ bits: [String], _ subtitle: String, _ color: Color) -> some View {
        VStack {
            HStack(spacing: 1) {
                ForEach(0..<bits.count) { bit(bits[$0], bg: color) }
            }
            Text(subtitle).fixedSize()    // no wrap
        }
    }
    
    /// no-wrap text
    func nowrapText<T: CustomStringConvertible>(
        _     x: T, 
        _ color: Color          = .primary,
        modify : (Text) -> Text = { $0 }        // text modifier
    ) -> some View {
        modify(Text("\(String(describing: x))"))
            .fixedSize().foregroundColor(color)
    }
    
    /// convenience init
    init(_ x: T, name: String? = nil) { self.init(x: x, optionalName: name) }
}

History

  1. 2022.02.12

Last updated