bitfields.py 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. #!/usr/bin/env python
  2. # License: GPLv3 Copyright: 2025, Kovid Goyal <kovid at kovidgoyal.net>
  3. import os
  4. from typing import NamedTuple
  5. class BitField(NamedTuple):
  6. name: str
  7. bits: int
  8. def typename_for_bitsize(bits: int) -> str:
  9. if bits <= 8:
  10. return 'uint8'
  11. if bits <= 16:
  12. return 'uint16'
  13. if bits <= 32:
  14. return 'uint32'
  15. return 'uint64'
  16. def make_bitfield(dest: str, typename: str, *fields_: str, add_package: bool = True) -> tuple[str, str]:
  17. output_path = os.path.join(dest, f'{typename.lower()}_generated.go')
  18. ans = [f'package {os.path.basename(dest)}', '']
  19. a = ans.append
  20. if not add_package:
  21. del ans[0]
  22. def fieldify(spec: str) -> BitField:
  23. name, num = spec.partition(' ')[::2]
  24. return BitField(name, int(num))
  25. fields = tuple(map(fieldify, fields_))
  26. total_size = sum(x.bits for x in fields)
  27. if total_size > 64:
  28. raise ValueError(f'Total size of bit fields: {total_size} for {typename} is larger than 64 bits')
  29. a(f'// Total number of bits used: {total_size}')
  30. itype = typename_for_bitsize(total_size)
  31. a(f'type {typename} {itype}')
  32. a('')
  33. shift = 0
  34. for bf in reversed(fields):
  35. tn = typename_for_bitsize(bf.bits)
  36. mask = '0b' + '1' * bf.bits
  37. a(f'func (s {typename}) {bf.name.capitalize()}() {tn} {{') # }}
  38. if shift:
  39. a(f' return {tn}((s >> {shift}) & {mask})')
  40. else:
  41. a(f' return {tn}(s & {mask})')
  42. a('}')
  43. a('')
  44. a(f'func (s *{typename}) Set_{bf.name}(val {tn}) {{') # }}
  45. if shift:
  46. a(f' *s &^= {mask} << {shift}')
  47. a(f' *s |= {typename}(val&{mask}) << {shift}')
  48. else:
  49. a(f' *s &^= {mask}')
  50. a(f' *s |= {typename}(val & {mask})')
  51. a('}')
  52. a('')
  53. shift += bf.bits
  54. return output_path, '\n'.join(ans)