varint-inl.h 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. #ifndef VARINT_INL_H_
  2. #error "Direct inclusion of this file is not allowed, include varint.h"
  3. // For the sake of sane code completion.
  4. #include "varint.h"
  5. #endif
  6. #include "zig_zag.h"
  7. #include <library/cpp/yt/exception/exception.h>
  8. #include <array>
  9. namespace NYT {
  10. ////////////////////////////////////////////////////////////////////////////////
  11. inline int WriteVarUint64(char* output, ui64 value)
  12. {
  13. output[0] = static_cast<ui8>(value);
  14. if (Y_LIKELY(value < 0x80)) {
  15. return 1;
  16. }
  17. output[0] |= 0x80;
  18. value >>= 7;
  19. output[1] = static_cast<ui8>(value);
  20. if (Y_LIKELY(value < 0x80)) {
  21. return 2;
  22. }
  23. int count = 2;
  24. do {
  25. output[count - 1] |= 0x80;
  26. value >>= 7;
  27. output[count] = static_cast<ui8>(value);
  28. ++count;
  29. } while (Y_UNLIKELY(value >= 0x80));
  30. return count;
  31. }
  32. inline int WriteVarUint64(IOutputStream* output, ui64 value)
  33. {
  34. std::array<char, MaxVarUint64Size> buffer;
  35. auto size = WriteVarUint64(buffer.data(), value);
  36. output->Write(buffer.data(), size);
  37. return size;
  38. }
  39. ////////////////////////////////////////////////////////////////////////////////
  40. namespace NDetail {
  41. template <class T, size_t N>
  42. T ReadVarUintKnownSize(const char* buffer)
  43. {
  44. auto result = static_cast<T>(static_cast<ui8>(buffer[N - 1])) << (7 * (N - 1));
  45. for (size_t i = 0, offset = 0; i < N - 1; i++, offset += 7) {
  46. result += static_cast<T>(static_cast<ui8>(buffer[i]) - 0x80) << offset;
  47. }
  48. return result;
  49. }
  50. } // namespace NDetail
  51. #define XX(type, size) \
  52. if (static_cast<ui8>(input[size - 1]) < 0x80) { \
  53. *value = NYT::NDetail::ReadVarUintKnownSize<type, size>(input); \
  54. return size; \
  55. }
  56. Y_FORCE_INLINE int ReadVarUint32(const char* input, ui32* value)
  57. {
  58. XX(ui64, 1)
  59. XX(ui64, 2)
  60. XX(ui64, 3)
  61. XX(ui64, 4)
  62. XX(ui64, 5)
  63. throw TSimpleException("Value is too big for varuint32");
  64. }
  65. Y_FORCE_INLINE int ReadVarUint64(const char* input, ui64* value)
  66. {
  67. XX(ui64, 1)
  68. XX(ui64, 2)
  69. XX(ui64, 3)
  70. XX(ui64, 4)
  71. XX(ui64, 5)
  72. XX(ui64, 6)
  73. XX(ui64, 7)
  74. XX(ui64, 8)
  75. XX(ui64, 9)
  76. XX(ui64, 10)
  77. throw TSimpleException("Value is too big for varuint64");
  78. }
  79. #undef XX
  80. ////////////////////////////////////////////////////////////////////////////////
  81. namespace NDetail {
  82. template <class TOutput>
  83. Y_FORCE_INLINE int WriteVarUint32Impl(TOutput output, ui32 value)
  84. {
  85. return WriteVarUint64(output, static_cast<ui64>(value));
  86. }
  87. template <class TOutput>
  88. Y_FORCE_INLINE int WriteVarInt32Impl(TOutput output, i32 value)
  89. {
  90. return WriteVarUint64(output, ZigZagEncode32(value));
  91. }
  92. template <class TOutput>
  93. Y_FORCE_INLINE int WriteVarInt64Impl(TOutput output, i64 value)
  94. {
  95. return WriteVarUint64(output, ZigZagEncode64(value));
  96. }
  97. } // namespace NDetail
  98. Y_FORCE_INLINE int WriteVarUint32(IOutputStream* output, ui32 value)
  99. {
  100. return NYT::NDetail::WriteVarUint32Impl(output, value);
  101. }
  102. Y_FORCE_INLINE int WriteVarUint32(char* output, ui32 value)
  103. {
  104. return NYT::NDetail::WriteVarUint32Impl(output, value);
  105. }
  106. Y_FORCE_INLINE int WriteVarInt32(IOutputStream* output, i32 value)
  107. {
  108. return NYT::NDetail::WriteVarInt32Impl(output, value);
  109. }
  110. Y_FORCE_INLINE int WriteVarInt32(char* output, i32 value)
  111. {
  112. return NYT::NDetail::WriteVarInt32Impl(output, value);
  113. }
  114. Y_FORCE_INLINE int WriteVarInt64(IOutputStream* output, i64 value)
  115. {
  116. return NYT::NDetail::WriteVarInt64Impl(output, value);
  117. }
  118. Y_FORCE_INLINE int WriteVarInt64(char* output, i64 value)
  119. {
  120. return NYT::NDetail::WriteVarInt64Impl(output, value);
  121. }
  122. ////////////////////////////////////////////////////////////////////////////////
  123. namespace NDetail {
  124. template <class TReadCallback>
  125. int ReadVarUint64Impl(ui64* value, TReadCallback&& doRead)
  126. {
  127. size_t count = 0;
  128. ui64 result = 0;
  129. ui8 byte;
  130. do {
  131. byte = doRead();
  132. result |= (static_cast<ui64> (byte & 0x7F)) << (7 * count);
  133. ++count;
  134. if (count > MaxVarUint64Size) {
  135. throw TSimpleException("Value is too big for varuint64");
  136. }
  137. } while (byte & 0x80);
  138. *value = result;
  139. return count;
  140. }
  141. inline int ReadVarUint64Fallback(const char* input, const char* end, ui64* value)
  142. {
  143. return ReadVarUint64Impl(
  144. value,
  145. [&] {
  146. if (input == end) {
  147. throw TSimpleException("Premature end of data while reading varuint64");
  148. }
  149. return *input++;
  150. });
  151. }
  152. } // namespace NDetail
  153. inline int ReadVarUint64(IInputStream* input, ui64* value)
  154. {
  155. return NYT::NDetail::ReadVarUint64Impl(
  156. value,
  157. [&] {
  158. char byte;
  159. if (input->Read(&byte, 1) != 1) {
  160. throw TSimpleException("Premature end of stream while reading varuint64");
  161. }
  162. return byte;
  163. });
  164. }
  165. Y_FORCE_INLINE int ReadVarUint64(const char* input, const char* end, ui64* value)
  166. {
  167. if (Y_LIKELY(static_cast<size_t>(end - input) >= MaxVarUint64Size)) {
  168. return ReadVarUint64(input, value);
  169. } else {
  170. return NYT::NDetail::ReadVarUint64Fallback(input, end, value);
  171. }
  172. }
  173. ////////////////////////////////////////////////////////////////////////////////
  174. namespace NDetail {
  175. template <class... TArgs>
  176. Y_FORCE_INLINE int ReadVarUint32Impl(ui32* value, TArgs&&... args)
  177. {
  178. ui64 varInt;
  179. int bytesRead = ReadVarUint64(std::forward<TArgs>(args)..., &varInt);
  180. if (varInt > std::numeric_limits<ui32>::max()) {
  181. throw TSimpleException("Value is too big for varuint32");
  182. }
  183. *value = static_cast<ui32>(varInt);
  184. return bytesRead;
  185. }
  186. } // namespace NDetail
  187. Y_FORCE_INLINE int ReadVarUint32(IInputStream* input, ui32* value)
  188. {
  189. return NYT::NDetail::ReadVarUint32Impl(value, input);
  190. }
  191. Y_FORCE_INLINE int ReadVarUint32(const char* input, const char* end, ui32* value)
  192. {
  193. return NYT::NDetail::ReadVarUint32Impl(value, input, end);
  194. }
  195. ////////////////////////////////////////////////////////////////////////////////
  196. namespace NDetail {
  197. template <class... TArgs>
  198. Y_FORCE_INLINE int ReadVarInt32Impl(i32* value, TArgs&&... args)
  199. {
  200. ui64 varInt;
  201. int bytesRead = ReadVarUint64(std::forward<TArgs>(args)..., &varInt);
  202. if (varInt > std::numeric_limits<ui32>::max()) {
  203. throw TSimpleException("Value is too big for varint32");
  204. }
  205. *value = ZigZagDecode32(static_cast<ui32>(varInt));
  206. return bytesRead;
  207. }
  208. } // namespace NDetail
  209. Y_FORCE_INLINE int ReadVarInt32(IInputStream* input, i32* value)
  210. {
  211. return NYT::NDetail::ReadVarInt32Impl(value, input);
  212. }
  213. Y_FORCE_INLINE int ReadVarInt32(const char* input, i32* value)
  214. {
  215. return NYT::NDetail::ReadVarInt32Impl(value, input);
  216. }
  217. Y_FORCE_INLINE int ReadVarInt32(const char* input, const char* end, i32* value)
  218. {
  219. return NYT::NDetail::ReadVarInt32Impl(value, input, end);
  220. }
  221. ////////////////////////////////////////////////////////////////////////////////
  222. namespace NDetail {
  223. template <class... TArgs>
  224. Y_FORCE_INLINE int ReadVarInt64Impl(i64* value, TArgs&&... args)
  225. {
  226. ui64 varInt;
  227. int bytesRead = ReadVarUint64(std::forward<TArgs>(args)..., &varInt);
  228. *value = ZigZagDecode64(varInt);
  229. return bytesRead;
  230. }
  231. } // namespace NDetail
  232. Y_FORCE_INLINE int ReadVarInt64(IInputStream* input, i64* value)
  233. {
  234. return NYT::NDetail::ReadVarInt64Impl(value, input);
  235. }
  236. Y_FORCE_INLINE int ReadVarInt64(const char* input, i64* value)
  237. {
  238. return NYT::NDetail::ReadVarInt64Impl(value, input);
  239. }
  240. Y_FORCE_INLINE int ReadVarInt64(const char* input, const char* end, i64* value)
  241. {
  242. return NYT::NDetail::ReadVarInt64Impl(value, input, end);
  243. }
  244. ////////////////////////////////////////////////////////////////////////////////
  245. } // namespace NYT