Coverage Report

Created: 2026-08-18 17:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/core/decimal12.h
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#pragma once
19
20
#include <cinttypes>
21
#include <cstdint>
22
#include <cstdio>
23
#include <cstdlib>
24
#include <cstring>
25
#include <iostream>
26
#include <string>
27
28
#include "common/status.h"
29
30
namespace doris {
31
32
// the sign of integer must be same as fraction
33
struct decimal12_t {
34
    decimal12_t& operator+=(const decimal12_t& value) {
35
        fraction += value.fraction;
36
        integer += value.integer;
37
38
        if (fraction >= FRAC_RATIO) {
39
            integer += 1;
40
            fraction -= FRAC_RATIO;
41
        } else if (fraction <= -FRAC_RATIO) {
42
            integer -= 1;
43
            fraction += FRAC_RATIO;
44
        }
45
46
        // if sign of fraction is different from integer
47
        if ((fraction != 0) && (integer != 0) && (fraction ^ integer) < 0) {
48
            bool sign = integer < 0;
49
            integer += (sign ? 1 : -1);
50
            fraction += (sign ? -FRAC_RATIO : FRAC_RATIO);
51
        }
52
53
        //LOG(WARNING) << "agg: int=" << integer << ", frac=" << fraction;
54
        //_set_flag();
55
        return *this;
56
    }
57
58
    bool operator==(const decimal12_t& value) const { return cmp(value) == 0; }
59
60
98.6k
    auto operator<=>(const decimal12_t& value) const { return cmp(value) <=> 0; }
61
62
98.7k
    int32_t cmp(const decimal12_t& other) const {
63
98.7k
        if (integer > other.integer) {
64
48.9k
            return 1;
65
49.7k
        } else if (integer == other.integer) {
66
384
            if (fraction > other.fraction) {
67
1
                return 1;
68
383
            } else if (fraction == other.fraction) {
69
383
                return 0;
70
383
            }
71
384
        }
72
73
49.3k
        return -1;
74
98.7k
    }
75
76
474
    std::string to_string() const {
77
474
        char buf[128] = {'\0'};
78
79
474
        if (integer < 0 || fraction < 0) {
80
162
            snprintf(buf, sizeof(buf), "-%" PRIu64 ".%09u", std::abs(integer), std::abs(fraction));
81
312
        } else {
82
312
            snprintf(buf, sizeof(buf), "%" PRIu64 ".%09u", std::abs(integer), std::abs(fraction));
83
312
        }
84
85
474
        return std::string(buf);
86
474
    }
87
88
    // Not modify this structure, ZoneMap use this from_string and to_string
89
    // to serialize decimalv2 value to segment files
90
0
    Status from_string(const std::string& str) {
91
0
        integer = 0;
92
0
        fraction = 0;
93
0
        const char* value_string = str.c_str();
94
0
        const char* sign = strchr(value_string, '-');
95
0
96
0
        if (sign != nullptr) {
97
0
            if (sign != value_string) {
98
0
                return Status::Error<ErrorCode::INVALID_ARGUMENT>(
99
0
                        "decimal12_t::from_string meet invalid sign");
100
0
            } else {
101
0
                ++value_string;
102
0
            }
103
0
        }
104
0
105
0
        const char* sepr = strchr(value_string, '.');
106
0
        if ((sepr != nullptr && sepr - value_string > MAX_INT_DIGITS_NUM) ||
107
0
            (sepr == nullptr && strlen(value_string) > MAX_INT_DIGITS_NUM)) {
108
0
            integer = 999999999999999999;
109
0
            fraction = 999999999;
110
0
        } else {
111
0
            int32_t f = 0;
112
0
            int64_t i = 0;
113
0
            if (sepr == value_string) {
114
0
                sscanf(value_string, ".%9d", &f);
115
0
            } else {
116
0
                sscanf(value_string, "%18" PRId64 ".%9d", &i, &f);
117
0
            }
118
0
            integer = i;
119
0
            fraction = f;
120
0
121
0
            int64_t frac_len =
122
0
                    (nullptr != sepr) ? MAX_FRAC_DIGITS_NUM - static_cast<int64_t>(strlen(sepr + 1))
123
0
                                      : MAX_FRAC_DIGITS_NUM;
124
0
            frac_len = frac_len > 0 ? frac_len : 0;
125
0
            fraction *= k_power_table[frac_len];
126
0
        }
127
0
128
0
        if (sign != nullptr) {
129
0
            fraction = -fraction;
130
0
            integer = -integer;
131
0
        }
132
0
133
0
        return Status::OK();
134
0
    }
135
136
    static const int32_t FRAC_RATIO = 1000000000;
137
    static const int32_t MAX_INT_DIGITS_NUM = 18;
138
    static const int32_t MAX_FRAC_DIGITS_NUM = 9;
139
    // 10^0 .. 10^MAX_FRAC_DIGITS_NUM, used by from_string. A private copy so
140
    // this header does not need storage/utils.h (whose g_power_table drags in
141
    // the whole storage layer).
142
    static constexpr int32_t k_power_table[MAX_FRAC_DIGITS_NUM + 1] = {
143
            1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
144
145
    int64_t integer;
146
    int32_t fraction;
147
} __attribute__((packed));
148
149
static_assert(std::is_trivial<decimal12_t>::value, "decimal12_t should be a POD type");
150
151
inline std::ostream& operator<<(std::ostream& os, const decimal12_t& val) {
152
    os << val.to_string();
153
    return os;
154
}
155
156
} // namespace doris