varints.nim 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2018 Nim contributors
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## A variable length integer
  10. ## encoding implementation inspired by SQLite.
  11. ##
  12. ## Unstable API.
  13. const
  14. maxVarIntLen* = 9 ## the maximal number of bytes a varint can take
  15. proc readVu64*(z: openArray[byte]; pResult: var uint64): int =
  16. if z[0] <= 240:
  17. pResult = z[0]
  18. return 1
  19. if z[0] <= 248:
  20. if z.len < 2: return 0
  21. pResult = (uint64 z[0] - 241) * 256 + z[1].uint64 + 240
  22. return 2
  23. if z.len < int(z[0]-246): return 0
  24. if z[0] == 249:
  25. pResult = 2288u64 + 256u64*z[1].uint64 + z[2].uint64
  26. return 3
  27. if z[0] == 250:
  28. pResult = (z[1].uint64 shl 16u64) + (z[2].uint64 shl 8u64) + z[3].uint64
  29. return 4
  30. let x = (z[1].uint64 shl 24) + (z[2].uint64 shl 16) + (z[3].uint64 shl 8) + z[4].uint64
  31. if z[0] == 251:
  32. pResult = x
  33. return 5
  34. if z[0] == 252:
  35. pResult = (((uint64)x) shl 8) + z[5].uint64
  36. return 6
  37. if z[0] == 253:
  38. pResult = (((uint64)x) shl 16) + (z[5].uint64 shl 8) + z[6].uint64
  39. return 7
  40. if z[0] == 254:
  41. pResult = (((uint64)x) shl 24) + (z[5].uint64 shl 16) + (z[6].uint64 shl 8) + z[7].uint64
  42. return 8
  43. pResult = (((uint64)x) shl 32) +
  44. (0xffffffff'u64 and ((z[5].uint64 shl 24) +
  45. (z[6].uint64 shl 16) + (z[7].uint64 shl 8) + z[8].uint64))
  46. return 9
  47. proc varintWrite32(z: var openArray[byte]; y: uint32) =
  48. z[0] = cast[uint8](y shr 24)
  49. z[1] = cast[uint8](y shr 16)
  50. z[2] = cast[uint8](y shr 8)
  51. z[3] = cast[uint8](y)
  52. proc writeVu64*(z: var openArray[byte], x: uint64): int =
  53. ## Write a varint into z. The buffer z must be at least 9 characters
  54. ## long to accommodate the largest possible varint. Returns the number of
  55. ## bytes used.
  56. if x <= 240:
  57. z[0] = cast[uint8](x)
  58. return 1
  59. if x <= 2287:
  60. let y = cast[uint32](x - 240)
  61. z[0] = cast[uint8](y shr 8 + 241)
  62. z[1] = cast[uint8](y and 255)
  63. return 2
  64. if x <= 67823:
  65. let y = cast[uint32](x - 2288)
  66. z[0] = 249
  67. z[1] = cast[uint8](y shr 8)
  68. z[2] = cast[uint8](y and 255)
  69. return 3
  70. let y = cast[uint32](x)
  71. let w = cast[uint32](x shr 32)
  72. if w == 0:
  73. if y <= 16777215:
  74. z[0] = 250
  75. z[1] = cast[uint8](y shr 16)
  76. z[2] = cast[uint8](y shr 8)
  77. z[3] = cast[uint8](y)
  78. return 4
  79. z[0] = 251
  80. varintWrite32(toOpenArray(z, 1, 4), y)
  81. return 5
  82. if w <= 255:
  83. z[0] = 252
  84. z[1] = cast[uint8](w)
  85. varintWrite32(toOpenArray(z, 2, 5), y)
  86. return 6
  87. if w <= 65535:
  88. z[0] = 253
  89. z[1] = cast[uint8](w shr 8)
  90. z[2] = cast[uint8](w)
  91. varintWrite32(toOpenArray(z, 3, 6), y)
  92. return 7
  93. if w <= 16777215:
  94. z[0] = 254
  95. z[1] = cast[uint8](w shr 16)
  96. z[2] = cast[uint8](w shr 8)
  97. z[3] = cast[uint8](w)
  98. varintWrite32(toOpenArray(z, 4, 7), y)
  99. return 8
  100. z[0] = 255
  101. varintWrite32(toOpenArray(z, 1, 4), w)
  102. varintWrite32(toOpenArray(z, 5, 8), y)
  103. return 9
  104. proc sar(a, b: int64): int64 =
  105. {.emit: [result, " = ", a, " >> ", b, ";"].}
  106. proc sal(a, b: int64): int64 =
  107. {.emit: [result, " = ", a, " << ", b, ";"].}
  108. proc encodeZigzag*(x: int64): uint64 {.inline.} =
  109. uint64(sal(x, 1)) xor uint64(sar(x, 63))
  110. proc decodeZigzag*(x: uint64): int64 {.inline.} =
  111. let casted = cast[int64](x)
  112. result = (`shr`(casted, 1)) xor (-(casted and 1))