rodutils.nim 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2012 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## Serialization utilities for the compiler.
  10. import strutils
  11. proc c_sprintf(buf, frmt: cstring) {.importc: "sprintf", header: "<stdio.h>", nodecl, varargs.}
  12. proc toStrMaxPrecision*(f: BiggestFloat, literalPostfix = ""): string =
  13. if f != f:
  14. result = "NAN"
  15. elif f == 0.0:
  16. result = "0.0" & literalPostfix
  17. elif f == 0.5 * f:
  18. if f > 0.0: result = "INF"
  19. else: result = "-INF"
  20. else:
  21. var buf: array[0..80, char]
  22. c_sprintf(buf, "%#.16e" & literalPostfix, f)
  23. result = $buf
  24. proc encodeStr*(s: string, result: var string) =
  25. for i in countup(0, len(s) - 1):
  26. case s[i]
  27. of 'a'..'z', 'A'..'Z', '0'..'9', '_': add(result, s[i])
  28. else: add(result, '\\' & toHex(ord(s[i]), 2))
  29. proc hexChar(c: char, xi: var int) =
  30. case c
  31. of '0'..'9': xi = (xi shl 4) or (ord(c) - ord('0'))
  32. of 'a'..'f': xi = (xi shl 4) or (ord(c) - ord('a') + 10)
  33. of 'A'..'F': xi = (xi shl 4) or (ord(c) - ord('A') + 10)
  34. else: discard
  35. proc decodeStr*(s: cstring, pos: var int): string =
  36. var i = pos
  37. result = ""
  38. while true:
  39. case s[i]
  40. of '\\':
  41. inc(i, 3)
  42. var xi = 0
  43. hexChar(s[i-2], xi)
  44. hexChar(s[i-1], xi)
  45. add(result, chr(xi))
  46. of 'a'..'z', 'A'..'Z', '0'..'9', '_':
  47. add(result, s[i])
  48. inc(i)
  49. else: break
  50. pos = i
  51. const
  52. chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
  53. # since negative numbers require a leading '-' they use up 1 byte. Thus we
  54. # subtract/add `vintDelta` here to save space for small negative numbers
  55. # which are common in ROD files:
  56. const
  57. vintDelta = 5
  58. template encodeIntImpl(self) =
  59. var d: char
  60. var v = x
  61. var rem = v mod 190
  62. if rem < 0:
  63. add(result, '-')
  64. v = - (v div 190)
  65. rem = - rem
  66. else:
  67. v = v div 190
  68. var idx = int(rem)
  69. if idx < 62: d = chars[idx]
  70. else: d = chr(idx - 62 + 128)
  71. if v != 0: self(v, result)
  72. add(result, d)
  73. proc encodeVBiggestIntAux(x: BiggestInt, result: var string) =
  74. ## encode a biggest int as a variable length base 190 int.
  75. encodeIntImpl(encodeVBiggestIntAux)
  76. proc encodeVBiggestInt*(x: BiggestInt, result: var string) =
  77. ## encode a biggest int as a variable length base 190 int.
  78. encodeVBiggestIntAux(x +% vintDelta, result)
  79. # encodeIntImpl(encodeVBiggestInt)
  80. proc encodeVIntAux(x: int, result: var string) =
  81. ## encode an int as a variable length base 190 int.
  82. encodeIntImpl(encodeVIntAux)
  83. proc encodeVInt*(x: int, result: var string) =
  84. ## encode an int as a variable length base 190 int.
  85. encodeVIntAux(x +% vintDelta, result)
  86. template decodeIntImpl() =
  87. var i = pos
  88. var sign = - 1
  89. assert(s[i] in {'a'..'z', 'A'..'Z', '0'..'9', '-', '\x80'..'\xFF'})
  90. if s[i] == '-':
  91. inc(i)
  92. sign = 1
  93. result = 0
  94. while true:
  95. case s[i]
  96. of '0'..'9': result = result * 190 - (ord(s[i]) - ord('0'))
  97. of 'a'..'z': result = result * 190 - (ord(s[i]) - ord('a') + 10)
  98. of 'A'..'Z': result = result * 190 - (ord(s[i]) - ord('A') + 36)
  99. of '\x80'..'\xFF': result = result * 190 - (ord(s[i]) - 128 + 62)
  100. else: break
  101. inc(i)
  102. result = result * sign -% vintDelta
  103. pos = i
  104. proc decodeVInt*(s: cstring, pos: var int): int =
  105. decodeIntImpl()
  106. proc decodeVBiggestInt*(s: cstring, pos: var int): BiggestInt =
  107. decodeIntImpl()
  108. iterator decodeVIntArray*(s: cstring): int =
  109. var i = 0
  110. while s[i] != '\0':
  111. yield decodeVInt(s, i)
  112. if s[i] == ' ': inc i
  113. iterator decodeStrArray*(s: cstring): string =
  114. var i = 0
  115. while s[i] != '\0':
  116. yield decodeStr(s, i)
  117. if s[i] == ' ': inc i