yql_decimal_serialize.cpp 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. #include "yql_decimal_serialize.h"
  2. #include <utility>
  3. namespace NYql {
  4. namespace NDecimal {
  5. size_t Serialize(TInt128 value, char* buf) {
  6. if (value == -Nan()) {
  7. *buf = 0x00;
  8. return 1U;
  9. }
  10. if (value == -Inf()) {
  11. *buf = 0x01;
  12. return 1U;
  13. }
  14. if (value == +Inf()) {
  15. *buf = 0xFE;
  16. return 1U;
  17. }
  18. if (value == +Nan()) {
  19. *buf = 0xFF;
  20. return 1U;
  21. }
  22. auto size = sizeof(value);
  23. auto p = reinterpret_cast<const char*>(&value) + size - 1U;
  24. if (*(p - 1U) & 0x80) {
  25. while (size > 1U && ~0 == *--p)
  26. --size;
  27. *buf = 0x80 - size;
  28. } else {
  29. while (size > 1U && 0 == *--p)
  30. --size;
  31. *buf = 0x7F + size;
  32. }
  33. for (auto i = 1U; i < size; ++i) {
  34. *++buf = *p--;
  35. }
  36. return size;
  37. }
  38. std::pair<TInt128, size_t> Deserialize(const char* b, size_t len) {
  39. if (!b || len == 0U)
  40. return std::make_pair(Err(), 0U);
  41. const auto mark = ui8(*b);
  42. const bool neg = mark < 0x80u;
  43. if (mark == 0x00u || mark == 0xFFu)
  44. return std::make_pair(neg ? -Nan() : +Nan(), 1U);
  45. if (mark == 0x01u || mark == 0xFEu)
  46. return std::make_pair(neg ? -Inf() : +Inf(), 1U);
  47. if (mark < 0x70u || mark > 0x8Fu) {
  48. return std::make_pair(Err(), 0U);
  49. }
  50. const auto used = neg ? 0x80u - mark : mark - 0x7Fu;
  51. if (len < used)
  52. return std::make_pair(Err(), 0U);
  53. TInt128 v;
  54. const auto size = sizeof(v);
  55. auto p = reinterpret_cast<char*>(&v) + size;
  56. for (auto fill = size - used + 2U; --fill;)
  57. *--p = neg ? ~0 : 0;
  58. for (auto copy = used; --copy;)
  59. *--p = *++b;
  60. return std::make_pair(v, used);
  61. }
  62. }
  63. }