blob: 2625ec446fcc20993f07cb237340f362d5461c64 (
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
#pragma once
#include "dynumber.h"
#include <util/generic/ymath.h>
#include <limits>
namespace NKikimr::NDyNumber {
template <typename T>
TMaybe<T> TryFromDyNumber(TStringBuf buffer) {
using traits = std::numeric_limits<T>;
if (!traits::is_specialized || !IsValidDyNumber(buffer)) {
return Nothing();
}
auto result = T();
auto s = buffer.data();
if (*s == '\x01') {
return result;
}
const bool negative = !*s++;
if (negative && !traits::is_signed) {
return Nothing();
}
auto power = ui8(*s++);
if (negative) {
power = '\xFF' - power;
}
std::function<TMaybe<T>(T, i16)> pow = [&pow](T base, i16 exp) -> TMaybe<T> {
if (exp > 0) {
const auto p = Power(base, exp - 1);
if (!p || p > traits::max()) {
return Nothing();
}
return base * p;
} else if (exp < 0) {
if (const auto p = pow(base, abs(exp))) {
return 1 / *p;
}
return Nothing();
} else {
return T(1);
}
};
auto apply = [&negative, &result, &pow](ui8 digit, i16 exp) -> bool {
if (traits::is_integer && (exp < 0 || exp > traits::digits10)) {
return false;
}
if (digit == '\x00') {
return true;
}
if (const auto p = pow(10, exp)) {
const T mul = digit * *p;
if (!mul || mul < *p || mul > traits::max()) {
return false;
}
if (negative) {
if (traits::lowest() - result > -mul) {
return false;
}
result -= mul;
} else {
if (traits::max() - result < mul) {
return false;
}
result += mul;
}
return true;
}
return false;
};
const auto digits = negative ? "FEDCBA9876543210" : "0123456789ABCDEF";
auto e = power - 129;
auto l = buffer.size() - 1;
while (--l) {
const auto c = *s++;
const auto hi = (c >> '\x04') & '\x0F';
const auto lo = c & '\x0F';
if (!apply(digits[hi] - '0', --e)) {
return Nothing();
}
if (lo != (negative ? '\x0F' : '\x00') || l > 1U) {
if (!apply(digits[lo] - '0', --e)) {
return Nothing();
}
}
}
return result;
}
}
|