Coverage Report

Created: 2025-07-26 00:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/root/doris/be/src/util/to_string.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
19
#pragma once
20
21
#include <absl/strings/ascii.h>
22
#include <fmt/compile.h>
23
#include <fmt/format.h>
24
#include <glog/logging.h>
25
26
#include <cfloat>
27
#include <map>
28
#include <set>
29
#include <string>
30
#include <type_traits>
31
#include <vector>
32
33
namespace doris {
34
35
template <typename T>
36
137
std::string to_string(const T& t) {
37
137
    return fmt::format("{}", t);
38
137
}
_ZN5doris9to_stringISt6atomicINS_19TWgSlotMemoryPolicy4typeEEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_
Line
Count
Source
36
137
std::string to_string(const T& t) {
37
137
    return fmt::format("{}", t);
38
137
}
Unexecuted instantiation: _ZN5doris9to_stringINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEES6_RKT_
39
40
template <typename K, typename V>
41
std::string to_string(const std::map<K, V>& m);
42
43
template <typename T>
44
std::string to_string(const std::set<T>& s);
45
46
template <typename T>
47
std::string to_string(const std::vector<T>& t);
48
49
template <typename K, typename V>
50
std::string to_string(const typename std::pair<K, V>& v) {
51
    return fmt::format("{}: {}", to_string(v.first), to_string(v.second));
52
}
53
54
template <typename T>
55
0
std::string to_string(const T& beg, const T& end) {
56
0
    std::string out;
57
0
    for (T it = beg; it != end; ++it) {
58
0
        if (it != beg) out += ", ";
59
0
        out += to_string(*it);
60
0
    }
61
0
    return out;
62
0
}
63
64
template <typename T>
65
0
std::string to_string(const std::vector<T>& t) {
66
0
    return "[" + to_string(t.begin(), t.end()) + "]";
67
0
}
68
69
template <typename K, typename V>
70
std::string to_string(const std::map<K, V>& m) {
71
    return "{" + to_string(m.begin(), m.end()) + "}";
72
}
73
74
template <typename T>
75
std::string to_string(const std::set<T>& s) {
76
    return "{" + to_string(s.begin(), s.end()) + "}";
77
}
78
79
// refer to: https://en.cppreference.com/w/cpp/types/numeric_limits/max_digits10.html
80
template <typename T>
81
1.62k
inline int fast_to_buffer(T value, char* buffer) {
82
1.62k
    char* end = nullptr;
83
    // output NaN and Infinity to be compatible with most of the implementations
84
1.62k
    if (std::isnan(value)) {
85
3
        static constexpr char nan_str[] = "NaN";
86
3
        static constexpr int nan_str_len = sizeof(nan_str) - 1;
87
3
        memcpy(buffer, nan_str, nan_str_len);
88
3
        end = buffer + nan_str_len;
89
1.62k
    } else if (std::isinf(value)) {
90
5
        static constexpr char inf_str[] = "Infinity";
91
5
        static constexpr int inf_str_len = sizeof(inf_str) - 1;
92
5
        static constexpr char neg_inf_str[] = "-Infinity";
93
5
        static constexpr int neg_inf_str_len = sizeof(neg_inf_str) - 1;
94
5
        if (value > 0) {
95
3
            memcpy(buffer, inf_str, inf_str_len);
96
3
            end = buffer + inf_str_len;
97
3
        } else {
98
2
            memcpy(buffer, neg_inf_str, neg_inf_str_len);
99
2
            end = buffer + neg_inf_str_len;
100
2
        }
101
1.62k
    } else {
102
1.62k
        end = fmt::format_to(buffer, FMT_COMPILE("{}"), value);
Unexecuted instantiation: _ZZZN5doris14fast_to_bufferIfEEiT_PcENKUlvE_clEvENK18FMT_COMPILE_STRINGcvN3fmt2v717basic_string_viewIcEEEv
Unexecuted instantiation: _ZZZN5doris14fast_to_bufferIdEEiT_PcENKUlvE_clEvENK18FMT_COMPILE_STRINGcvN3fmt2v717basic_string_viewIcEEEv
103
1.62k
    }
104
1.62k
    *end = '\0';
105
1.62k
    return end - buffer;
106
1.62k
}
_ZN5doris14fast_to_bufferIfEEiT_Pc
Line
Count
Source
81
764
inline int fast_to_buffer(T value, char* buffer) {
82
764
    char* end = nullptr;
83
    // output NaN and Infinity to be compatible with most of the implementations
84
764
    if (std::isnan(value)) {
85
1
        static constexpr char nan_str[] = "NaN";
86
1
        static constexpr int nan_str_len = sizeof(nan_str) - 1;
87
1
        memcpy(buffer, nan_str, nan_str_len);
88
1
        end = buffer + nan_str_len;
89
763
    } else if (std::isinf(value)) {
90
2
        static constexpr char inf_str[] = "Infinity";
91
2
        static constexpr int inf_str_len = sizeof(inf_str) - 1;
92
2
        static constexpr char neg_inf_str[] = "-Infinity";
93
2
        static constexpr int neg_inf_str_len = sizeof(neg_inf_str) - 1;
94
2
        if (value > 0) {
95
1
            memcpy(buffer, inf_str, inf_str_len);
96
1
            end = buffer + inf_str_len;
97
1
        } else {
98
1
            memcpy(buffer, neg_inf_str, neg_inf_str_len);
99
1
            end = buffer + neg_inf_str_len;
100
1
        }
101
761
    } else {
102
        end = fmt::format_to(buffer, FMT_COMPILE("{}"), value);
103
761
    }
104
764
    *end = '\0';
105
764
    return end - buffer;
106
764
}
_ZN5doris14fast_to_bufferIdEEiT_Pc
Line
Count
Source
81
865
inline int fast_to_buffer(T value, char* buffer) {
82
865
    char* end = nullptr;
83
    // output NaN and Infinity to be compatible with most of the implementations
84
865
    if (std::isnan(value)) {
85
2
        static constexpr char nan_str[] = "NaN";
86
2
        static constexpr int nan_str_len = sizeof(nan_str) - 1;
87
2
        memcpy(buffer, nan_str, nan_str_len);
88
2
        end = buffer + nan_str_len;
89
863
    } else if (std::isinf(value)) {
90
3
        static constexpr char inf_str[] = "Infinity";
91
3
        static constexpr int inf_str_len = sizeof(inf_str) - 1;
92
3
        static constexpr char neg_inf_str[] = "-Infinity";
93
3
        static constexpr int neg_inf_str_len = sizeof(neg_inf_str) - 1;
94
3
        if (value > 0) {
95
2
            memcpy(buffer, inf_str, inf_str_len);
96
2
            end = buffer + inf_str_len;
97
2
        } else {
98
1
            memcpy(buffer, neg_inf_str, neg_inf_str_len);
99
1
            end = buffer + neg_inf_str_len;
100
1
        }
101
860
    } else {
102
        end = fmt::format_to(buffer, FMT_COMPILE("{}"), value);
103
860
    }
104
865
    *end = '\0';
105
865
    return end - buffer;
106
865
}
107
108
template <typename T>
109
18.0M
int to_buffer(const T& value, int width, char* buffer) {
110
18.0M
    constexpr int DIG = (std::is_same_v<T, double> ? DBL_DIG : FLT_DIG);
111
18.0M
    int snprintf_result = snprintf(buffer, width, "%.*g", DIG, value);
112
    // The snprintf should never overflow because the buffer is significantly
113
    // larger than the precision we asked for.
114
18.0M
    DCHECK(snprintf_result > 0 && snprintf_result < width);
115
116
18.0M
    bool need_reformat = false;
117
18.0M
    if constexpr (std::is_same_v<T, double>) {
118
11
        need_reformat = (strtod(buffer, nullptr) != value);
119
18.0M
    } else {
120
18.0M
        auto safe_strtof = [](const char* str, float* value) {
121
18.0M
            char* endptr;
122
18.0M
            *value = strtof(str, &endptr);
123
18.0M
            if (endptr != str) {
124
18.0M
                while (absl::ascii_isspace(*endptr)) {
125
0
                    ++endptr;
126
0
                }
127
18.0M
            }
128
            // Ignore range errors from strtod/strtof.
129
            // The values it returns on underflow and
130
            // overflow are the right fallback in a
131
            // robust setting.
132
18.0M
            return *str != '\0' && *endptr == '\0';
133
18.0M
        };
134
135
18.0M
        if (float parsed_value; !safe_strtof(buffer, &parsed_value) || parsed_value != value) {
136
12
            need_reformat = true;
137
12
        }
138
18.0M
    }
139
140
18.0M
    if (need_reformat) {
141
15
        snprintf_result = snprintf(buffer, width, "%.*g", DIG + 2, value);
142
        // Should never overflow; see above.
143
        DCHECK(snprintf_result > 0 && snprintf_result < width);
144
15
    }
145
18.0M
    return snprintf_result;
146
18.0M
}
_ZN5doris9to_bufferIfEEiRKT_iPc
Line
Count
Source
109
18.0M
int to_buffer(const T& value, int width, char* buffer) {
110
18.0M
    constexpr int DIG = (std::is_same_v<T, double> ? DBL_DIG : FLT_DIG);
111
18.0M
    int snprintf_result = snprintf(buffer, width, "%.*g", DIG, value);
112
    // The snprintf should never overflow because the buffer is significantly
113
    // larger than the precision we asked for.
114
18.0M
    DCHECK(snprintf_result > 0 && snprintf_result < width);
115
116
18.0M
    bool need_reformat = false;
117
    if constexpr (std::is_same_v<T, double>) {
118
        need_reformat = (strtod(buffer, nullptr) != value);
119
18.0M
    } else {
120
18.0M
        auto safe_strtof = [](const char* str, float* value) {
121
18.0M
            char* endptr;
122
18.0M
            *value = strtof(str, &endptr);
123
18.0M
            if (endptr != str) {
124
18.0M
                while (absl::ascii_isspace(*endptr)) {
125
18.0M
                    ++endptr;
126
18.0M
                }
127
18.0M
            }
128
            // Ignore range errors from strtod/strtof.
129
            // The values it returns on underflow and
130
            // overflow are the right fallback in a
131
            // robust setting.
132
18.0M
            return *str != '\0' && *endptr == '\0';
133
18.0M
        };
134
135
18.0M
        if (float parsed_value; !safe_strtof(buffer, &parsed_value) || parsed_value != value) {
136
12
            need_reformat = true;
137
12
        }
138
18.0M
    }
139
140
18.0M
    if (need_reformat) {
141
12
        snprintf_result = snprintf(buffer, width, "%.*g", DIG + 2, value);
142
        // Should never overflow; see above.
143
        DCHECK(snprintf_result > 0 && snprintf_result < width);
144
12
    }
145
18.0M
    return snprintf_result;
146
18.0M
}
_ZN5doris9to_bufferIdEEiRKT_iPc
Line
Count
Source
109
11
int to_buffer(const T& value, int width, char* buffer) {
110
11
    constexpr int DIG = (std::is_same_v<T, double> ? DBL_DIG : FLT_DIG);
111
11
    int snprintf_result = snprintf(buffer, width, "%.*g", DIG, value);
112
    // The snprintf should never overflow because the buffer is significantly
113
    // larger than the precision we asked for.
114
11
    DCHECK(snprintf_result > 0 && snprintf_result < width);
115
116
11
    bool need_reformat = false;
117
11
    if constexpr (std::is_same_v<T, double>) {
118
11
        need_reformat = (strtod(buffer, nullptr) != value);
119
    } else {
120
        auto safe_strtof = [](const char* str, float* value) {
121
            char* endptr;
122
            *value = strtof(str, &endptr);
123
            if (endptr != str) {
124
                while (absl::ascii_isspace(*endptr)) {
125
                    ++endptr;
126
                }
127
            }
128
            // Ignore range errors from strtod/strtof.
129
            // The values it returns on underflow and
130
            // overflow are the right fallback in a
131
            // robust setting.
132
            return *str != '\0' && *endptr == '\0';
133
        };
134
135
        if (float parsed_value; !safe_strtof(buffer, &parsed_value) || parsed_value != value) {
136
            need_reformat = true;
137
        }
138
    }
139
140
11
    if (need_reformat) {
141
3
        snprintf_result = snprintf(buffer, width, "%.*g", DIG + 2, value);
142
        // Should never overflow; see above.
143
        DCHECK(snprintf_result > 0 && snprintf_result < width);
144
3
    }
145
11
    return snprintf_result;
146
11
}
147
} // namespace doris