rodutils.nim 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  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_snprintf(s: cstring; n:uint; frmt: cstring): cint {.importc: "snprintf", 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. when defined(nimNoArrayToCstringConversion):
  22. result = newString(81)
  23. let n = c_snprintf(result.cstring, result.len.uint, "%#.16e%s", f, literalPostfix.cstring)
  24. setLen(result, n)
  25. else:
  26. var buf: array[0..80, char]
  27. discard c_snprintf(buf.cstring, buf.len.uint, "%#.16e%s", f, literalPostfix.cstring)
  28. result = $buf.cstring
  29. proc encodeStr*(s: string, result: var string) =
  30. for i in countup(0, len(s) - 1):
  31. case s[i]
  32. of 'a'..'z', 'A'..'Z', '0'..'9', '_': add(result, s[i])
  33. else: add(result, '\\' & toHex(ord(s[i]), 2))
  34. proc hexChar(c: char, xi: var int) =
  35. case c
  36. of '0'..'9': xi = (xi shl 4) or (ord(c) - ord('0'))
  37. of 'a'..'f': xi = (xi shl 4) or (ord(c) - ord('a') + 10)
  38. of 'A'..'F': xi = (xi shl 4) or (ord(c) - ord('A') + 10)
  39. else: discard
  40. proc decodeStr*(s: cstring, pos: var int): string =
  41. var i = pos
  42. result = ""
  43. while true:
  44. case s[i]
  45. of '\\':
  46. inc(i, 3)
  47. var xi = 0
  48. hexChar(s[i-2], xi)
  49. hexChar(s[i-1], xi)
  50. add(result, chr(xi))
  51. of 'a'..'z', 'A'..'Z', '0'..'9', '_':
  52. add(result, s[i])
  53. inc(i)
  54. else: break
  55. pos = i
  56. const
  57. chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
  58. # since negative numbers require a leading '-' they use up 1 byte. Thus we
  59. # subtract/add `vintDelta` here to save space for small negative numbers
  60. # which are common in ROD files:
  61. const
  62. vintDelta = 5
  63. template encodeIntImpl(self) =
  64. var d: char
  65. var v = x
  66. var rem = v mod 190
  67. if rem < 0:
  68. add(result, '-')
  69. v = - (v div 190)
  70. rem = - rem
  71. else:
  72. v = v div 190
  73. var idx = int(rem)
  74. if idx < 62: d = chars[idx]
  75. else: d = chr(idx - 62 + 128)
  76. if v != 0: self(v, result)
  77. add(result, d)
  78. proc encodeVBiggestIntAux(x: BiggestInt, result: var string) =
  79. ## encode a biggest int as a variable length base 190 int.
  80. encodeIntImpl(encodeVBiggestIntAux)
  81. proc encodeVBiggestInt*(x: BiggestInt, result: var string) =
  82. ## encode a biggest int as a variable length base 190 int.
  83. encodeVBiggestIntAux(x +% vintDelta, result)
  84. # encodeIntImpl(encodeVBiggestInt)
  85. proc encodeVIntAux(x: int, result: var string) =
  86. ## encode an int as a variable length base 190 int.
  87. encodeIntImpl(encodeVIntAux)
  88. proc encodeVInt*(x: int, result: var string) =
  89. ## encode an int as a variable length base 190 int.
  90. encodeVIntAux(x +% vintDelta, result)
  91. template decodeIntImpl() =
  92. var i = pos
  93. var sign = - 1
  94. assert(s[i] in {'a'..'z', 'A'..'Z', '0'..'9', '-', '\x80'..'\xFF'})
  95. if s[i] == '-':
  96. inc(i)
  97. sign = 1
  98. result = 0
  99. while true:
  100. case s[i]
  101. of '0'..'9': result = result * 190 - (ord(s[i]) - ord('0'))
  102. of 'a'..'z': result = result * 190 - (ord(s[i]) - ord('a') + 10)
  103. of 'A'..'Z': result = result * 190 - (ord(s[i]) - ord('A') + 36)
  104. of '\x80'..'\xFF': result = result * 190 - (ord(s[i]) - 128 + 62)
  105. else: break
  106. inc(i)
  107. result = result * sign -% vintDelta
  108. pos = i
  109. proc decodeVInt*(s: cstring, pos: var int): int =
  110. decodeIntImpl()
  111. proc decodeVBiggestInt*(s: cstring, pos: var int): BiggestInt =
  112. decodeIntImpl()
  113. iterator decodeVIntArray*(s: cstring): int =
  114. var i = 0
  115. while s[i] != '\0':
  116. yield decodeVInt(s, i)
  117. if s[i] == ' ': inc i
  118. iterator decodeStrArray*(s: cstring): string =
  119. var i = 0
  120. while s[i] != '\0':
  121. yield decodeStr(s, i)
  122. if s[i] == ' ': inc i