github.com/tunabay/go-bitarray@v1.3.1/bitarray_format.go (about) 1 // Copyright (c) 2021 Hirotsuna Mizuno. All rights reserved. 2 // Use of this source code is governed by the MIT license that can be found in 3 // the LICENSE file. 4 5 package bitarray 6 7 import ( 8 "bytes" 9 "fmt" 10 "io" 11 ) 12 13 // Format implements the fmt.Formatter interface to format BitArray values using 14 // the standard fmt.Printf family functions. 15 // 16 // Verbs: 17 // %b, %s binary, 1 digit represents 1 bit. 18 // %q quoted version of %b. 19 // %v default format, same as %b. 20 // %o octal, 1 digit represents 3 bits. 21 // %x, %X hexadecimal, 1 digit represents 4 bits. 22 // 23 // Flags: 24 // ' ' (space) print a separator space every 8 digits. 25 // # more separators, ' ' and/or '-' every 4 digits. 26 // - left-justify 27 // + print the number of padding bits at the end, for %o, %x, %X 28 func (ba BitArray) Format(s fmt.State, verb rune) { 29 switch verb { 30 case 'b', 's', 'q': 31 wid, widOK := s.Width() 32 if !widOK { 33 wid = 0 34 } 35 if s.Flag(int('0')) { 36 fmt.Fprintf(s, "%%!%c(ERROR: unsupported flag 0)", verb) 37 break 38 } 39 if err := ba.writeBinStr( 40 s, wid, s.Flag(int(' ')), s.Flag(int('#')), 41 verb == 'q', s.Flag(int('-')), 42 ); err != nil { 43 fmt.Fprintf(s, "%%!%c(ERROR: %v)", verb, err) 44 break 45 } 46 47 case 'v': 48 if s.Flag(int('#')) { 49 fmt.Fprintf(s, "%%!%c(ERROR: unsupported flag #)", verb) 50 break 51 } 52 if err := ba.writeBinStr(s, 0, false, false, false, false); err != nil { 53 fmt.Fprintf(s, "%%!%c(ERROR: %v)", verb, err) 54 break 55 } 56 57 case 'o': 58 wid, widOK := s.Width() 59 if !widOK { 60 wid = 0 61 } 62 if s.Flag(int('0')) { 63 fmt.Fprintf(s, "%%!%c(ERROR: unsupported flag 0)", verb) 64 break 65 } 66 if err := ba.writeOctStr( 67 s, wid, 68 s.Flag(int(' ')), s.Flag(int('#')), 69 s.Flag(int('+')), s.Flag(int('-')), 70 ); err != nil { 71 fmt.Fprintf(s, "%%!%c(ERROR: %v)", verb, err) 72 break 73 } 74 75 case 'x', 'X': 76 wid, widOK := s.Width() 77 if !widOK { 78 wid = 0 79 } 80 if s.Flag(int('0')) { 81 fmt.Fprintf(s, "%%!%c(ERROR: unsupported flag 0)", verb) 82 break 83 } 84 if err := ba.writeHexStr( 85 s, wid, verb == 'X', 86 s.Flag(int(' ')), s.Flag(int('#')), 87 s.Flag(int('+')), s.Flag(int('-')), 88 ); err != nil { 89 fmt.Fprintf(s, "%%!%c(ERROR: %v)", verb, err) 90 break 91 } 92 93 default: 94 fmt.Fprintf(s, "%%!%c(BitArray=", verb) 95 if err := ba.writeBinStr(s, 0, true, true, true, false); err != nil { 96 fmt.Fprintf(s, "(ERROR: %v)", err) 97 } 98 fmt.Fprint(s, ")") 99 } 100 } 101 102 func (ba *BitArray) writeBinStr(wr io.Writer, wid int, sep8, sep4, quote, left bool) error { 103 sep8 = sep8 || sep4 104 sLen := ba.Len() 105 if 0 < ba.nBits && sep8 { 106 n4d := (ba.nBits + 3) >> 2 // num of 1111 107 n8d := (n4d + 1) >> 1 // num of 11111111 108 if sep4 { 109 sLen += n4d - 1 110 } else { 111 sLen += n8d - 1 112 } 113 } 114 if quote { 115 sLen += 2 116 } 117 if wid < sLen { 118 wid = sLen 119 } 120 if !left { 121 if pad := wid - sLen; 0 < pad { 122 if _, err := wr.Write(bytes.Repeat([]byte{' '}, pad)); err != nil { 123 return fmt.Errorf("pad-l: %w", err) 124 } 125 } 126 } 127 if quote { 128 if _, err := wr.Write([]byte{'"'}); err != nil { 129 return fmt.Errorf("quote-l: %w", err) 130 } 131 } 132 octbuf := make([]byte, 9) 133 for i := 0; i < (ba.nBits+7)>>3; i++ { 134 var wb byte 135 if ba.b != nil { 136 wb = ba.b[i] 137 } 138 if sep8 && i != 0 { 139 if _, err := wr.Write([]byte{' '}); err != nil { 140 return fmt.Errorf("oct-sep: %w", err) 141 } 142 } 143 cLSB := 0 // num of LSBs to be cleared 144 if i+1 == (ba.nBits+7)>>3 { // last byte 145 cLSB = ba.NumPadding() 146 } 147 bi := 0 148 for j := 7; cLSB <= j; j-- { 149 if sep4 && j == 3 { 150 octbuf[bi] = byte('-') 151 bi++ 152 } 153 octbuf[bi] = '0' + wb>>j&1 154 bi++ 155 } 156 if _, err := wr.Write(octbuf[:bi]); err != nil { 157 return fmt.Errorf("byte: %d(%d): %w", i, cLSB, err) 158 } 159 } 160 if quote { 161 if _, err := wr.Write([]byte{'"'}); err != nil { 162 return fmt.Errorf("quote-r: %w", err) 163 } 164 } 165 if left { 166 if pad := wid - sLen; 0 < pad { 167 if _, err := wr.Write(bytes.Repeat([]byte{' '}, pad)); err != nil { 168 return fmt.Errorf("pad-r: %w", err) 169 } 170 } 171 } 172 173 return nil 174 } 175 176 func (ba *BitArray) writeOctStr(wr io.Writer, wid int, sep8, sep4, rpad, left bool) error { 177 sep8 = sep8 || sep4 178 ntri, nfrc := ba.nBits/3, ba.nBits%3 // num of 777, and remaining bits 179 if nfrc != 0 { 180 ntri++ 181 } 182 npad := (3 - nfrc) % 3 // num of last padding bits 183 184 sLen := ntri 185 if 0 < ba.nBits && sep8 { 186 n4d := (ntri + 3) >> 2 // num of 7777 187 n8d := (n4d + 1) >> 1 // num of 77777777 188 if sep4 { 189 sLen += n4d - 1 190 } else { 191 sLen += n8d - 1 192 } 193 } 194 if rpad && npad != 0 { // (pad=2) 195 if sep8 { 196 sLen++ 197 } 198 sLen += 7 199 } 200 if wid < sLen { 201 wid = sLen 202 } 203 if !left { 204 if pad := wid - sLen; 0 < pad { 205 if _, err := wr.Write(bytes.Repeat([]byte{' '}, pad)); err != nil { 206 return fmt.Errorf("pad-l: %w", err) 207 } 208 } 209 } 210 211 iby, ibi := 0, 0 // source cursor on ba.b, byte and bit 212 for i := 0; i < ntri; i++ { 213 if sep8 && i != 0 && i&3 == 0 { 214 if i&7 == 0 { 215 if _, err := wr.Write([]byte{' '}); err != nil { 216 return fmt.Errorf("sep8: %w", err) 217 } 218 } else if sep4 { 219 if _, err := wr.Write([]byte{'-'}); err != nil { 220 return fmt.Errorf("sep4: %w", err) 221 } 222 } 223 } 224 var b byte 225 if ba.b != nil { 226 b = ba.b[iby] 227 } 228 rsf := (5 - ibi) 229 if 0 < rsf { 230 b >>= rsf 231 } else { 232 b <<= -rsf 233 } 234 b &= 7 235 ibi += 3 236 if 7 < ibi { 237 iby++ 238 if iby < (ba.nBits+7)>>3 { 239 ibi &= 7 240 if ba.b != nil { 241 b |= ba.b[iby] >> (8 - ibi) & byte(ibi|1) 242 } 243 } 244 } 245 if _, err := wr.Write([]byte{'0' + b}); err != nil { 246 return fmt.Errorf("oct: %w", err) 247 } 248 } 249 if rpad && npad != 0 { // (pad=2) 250 b := []byte{' ', '(', 'p', 'a', 'd', '=', '0' + byte(npad), ')'} 251 if !sep8 { 252 b = b[1:] 253 } 254 if _, err := wr.Write(b); err != nil { 255 return fmt.Errorf("npad: %w", err) 256 } 257 } 258 if left { 259 if pad := wid - sLen; 0 < pad { 260 if _, err := wr.Write(bytes.Repeat([]byte{' '}, pad)); err != nil { 261 return fmt.Errorf("pad-r: %w", err) 262 } 263 } 264 } 265 266 return nil 267 } 268 269 func (ba *BitArray) writeHexStr(wr io.Writer, wid int, upper, sep8, sep4, rpad, left bool) error { 270 const ( 271 hexCharsL = "0123456789abcdef" 272 hexCharsU = "0123456789ABCDEF" 273 ) 274 sep8 = sep8 || sep4 275 nnbl := (ba.nBits + 3) >> 2 // num of f 276 npad := ba.NumPadding() & 3 277 sLen := nnbl 278 if 0 < ba.nBits && sep8 { 279 n4d := (nnbl + 3) >> 2 // num of ffff 280 n8d := (n4d + 1) >> 1 // num of ffffffff 281 if sep4 { 282 sLen += n4d - 1 283 } else { 284 sLen += n8d - 1 285 } 286 } 287 if rpad && npad != 0 { // (pad=3) 288 if sep8 { 289 sLen++ 290 } 291 sLen += 7 292 } 293 if wid < sLen { 294 wid = sLen 295 } 296 if !left { 297 if pad := wid - sLen; 0 < pad { 298 if _, err := wr.Write(bytes.Repeat([]byte{' '}, pad)); err != nil { 299 return fmt.Errorf("pad-l: %w", err) 300 } 301 } 302 } 303 hexc := hexCharsL 304 if upper { 305 hexc = hexCharsU 306 } 307 for i := 0; i < nnbl; i++ { 308 if i != 0 && sep8 && i&3 == 0 { 309 if sep4 || i&7 == 0 { 310 if _, err := wr.Write([]byte{' '}); err != nil { 311 return fmt.Errorf("sep: %w", err) 312 } 313 } 314 } 315 boff := 4 ^ i&1<<2 316 var b byte 317 if ba.b != nil { 318 b = ba.b[i>>1] 319 } 320 if _, err := wr.Write([]byte{hexc[b>>boff&0xf]}); err != nil { 321 return fmt.Errorf("nibble: %w", err) 322 } 323 } 324 if rpad && npad != 0 { // (pad=3) 325 b := []byte{' ', '(', 'p', 'a', 'd', '=', '0' + byte(npad), ')'} 326 if !sep8 { 327 b = b[1:] 328 } 329 if _, err := wr.Write(b); err != nil { 330 return fmt.Errorf("npad: %w", err) 331 } 332 } 333 if left { 334 if pad := wid - sLen; 0 < pad { 335 if _, err := wr.Write(bytes.Repeat([]byte{' '}, pad)); err != nil { 336 return fmt.Errorf("pad-r: %w", err) 337 } 338 } 339 } 340 341 return nil 342 }