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