rodutils.nim 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  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, math
  11. when defined(nimPreviewSlimSystem):
  12. import std/assertions
  13. # bcc on windows doesn't have C99 functions
  14. when defined(windows) and defined(bcc):
  15. {.emit: """#if defined(_MSC_VER) && _MSC_VER < 1900
  16. #include <stdarg.h>
  17. static int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) {
  18. int count = -1;
  19. if (size != 0) count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);
  20. if (count == -1) count = _vscprintf(format, ap);
  21. return count;
  22. }
  23. int snprintf(char *outBuf, size_t size, const char *format, ...) {
  24. int count;
  25. va_list ap;
  26. va_start(ap, format);
  27. count = c99_vsnprintf(outBuf, size, format, ap);
  28. va_end(ap);
  29. return count;
  30. }
  31. #endif
  32. """.}
  33. proc c_snprintf(s: cstring; n:uint; frmt: cstring): cint {.importc: "snprintf", header: "<stdio.h>", nodecl, varargs.}
  34. when not declared(signbit):
  35. proc c_signbit(x: SomeFloat): cint {.importc: "signbit", header: "<math.h>".}
  36. proc signbit*(x: SomeFloat): bool {.inline.} =
  37. result = c_signbit(x) != 0
  38. import std/formatfloat
  39. proc toStrMaxPrecision*(f: BiggestFloat | float32): string =
  40. const literalPostfix = when f is float32: "f" else: ""
  41. case classify(f)
  42. of fcNan:
  43. if signbit(f):
  44. result = "-NAN"
  45. else:
  46. result = "NAN"
  47. of fcNegZero:
  48. result = "-0.0" & literalPostfix
  49. of fcZero:
  50. result = "0.0" & literalPostfix
  51. of fcInf:
  52. result = "INF"
  53. of fcNegInf:
  54. result = "-INF"
  55. else:
  56. result = ""
  57. result.addFloatRoundtrip(f)
  58. result.add literalPostfix
  59. proc encodeStr*(s: string, result: var string) =
  60. for i in 0..<s.len:
  61. case s[i]
  62. of 'a'..'z', 'A'..'Z', '0'..'9', '_': result.add(s[i])
  63. else: result.add('\\' & toHex(ord(s[i]), 2))
  64. proc hexChar(c: char, xi: var int) =
  65. case c
  66. of '0'..'9': xi = (xi shl 4) or (ord(c) - ord('0'))
  67. of 'a'..'f': xi = (xi shl 4) or (ord(c) - ord('a') + 10)
  68. of 'A'..'F': xi = (xi shl 4) or (ord(c) - ord('A') + 10)
  69. else: discard
  70. proc decodeStr*(s: cstring, pos: var int): string =
  71. var i = pos
  72. result = ""
  73. while true:
  74. case s[i]
  75. of '\\':
  76. inc(i, 3)
  77. var xi = 0
  78. hexChar(s[i-2], xi)
  79. hexChar(s[i-1], xi)
  80. result.add(chr(xi))
  81. of 'a'..'z', 'A'..'Z', '0'..'9', '_':
  82. result.add(s[i])
  83. inc(i)
  84. else: break
  85. pos = i
  86. const chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
  87. {.push overflowChecks: off.}
  88. # since negative numbers require a leading '-' they use up 1 byte. Thus we
  89. # subtract/add `vintDelta` here to save space for small negative numbers
  90. # which are common in ROD files:
  91. const vintDelta = 5
  92. template encodeIntImpl(self) =
  93. var d: char
  94. var v = x
  95. var rem = v mod 190
  96. if rem < 0:
  97. result.add('-')
  98. v = - (v div 190)
  99. rem = - rem
  100. else:
  101. v = v div 190
  102. var idx = int(rem)
  103. if idx < 62: d = chars[idx]
  104. else: d = chr(idx - 62 + 128)
  105. if v != 0: self(v, result)
  106. result.add(d)
  107. proc encodeVBiggestIntAux(x: BiggestInt, result: var string) =
  108. ## encode a biggest int as a variable length base 190 int.
  109. encodeIntImpl(encodeVBiggestIntAux)
  110. proc encodeVBiggestInt*(x: BiggestInt, result: var string) =
  111. ## encode a biggest int as a variable length base 190 int.
  112. encodeVBiggestIntAux(x +% vintDelta, result)
  113. # encodeIntImpl(encodeVBiggestInt)
  114. proc encodeVIntAux(x: int, result: var string) =
  115. ## encode an int as a variable length base 190 int.
  116. encodeIntImpl(encodeVIntAux)
  117. proc encodeVInt*(x: int, result: var string) =
  118. ## encode an int as a variable length base 190 int.
  119. encodeVIntAux(x +% vintDelta, result)
  120. template decodeIntImpl() =
  121. var i = pos
  122. var sign = - 1
  123. assert(s[i] in {'a'..'z', 'A'..'Z', '0'..'9', '-', '\x80'..'\xFF'})
  124. if s[i] == '-':
  125. inc(i)
  126. sign = 1
  127. result = 0
  128. while true:
  129. case s[i]
  130. of '0'..'9': result = result * 190 - (ord(s[i]) - ord('0'))
  131. of 'a'..'z': result = result * 190 - (ord(s[i]) - ord('a') + 10)
  132. of 'A'..'Z': result = result * 190 - (ord(s[i]) - ord('A') + 36)
  133. of '\x80'..'\xFF': result = result * 190 - (ord(s[i]) - 128 + 62)
  134. else: break
  135. inc(i)
  136. result = result * sign -% vintDelta
  137. pos = i
  138. proc decodeVInt*(s: cstring, pos: var int): int =
  139. decodeIntImpl()
  140. proc decodeVBiggestInt*(s: cstring, pos: var int): BiggestInt =
  141. decodeIntImpl()
  142. {.pop.}
  143. iterator decodeVIntArray*(s: cstring): int =
  144. var i = 0
  145. while s[i] != '\0':
  146. yield decodeVInt(s, i)
  147. if s[i] == ' ': inc i
  148. iterator decodeStrArray*(s: cstring): string =
  149. var i = 0
  150. while s[i] != '\0':
  151. yield decodeStr(s, i)
  152. if s[i] == ' ': inc i