Coverage Report

Created: 2026-11-05 21:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/exec/common/histogram_helpers.hpp
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 <rapidjson/document.h>
21
#include <rapidjson/prettywriter.h>
22
#include <rapidjson/stringbuffer.h>
23
24
#include <boost/dynamic_bitset.hpp>
25
26
#include "common/cast_set.h"
27
#include "core/data_type/data_type_decimal.h"
28
29
namespace doris {
30
template <typename T>
31
struct Bucket {
32
public:
33
    Bucket() = default;
34
    Bucket(T lower, T upper, size_t ndv, size_t count, size_t pre_sum)
35
328
            : lower(lower), upper(upper), ndv(ndv), count(count), pre_sum(pre_sum) {}
Unexecuted instantiation: _ZN5doris6BucketINS_7DecimalIiEEEC2ES2_S2_mmm
Unexecuted instantiation: _ZN5doris6BucketINS_7DecimalIlEEEC2ES2_S2_mmm
Unexecuted instantiation: _ZN5doris6BucketINS_12Decimal128V3EEC2ES1_S1_mmm
Unexecuted instantiation: _ZN5doris6BucketINS_7DecimalIN4wide7integerILm256EiEEEEEC2ES5_S5_mmm
_ZN5doris6BucketINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2ES6_S6_mmm
Line
Count
Source
35
20
            : lower(lower), upper(upper), ndv(ndv), count(count), pre_sum(pre_sum) {}
_ZN5doris6BucketINS_11DateV2ValueINS_15DateV2ValueTypeEEEEC2ES3_S3_mmm
Line
Count
Source
35
20
            : lower(lower), upper(upper), ndv(ndv), count(count), pre_sum(pre_sum) {}
_ZN5doris6BucketINS_11DateV2ValueINS_19DateTimeV2ValueTypeEEEEC2ES3_S3_mmm
Line
Count
Source
35
20
            : lower(lower), upper(upper), ndv(ndv), count(count), pre_sum(pre_sum) {}
Unexecuted instantiation: _ZN5doris6BucketINS_16TimeStampNsValueEEC2ES1_S1_mmm
Unexecuted instantiation: _ZN5doris6BucketINS_16TimestampTzValueEEC2ES1_S1_mmm
_ZN5doris6BucketIiEC2Eiimmm
Line
Count
Source
35
108
            : lower(lower), upper(upper), ndv(ndv), count(count), pre_sum(pre_sum) {}
Unexecuted instantiation: _ZN5doris6BucketIhEC2Ehhmmm
_ZN5doris6BucketIaEC2Eaammm
Line
Count
Source
35
20
            : lower(lower), upper(upper), ndv(ndv), count(count), pre_sum(pre_sum) {}
_ZN5doris6BucketIsEC2Essmmm
Line
Count
Source
35
20
            : lower(lower), upper(upper), ndv(ndv), count(count), pre_sum(pre_sum) {}
_ZN5doris6BucketIlEC2Ellmmm
Line
Count
Source
35
20
            : lower(lower), upper(upper), ndv(ndv), count(count), pre_sum(pre_sum) {}
_ZN5doris6BucketInEC2Ennmmm
Line
Count
Source
35
20
            : lower(lower), upper(upper), ndv(ndv), count(count), pre_sum(pre_sum) {}
_ZN5doris6BucketIfEC2Effmmm
Line
Count
Source
35
20
            : lower(lower), upper(upper), ndv(ndv), count(count), pre_sum(pre_sum) {}
_ZN5doris6BucketIdEC2Eddmmm
Line
Count
Source
35
20
            : lower(lower), upper(upper), ndv(ndv), count(count), pre_sum(pre_sum) {}
_ZN5doris6BucketIoEC2Eoommm
Line
Count
Source
35
40
            : lower(lower), upper(upper), ndv(ndv), count(count), pre_sum(pre_sum) {}
36
37
    T lower;
38
    T upper;
39
    size_t ndv;
40
    size_t count;
41
    size_t pre_sum;
42
};
43
44
/**
45
 * Checks if it is possible to assign the provided value_map to the given
46
 * number of buckets such that no bucket has a size larger than max_bucket_size.
47
 *
48
 * @param value_map A mapping of values to their counts.
49
 * @param max_bucket_size The maximum size that any bucket is allowed to have.
50
 * @param num_buckets The number of buckets that we want to assign values to.
51
 *
52
 * @return true if the values can be assigned to the buckets, false otherwise.
53
 */
54
template <typename T>
55
bool can_assign_into_buckets(const std::map<T, size_t>& value_map, const size_t max_bucket_size,
56
404
                             const size_t num_buckets) {
57
404
    if (value_map.empty()) {
58
2
        return false;
59
402
    };
60
61
402
    size_t used_buckets = 1;
62
402
    size_t current_bucket_size = 0;
63
64
57.9k
    for (const auto& [value, count] : value_map) {
65
57.9k
        current_bucket_size += count;
66
67
        // If adding the current value to the current bucket would exceed max_bucket_size,
68
        // then we start a new bucket.
69
57.9k
        if (current_bucket_size > max_bucket_size) {
70
1.40k
            ++used_buckets;
71
1.40k
            current_bucket_size = count;
72
1.40k
        }
73
74
        // If we have used more buckets than num_buckets, we cannot assign the values to buckets.
75
57.9k
        if (used_buckets > num_buckets) {
76
190
            return false;
77
190
        }
78
57.9k
    }
79
80
212
    return true;
81
402
}
_ZN5doris23can_assign_into_bucketsIiEEbRKSt3mapIT_mSt4lessIS2_ESaISt4pairIKS2_mEEEmm
Line
Count
Source
56
158
                             const size_t num_buckets) {
57
158
    if (value_map.empty()) {
58
2
        return false;
59
156
    };
60
61
156
    size_t used_buckets = 1;
62
156
    size_t current_bucket_size = 0;
63
64
2.78k
    for (const auto& [value, count] : value_map) {
65
2.78k
        current_bucket_size += count;
66
67
        // If adding the current value to the current bucket would exceed max_bucket_size,
68
        // then we start a new bucket.
69
2.78k
        if (current_bucket_size > max_bucket_size) {
70
326
            ++used_buckets;
71
326
            current_bucket_size = count;
72
326
        }
73
74
        // If we have used more buckets than num_buckets, we cannot assign the values to buckets.
75
2.78k
        if (used_buckets > num_buckets) {
76
58
            return false;
77
58
        }
78
2.78k
    }
79
80
98
    return true;
81
156
}
Unexecuted instantiation: _ZN5doris23can_assign_into_bucketsIhEEbRKSt3mapIT_mSt4lessIS2_ESaISt4pairIKS2_mEEEmm
_ZN5doris23can_assign_into_bucketsIaEEbRKSt3mapIT_mSt4lessIS2_ESaISt4pairIKS2_mEEEmm
Line
Count
Source
56
26
                             const size_t num_buckets) {
57
26
    if (value_map.empty()) {
58
0
        return false;
59
26
    };
60
61
26
    size_t used_buckets = 1;
62
26
    size_t current_bucket_size = 0;
63
64
2.38k
    for (const auto& [value, count] : value_map) {
65
2.38k
        current_bucket_size += count;
66
67
        // If adding the current value to the current bucket would exceed max_bucket_size,
68
        // then we start a new bucket.
69
2.38k
        if (current_bucket_size > max_bucket_size) {
70
114
            ++used_buckets;
71
114
            current_bucket_size = count;
72
114
        }
73
74
        // If we have used more buckets than num_buckets, we cannot assign the values to buckets.
75
2.38k
        if (used_buckets > num_buckets) {
76
14
            return false;
77
14
        }
78
2.38k
    }
79
80
12
    return true;
81
26
}
_ZN5doris23can_assign_into_bucketsIsEEbRKSt3mapIT_mSt4lessIS2_ESaISt4pairIKS2_mEEEmm
Line
Count
Source
56
26
                             const size_t num_buckets) {
57
26
    if (value_map.empty()) {
58
0
        return false;
59
26
    };
60
61
26
    size_t used_buckets = 1;
62
26
    size_t current_bucket_size = 0;
63
64
2.38k
    for (const auto& [value, count] : value_map) {
65
2.38k
        current_bucket_size += count;
66
67
        // If adding the current value to the current bucket would exceed max_bucket_size,
68
        // then we start a new bucket.
69
2.38k
        if (current_bucket_size > max_bucket_size) {
70
114
            ++used_buckets;
71
114
            current_bucket_size = count;
72
114
        }
73
74
        // If we have used more buckets than num_buckets, we cannot assign the values to buckets.
75
2.38k
        if (used_buckets > num_buckets) {
76
14
            return false;
77
14
        }
78
2.38k
    }
79
80
12
    return true;
81
26
}
_ZN5doris23can_assign_into_bucketsIlEEbRKSt3mapIT_mSt4lessIS2_ESaISt4pairIKS2_mEEEmm
Line
Count
Source
56
26
                             const size_t num_buckets) {
57
26
    if (value_map.empty()) {
58
0
        return false;
59
26
    };
60
61
26
    size_t used_buckets = 1;
62
26
    size_t current_bucket_size = 0;
63
64
2.38k
    for (const auto& [value, count] : value_map) {
65
2.38k
        current_bucket_size += count;
66
67
        // If adding the current value to the current bucket would exceed max_bucket_size,
68
        // then we start a new bucket.
69
2.38k
        if (current_bucket_size > max_bucket_size) {
70
114
            ++used_buckets;
71
114
            current_bucket_size = count;
72
114
        }
73
74
        // If we have used more buckets than num_buckets, we cannot assign the values to buckets.
75
2.38k
        if (used_buckets > num_buckets) {
76
14
            return false;
77
14
        }
78
2.38k
    }
79
80
12
    return true;
81
26
}
_ZN5doris23can_assign_into_bucketsInEEbRKSt3mapIT_mSt4lessIS2_ESaISt4pairIKS2_mEEEmm
Line
Count
Source
56
26
                             const size_t num_buckets) {
57
26
    if (value_map.empty()) {
58
0
        return false;
59
26
    };
60
61
26
    size_t used_buckets = 1;
62
26
    size_t current_bucket_size = 0;
63
64
2.38k
    for (const auto& [value, count] : value_map) {
65
2.38k
        current_bucket_size += count;
66
67
        // If adding the current value to the current bucket would exceed max_bucket_size,
68
        // then we start a new bucket.
69
2.38k
        if (current_bucket_size > max_bucket_size) {
70
114
            ++used_buckets;
71
114
            current_bucket_size = count;
72
114
        }
73
74
        // If we have used more buckets than num_buckets, we cannot assign the values to buckets.
75
2.38k
        if (used_buckets > num_buckets) {
76
14
            return false;
77
14
        }
78
2.38k
    }
79
80
12
    return true;
81
26
}
_ZN5doris23can_assign_into_bucketsIfEEbRKSt3mapIT_mSt4lessIS2_ESaISt4pairIKS2_mEEEmm
Line
Count
Source
56
26
                             const size_t num_buckets) {
57
26
    if (value_map.empty()) {
58
0
        return false;
59
26
    };
60
61
26
    size_t used_buckets = 1;
62
26
    size_t current_bucket_size = 0;
63
64
2.38k
    for (const auto& [value, count] : value_map) {
65
2.38k
        current_bucket_size += count;
66
67
        // If adding the current value to the current bucket would exceed max_bucket_size,
68
        // then we start a new bucket.
69
2.38k
        if (current_bucket_size > max_bucket_size) {
70
114
            ++used_buckets;
71
114
            current_bucket_size = count;
72
114
        }
73
74
        // If we have used more buckets than num_buckets, we cannot assign the values to buckets.
75
2.38k
        if (used_buckets > num_buckets) {
76
14
            return false;
77
14
        }
78
2.38k
    }
79
80
12
    return true;
81
26
}
_ZN5doris23can_assign_into_bucketsIdEEbRKSt3mapIT_mSt4lessIS2_ESaISt4pairIKS2_mEEEmm
Line
Count
Source
56
26
                             const size_t num_buckets) {
57
26
    if (value_map.empty()) {
58
0
        return false;
59
26
    };
60
61
26
    size_t used_buckets = 1;
62
26
    size_t current_bucket_size = 0;
63
64
2.38k
    for (const auto& [value, count] : value_map) {
65
2.38k
        current_bucket_size += count;
66
67
        // If adding the current value to the current bucket would exceed max_bucket_size,
68
        // then we start a new bucket.
69
2.38k
        if (current_bucket_size > max_bucket_size) {
70
114
            ++used_buckets;
71
114
            current_bucket_size = count;
72
114
        }
73
74
        // If we have used more buckets than num_buckets, we cannot assign the values to buckets.
75
2.38k
        if (used_buckets > num_buckets) {
76
14
            return false;
77
14
        }
78
2.38k
    }
79
80
12
    return true;
81
26
}
Unexecuted instantiation: _ZN5doris23can_assign_into_bucketsINS_7DecimalIiEEEEbRKSt3mapIT_mSt4lessIS4_ESaISt4pairIKS4_mEEEmm
Unexecuted instantiation: _ZN5doris23can_assign_into_bucketsINS_7DecimalIlEEEEbRKSt3mapIT_mSt4lessIS4_ESaISt4pairIKS4_mEEEmm
Unexecuted instantiation: _ZN5doris23can_assign_into_bucketsINS_12Decimal128V3EEEbRKSt3mapIT_mSt4lessIS3_ESaISt4pairIKS3_mEEEmm
Unexecuted instantiation: _ZN5doris23can_assign_into_bucketsINS_7DecimalIN4wide7integerILm256EiEEEEEEbRKSt3mapIT_mSt4lessIS7_ESaISt4pairIKS7_mEEEmm
_ZN5doris23can_assign_into_bucketsINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEbRKSt3mapIT_mSt4lessIS8_ESaISt4pairIKS8_mEEEmm
Line
Count
Source
56
38
                             const size_t num_buckets) {
57
38
    if (value_map.empty()) {
58
0
        return false;
59
38
    };
60
61
38
    size_t used_buckets = 1;
62
38
    size_t current_bucket_size = 0;
63
64
36.1k
    for (const auto& [value, count] : value_map) {
65
36.1k
        current_bucket_size += count;
66
67
        // If adding the current value to the current bucket would exceed max_bucket_size,
68
        // then we start a new bucket.
69
36.1k
        if (current_bucket_size > max_bucket_size) {
70
168
            ++used_buckets;
71
168
            current_bucket_size = count;
72
168
        }
73
74
        // If we have used more buckets than num_buckets, we cannot assign the values to buckets.
75
36.1k
        if (used_buckets > num_buckets) {
76
20
            return false;
77
20
        }
78
36.1k
    }
79
80
18
    return true;
81
38
}
_ZN5doris23can_assign_into_bucketsINS_11DateV2ValueINS_15DateV2ValueTypeEEEEEbRKSt3mapIT_mSt4lessIS5_ESaISt4pairIKS5_mEEEmm
Line
Count
Source
56
26
                             const size_t num_buckets) {
57
26
    if (value_map.empty()) {
58
0
        return false;
59
26
    };
60
61
26
    size_t used_buckets = 1;
62
26
    size_t current_bucket_size = 0;
63
64
2.38k
    for (const auto& [value, count] : value_map) {
65
2.38k
        current_bucket_size += count;
66
67
        // If adding the current value to the current bucket would exceed max_bucket_size,
68
        // then we start a new bucket.
69
2.38k
        if (current_bucket_size > max_bucket_size) {
70
114
            ++used_buckets;
71
114
            current_bucket_size = count;
72
114
        }
73
74
        // If we have used more buckets than num_buckets, we cannot assign the values to buckets.
75
2.38k
        if (used_buckets > num_buckets) {
76
14
            return false;
77
14
        }
78
2.38k
    }
79
80
12
    return true;
81
26
}
_ZN5doris23can_assign_into_bucketsINS_11DateV2ValueINS_19DateTimeV2ValueTypeEEEEEbRKSt3mapIT_mSt4lessIS5_ESaISt4pairIKS5_mEEEmm
Line
Count
Source
56
26
                             const size_t num_buckets) {
57
26
    if (value_map.empty()) {
58
0
        return false;
59
26
    };
60
61
26
    size_t used_buckets = 1;
62
26
    size_t current_bucket_size = 0;
63
64
2.38k
    for (const auto& [value, count] : value_map) {
65
2.38k
        current_bucket_size += count;
66
67
        // If adding the current value to the current bucket would exceed max_bucket_size,
68
        // then we start a new bucket.
69
2.38k
        if (current_bucket_size > max_bucket_size) {
70
114
            ++used_buckets;
71
114
            current_bucket_size = count;
72
114
        }
73
74
        // If we have used more buckets than num_buckets, we cannot assign the values to buckets.
75
2.38k
        if (used_buckets > num_buckets) {
76
14
            return false;
77
14
        }
78
2.38k
    }
79
80
12
    return true;
81
26
}
Unexecuted instantiation: _ZN5doris23can_assign_into_bucketsINS_16TimeStampNsValueEEEbRKSt3mapIT_mSt4lessIS3_ESaISt4pairIKS3_mEEEmm
Unexecuted instantiation: _ZN5doris23can_assign_into_bucketsINS_16TimestampTzValueEEEbRKSt3mapIT_mSt4lessIS3_ESaISt4pairIKS3_mEEEmm
Unexecuted instantiation: _ZN5doris23can_assign_into_bucketsIoEEbRKSt3mapIT_mSt4lessIS2_ESaISt4pairIKS2_mEEEmm
82
83
/**
84
 * Calculates the maximum number of values that can fit into each bucket given a set of values
85
 * and the desired number of buckets.
86
 *
87
 * @tparam T the type of the values in the value map
88
 * @param value_map the map of values and their counts
89
 * @param num_buckets the desired number of buckets
90
 * @return the maximum number of values that can fit into each bucket
91
 */
92
template <typename T>
93
128
size_t calculate_bucket_max_values(const std::map<T, size_t>& value_map, const size_t num_buckets) {
94
    // Ensure that the value map is not empty
95
128
    assert(!value_map.empty());
96
97
    // Calculate the total number of values in the map using std::accumulate()
98
128
    size_t total_values = 0;
99
7.76k
    for (const auto& [value, count] : value_map) {
100
7.76k
        total_values += count;
101
7.76k
    }
102
103
    // If there is only one bucket, then all values will be assigned to that bucket
104
128
    if (num_buckets == 1) {
105
34
        return total_values;
106
34
    }
107
108
    // To calculate the maximum value count in each bucket, we first calculate a conservative upper
109
    // bound, which is equal to 2 * total_values / (max_buckets - 1) + 1. This upper bound may exceed
110
    // the actual maximum value count, but it does not underestimate it. The subsequent binary search
111
    // algorithm will approach the actual maximum value count.
112
94
    size_t upper_bucket_values = 2 * total_values / (num_buckets - 1) + 1;
113
114
    // Initialize the lower bound to 0
115
94
    size_t lower_bucket_values = 0;
116
117
    // Perform a binary search to find the maximum number of values that can fit into each bucket
118
94
    int search_step = 0;
119
94
    const int max_search_steps =
120
94
            10; // Limit the number of search steps to avoid excessive iteration
121
122
470
    while (upper_bucket_values > lower_bucket_values + 1 && search_step < max_search_steps) {
123
        // Calculate the midpoint of the upper and lower bounds
124
376
        const size_t bucket_values = (upper_bucket_values + lower_bucket_values) / 2;
125
126
        // Check if the given number of values can be assigned to the desired number of buckets
127
376
        if (can_assign_into_buckets(value_map, bucket_values, num_buckets)) {
128
            // If it can, then set the upper bound to the midpoint
129
198
            upper_bucket_values = bucket_values;
130
198
        } else {
131
            // If it can't, then set the lower bound to the midpoint
132
178
            lower_bucket_values = bucket_values;
133
178
        }
134
        // Increment the search step counter
135
376
        ++search_step;
136
376
    }
137
138
94
    return upper_bucket_values;
139
128
}
_ZN5doris27calculate_bucket_max_valuesIiEEmRKSt3mapIT_mSt4lessIS2_ESaISt4pairIKS2_mEEEm
Line
Count
Source
93
84
size_t calculate_bucket_max_values(const std::map<T, size_t>& value_map, const size_t num_buckets) {
94
    // Ensure that the value map is not empty
95
84
    assert(!value_map.empty());
96
97
    // Calculate the total number of values in the map using std::accumulate()
98
84
    size_t total_values = 0;
99
522
    for (const auto& [value, count] : value_map) {
100
522
        total_values += count;
101
522
    }
102
103
    // If there is only one bucket, then all values will be assigned to that bucket
104
84
    if (num_buckets == 1) {
105
34
        return total_values;
106
34
    }
107
108
    // To calculate the maximum value count in each bucket, we first calculate a conservative upper
109
    // bound, which is equal to 2 * total_values / (max_buckets - 1) + 1. This upper bound may exceed
110
    // the actual maximum value count, but it does not underestimate it. The subsequent binary search
111
    // algorithm will approach the actual maximum value count.
112
50
    size_t upper_bucket_values = 2 * total_values / (num_buckets - 1) + 1;
113
114
    // Initialize the lower bound to 0
115
50
    size_t lower_bucket_values = 0;
116
117
    // Perform a binary search to find the maximum number of values that can fit into each bucket
118
50
    int search_step = 0;
119
50
    const int max_search_steps =
120
50
            10; // Limit the number of search steps to avoid excessive iteration
121
122
180
    while (upper_bucket_values > lower_bucket_values + 1 && search_step < max_search_steps) {
123
        // Calculate the midpoint of the upper and lower bounds
124
130
        const size_t bucket_values = (upper_bucket_values + lower_bucket_values) / 2;
125
126
        // Check if the given number of values can be assigned to the desired number of buckets
127
130
        if (can_assign_into_buckets(value_map, bucket_values, num_buckets)) {
128
            // If it can, then set the upper bound to the midpoint
129
84
            upper_bucket_values = bucket_values;
130
84
        } else {
131
            // If it can't, then set the lower bound to the midpoint
132
46
            lower_bucket_values = bucket_values;
133
46
        }
134
        // Increment the search step counter
135
130
        ++search_step;
136
130
    }
137
138
50
    return upper_bucket_values;
139
84
}
Unexecuted instantiation: _ZN5doris27calculate_bucket_max_valuesIhEEmRKSt3mapIT_mSt4lessIS2_ESaISt4pairIKS2_mEEEm
_ZN5doris27calculate_bucket_max_valuesIaEEmRKSt3mapIT_mSt4lessIS2_ESaISt4pairIKS2_mEEEm
Line
Count
Source
93
4
size_t calculate_bucket_max_values(const std::map<T, size_t>& value_map, const size_t num_buckets) {
94
    // Ensure that the value map is not empty
95
4
    assert(!value_map.empty());
96
97
    // Calculate the total number of values in the map using std::accumulate()
98
4
    size_t total_values = 0;
99
400
    for (const auto& [value, count] : value_map) {
100
400
        total_values += count;
101
400
    }
102
103
    // If there is only one bucket, then all values will be assigned to that bucket
104
4
    if (num_buckets == 1) {
105
0
        return total_values;
106
0
    }
107
108
    // To calculate the maximum value count in each bucket, we first calculate a conservative upper
109
    // bound, which is equal to 2 * total_values / (max_buckets - 1) + 1. This upper bound may exceed
110
    // the actual maximum value count, but it does not underestimate it. The subsequent binary search
111
    // algorithm will approach the actual maximum value count.
112
4
    size_t upper_bucket_values = 2 * total_values / (num_buckets - 1) + 1;
113
114
    // Initialize the lower bound to 0
115
4
    size_t lower_bucket_values = 0;
116
117
    // Perform a binary search to find the maximum number of values that can fit into each bucket
118
4
    int search_step = 0;
119
4
    const int max_search_steps =
120
4
            10; // Limit the number of search steps to avoid excessive iteration
121
122
30
    while (upper_bucket_values > lower_bucket_values + 1 && search_step < max_search_steps) {
123
        // Calculate the midpoint of the upper and lower bounds
124
26
        const size_t bucket_values = (upper_bucket_values + lower_bucket_values) / 2;
125
126
        // Check if the given number of values can be assigned to the desired number of buckets
127
26
        if (can_assign_into_buckets(value_map, bucket_values, num_buckets)) {
128
            // If it can, then set the upper bound to the midpoint
129
12
            upper_bucket_values = bucket_values;
130
14
        } else {
131
            // If it can't, then set the lower bound to the midpoint
132
14
            lower_bucket_values = bucket_values;
133
14
        }
134
        // Increment the search step counter
135
26
        ++search_step;
136
26
    }
137
138
4
    return upper_bucket_values;
139
4
}
_ZN5doris27calculate_bucket_max_valuesIsEEmRKSt3mapIT_mSt4lessIS2_ESaISt4pairIKS2_mEEEm
Line
Count
Source
93
4
size_t calculate_bucket_max_values(const std::map<T, size_t>& value_map, const size_t num_buckets) {
94
    // Ensure that the value map is not empty
95
4
    assert(!value_map.empty());
96
97
    // Calculate the total number of values in the map using std::accumulate()
98
4
    size_t total_values = 0;
99
400
    for (const auto& [value, count] : value_map) {
100
400
        total_values += count;
101
400
    }
102
103
    // If there is only one bucket, then all values will be assigned to that bucket
104
4
    if (num_buckets == 1) {
105
0
        return total_values;
106
0
    }
107
108
    // To calculate the maximum value count in each bucket, we first calculate a conservative upper
109
    // bound, which is equal to 2 * total_values / (max_buckets - 1) + 1. This upper bound may exceed
110
    // the actual maximum value count, but it does not underestimate it. The subsequent binary search
111
    // algorithm will approach the actual maximum value count.
112
4
    size_t upper_bucket_values = 2 * total_values / (num_buckets - 1) + 1;
113
114
    // Initialize the lower bound to 0
115
4
    size_t lower_bucket_values = 0;
116
117
    // Perform a binary search to find the maximum number of values that can fit into each bucket
118
4
    int search_step = 0;
119
4
    const int max_search_steps =
120
4
            10; // Limit the number of search steps to avoid excessive iteration
121
122
30
    while (upper_bucket_values > lower_bucket_values + 1 && search_step < max_search_steps) {
123
        // Calculate the midpoint of the upper and lower bounds
124
26
        const size_t bucket_values = (upper_bucket_values + lower_bucket_values) / 2;
125
126
        // Check if the given number of values can be assigned to the desired number of buckets
127
26
        if (can_assign_into_buckets(value_map, bucket_values, num_buckets)) {
128
            // If it can, then set the upper bound to the midpoint
129
12
            upper_bucket_values = bucket_values;
130
14
        } else {
131
            // If it can't, then set the lower bound to the midpoint
132
14
            lower_bucket_values = bucket_values;
133
14
        }
134
        // Increment the search step counter
135
26
        ++search_step;
136
26
    }
137
138
4
    return upper_bucket_values;
139
4
}
_ZN5doris27calculate_bucket_max_valuesIlEEmRKSt3mapIT_mSt4lessIS2_ESaISt4pairIKS2_mEEEm
Line
Count
Source
93
4
size_t calculate_bucket_max_values(const std::map<T, size_t>& value_map, const size_t num_buckets) {
94
    // Ensure that the value map is not empty
95
4
    assert(!value_map.empty());
96
97
    // Calculate the total number of values in the map using std::accumulate()
98
4
    size_t total_values = 0;
99
400
    for (const auto& [value, count] : value_map) {
100
400
        total_values += count;
101
400
    }
102
103
    // If there is only one bucket, then all values will be assigned to that bucket
104
4
    if (num_buckets == 1) {
105
0
        return total_values;
106
0
    }
107
108
    // To calculate the maximum value count in each bucket, we first calculate a conservative upper
109
    // bound, which is equal to 2 * total_values / (max_buckets - 1) + 1. This upper bound may exceed
110
    // the actual maximum value count, but it does not underestimate it. The subsequent binary search
111
    // algorithm will approach the actual maximum value count.
112
4
    size_t upper_bucket_values = 2 * total_values / (num_buckets - 1) + 1;
113
114
    // Initialize the lower bound to 0
115
4
    size_t lower_bucket_values = 0;
116
117
    // Perform a binary search to find the maximum number of values that can fit into each bucket
118
4
    int search_step = 0;
119
4
    const int max_search_steps =
120
4
            10; // Limit the number of search steps to avoid excessive iteration
121
122
30
    while (upper_bucket_values > lower_bucket_values + 1 && search_step < max_search_steps) {
123
        // Calculate the midpoint of the upper and lower bounds
124
26
        const size_t bucket_values = (upper_bucket_values + lower_bucket_values) / 2;
125
126
        // Check if the given number of values can be assigned to the desired number of buckets
127
26
        if (can_assign_into_buckets(value_map, bucket_values, num_buckets)) {
128
            // If it can, then set the upper bound to the midpoint
129
12
            upper_bucket_values = bucket_values;
130
14
        } else {
131
            // If it can't, then set the lower bound to the midpoint
132
14
            lower_bucket_values = bucket_values;
133
14
        }
134
        // Increment the search step counter
135
26
        ++search_step;
136
26
    }
137
138
4
    return upper_bucket_values;
139
4
}
_ZN5doris27calculate_bucket_max_valuesInEEmRKSt3mapIT_mSt4lessIS2_ESaISt4pairIKS2_mEEEm
Line
Count
Source
93
4
size_t calculate_bucket_max_values(const std::map<T, size_t>& value_map, const size_t num_buckets) {
94
    // Ensure that the value map is not empty
95
4
    assert(!value_map.empty());
96
97
    // Calculate the total number of values in the map using std::accumulate()
98
4
    size_t total_values = 0;
99
400
    for (const auto& [value, count] : value_map) {
100
400
        total_values += count;
101
400
    }
102
103
    // If there is only one bucket, then all values will be assigned to that bucket
104
4
    if (num_buckets == 1) {
105
0
        return total_values;
106
0
    }
107
108
    // To calculate the maximum value count in each bucket, we first calculate a conservative upper
109
    // bound, which is equal to 2 * total_values / (max_buckets - 1) + 1. This upper bound may exceed
110
    // the actual maximum value count, but it does not underestimate it. The subsequent binary search
111
    // algorithm will approach the actual maximum value count.
112
4
    size_t upper_bucket_values = 2 * total_values / (num_buckets - 1) + 1;
113
114
    // Initialize the lower bound to 0
115
4
    size_t lower_bucket_values = 0;
116
117
    // Perform a binary search to find the maximum number of values that can fit into each bucket
118
4
    int search_step = 0;
119
4
    const int max_search_steps =
120
4
            10; // Limit the number of search steps to avoid excessive iteration
121
122
30
    while (upper_bucket_values > lower_bucket_values + 1 && search_step < max_search_steps) {
123
        // Calculate the midpoint of the upper and lower bounds
124
26
        const size_t bucket_values = (upper_bucket_values + lower_bucket_values) / 2;
125
126
        // Check if the given number of values can be assigned to the desired number of buckets
127
26
        if (can_assign_into_buckets(value_map, bucket_values, num_buckets)) {
128
            // If it can, then set the upper bound to the midpoint
129
12
            upper_bucket_values = bucket_values;
130
14
        } else {
131
            // If it can't, then set the lower bound to the midpoint
132
14
            lower_bucket_values = bucket_values;
133
14
        }
134
        // Increment the search step counter
135
26
        ++search_step;
136
26
    }
137
138
4
    return upper_bucket_values;
139
4
}
_ZN5doris27calculate_bucket_max_valuesIfEEmRKSt3mapIT_mSt4lessIS2_ESaISt4pairIKS2_mEEEm
Line
Count
Source
93
4
size_t calculate_bucket_max_values(const std::map<T, size_t>& value_map, const size_t num_buckets) {
94
    // Ensure that the value map is not empty
95
4
    assert(!value_map.empty());
96
97
    // Calculate the total number of values in the map using std::accumulate()
98
4
    size_t total_values = 0;
99
400
    for (const auto& [value, count] : value_map) {
100
400
        total_values += count;
101
400
    }
102
103
    // If there is only one bucket, then all values will be assigned to that bucket
104
4
    if (num_buckets == 1) {
105
0
        return total_values;
106
0
    }
107
108
    // To calculate the maximum value count in each bucket, we first calculate a conservative upper
109
    // bound, which is equal to 2 * total_values / (max_buckets - 1) + 1. This upper bound may exceed
110
    // the actual maximum value count, but it does not underestimate it. The subsequent binary search
111
    // algorithm will approach the actual maximum value count.
112
4
    size_t upper_bucket_values = 2 * total_values / (num_buckets - 1) + 1;
113
114
    // Initialize the lower bound to 0
115
4
    size_t lower_bucket_values = 0;
116
117
    // Perform a binary search to find the maximum number of values that can fit into each bucket
118
4
    int search_step = 0;
119
4
    const int max_search_steps =
120
4
            10; // Limit the number of search steps to avoid excessive iteration
121
122
30
    while (upper_bucket_values > lower_bucket_values + 1 && search_step < max_search_steps) {
123
        // Calculate the midpoint of the upper and lower bounds
124
26
        const size_t bucket_values = (upper_bucket_values + lower_bucket_values) / 2;
125
126
        // Check if the given number of values can be assigned to the desired number of buckets
127
26
        if (can_assign_into_buckets(value_map, bucket_values, num_buckets)) {
128
            // If it can, then set the upper bound to the midpoint
129
12
            upper_bucket_values = bucket_values;
130
14
        } else {
131
            // If it can't, then set the lower bound to the midpoint
132
14
            lower_bucket_values = bucket_values;
133
14
        }
134
        // Increment the search step counter
135
26
        ++search_step;
136
26
    }
137
138
4
    return upper_bucket_values;
139
4
}
_ZN5doris27calculate_bucket_max_valuesIdEEmRKSt3mapIT_mSt4lessIS2_ESaISt4pairIKS2_mEEEm
Line
Count
Source
93
4
size_t calculate_bucket_max_values(const std::map<T, size_t>& value_map, const size_t num_buckets) {
94
    // Ensure that the value map is not empty
95
4
    assert(!value_map.empty());
96
97
    // Calculate the total number of values in the map using std::accumulate()
98
4
    size_t total_values = 0;
99
400
    for (const auto& [value, count] : value_map) {
100
400
        total_values += count;
101
400
    }
102
103
    // If there is only one bucket, then all values will be assigned to that bucket
104
4
    if (num_buckets == 1) {
105
0
        return total_values;
106
0
    }
107
108
    // To calculate the maximum value count in each bucket, we first calculate a conservative upper
109
    // bound, which is equal to 2 * total_values / (max_buckets - 1) + 1. This upper bound may exceed
110
    // the actual maximum value count, but it does not underestimate it. The subsequent binary search
111
    // algorithm will approach the actual maximum value count.
112
4
    size_t upper_bucket_values = 2 * total_values / (num_buckets - 1) + 1;
113
114
    // Initialize the lower bound to 0
115
4
    size_t lower_bucket_values = 0;
116
117
    // Perform a binary search to find the maximum number of values that can fit into each bucket
118
4
    int search_step = 0;
119
4
    const int max_search_steps =
120
4
            10; // Limit the number of search steps to avoid excessive iteration
121
122
30
    while (upper_bucket_values > lower_bucket_values + 1 && search_step < max_search_steps) {
123
        // Calculate the midpoint of the upper and lower bounds
124
26
        const size_t bucket_values = (upper_bucket_values + lower_bucket_values) / 2;
125
126
        // Check if the given number of values can be assigned to the desired number of buckets
127
26
        if (can_assign_into_buckets(value_map, bucket_values, num_buckets)) {
128
            // If it can, then set the upper bound to the midpoint
129
12
            upper_bucket_values = bucket_values;
130
14
        } else {
131
            // If it can't, then set the lower bound to the midpoint
132
14
            lower_bucket_values = bucket_values;
133
14
        }
134
        // Increment the search step counter
135
26
        ++search_step;
136
26
    }
137
138
4
    return upper_bucket_values;
139
4
}
Unexecuted instantiation: _ZN5doris27calculate_bucket_max_valuesINS_7DecimalIiEEEEmRKSt3mapIT_mSt4lessIS4_ESaISt4pairIKS4_mEEEm
Unexecuted instantiation: _ZN5doris27calculate_bucket_max_valuesINS_7DecimalIlEEEEmRKSt3mapIT_mSt4lessIS4_ESaISt4pairIKS4_mEEEm
Unexecuted instantiation: _ZN5doris27calculate_bucket_max_valuesINS_12Decimal128V3EEEmRKSt3mapIT_mSt4lessIS3_ESaISt4pairIKS3_mEEEm
Unexecuted instantiation: _ZN5doris27calculate_bucket_max_valuesINS_7DecimalIN4wide7integerILm256EiEEEEEEmRKSt3mapIT_mSt4lessIS7_ESaISt4pairIKS7_mEEEm
_ZN5doris27calculate_bucket_max_valuesINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEmRKSt3mapIT_mSt4lessIS8_ESaISt4pairIKS8_mEEEm
Line
Count
Source
93
4
size_t calculate_bucket_max_values(const std::map<T, size_t>& value_map, const size_t num_buckets) {
94
    // Ensure that the value map is not empty
95
4
    assert(!value_map.empty());
96
97
    // Calculate the total number of values in the map using std::accumulate()
98
4
    size_t total_values = 0;
99
4.00k
    for (const auto& [value, count] : value_map) {
100
4.00k
        total_values += count;
101
4.00k
    }
102
103
    // If there is only one bucket, then all values will be assigned to that bucket
104
4
    if (num_buckets == 1) {
105
0
        return total_values;
106
0
    }
107
108
    // To calculate the maximum value count in each bucket, we first calculate a conservative upper
109
    // bound, which is equal to 2 * total_values / (max_buckets - 1) + 1. This upper bound may exceed
110
    // the actual maximum value count, but it does not underestimate it. The subsequent binary search
111
    // algorithm will approach the actual maximum value count.
112
4
    size_t upper_bucket_values = 2 * total_values / (num_buckets - 1) + 1;
113
114
    // Initialize the lower bound to 0
115
4
    size_t lower_bucket_values = 0;
116
117
    // Perform a binary search to find the maximum number of values that can fit into each bucket
118
4
    int search_step = 0;
119
4
    const int max_search_steps =
120
4
            10; // Limit the number of search steps to avoid excessive iteration
121
122
42
    while (upper_bucket_values > lower_bucket_values + 1 && search_step < max_search_steps) {
123
        // Calculate the midpoint of the upper and lower bounds
124
38
        const size_t bucket_values = (upper_bucket_values + lower_bucket_values) / 2;
125
126
        // Check if the given number of values can be assigned to the desired number of buckets
127
38
        if (can_assign_into_buckets(value_map, bucket_values, num_buckets)) {
128
            // If it can, then set the upper bound to the midpoint
129
18
            upper_bucket_values = bucket_values;
130
20
        } else {
131
            // If it can't, then set the lower bound to the midpoint
132
20
            lower_bucket_values = bucket_values;
133
20
        }
134
        // Increment the search step counter
135
38
        ++search_step;
136
38
    }
137
138
4
    return upper_bucket_values;
139
4
}
_ZN5doris27calculate_bucket_max_valuesINS_11DateV2ValueINS_15DateV2ValueTypeEEEEEmRKSt3mapIT_mSt4lessIS5_ESaISt4pairIKS5_mEEEm
Line
Count
Source
93
4
size_t calculate_bucket_max_values(const std::map<T, size_t>& value_map, const size_t num_buckets) {
94
    // Ensure that the value map is not empty
95
4
    assert(!value_map.empty());
96
97
    // Calculate the total number of values in the map using std::accumulate()
98
4
    size_t total_values = 0;
99
400
    for (const auto& [value, count] : value_map) {
100
400
        total_values += count;
101
400
    }
102
103
    // If there is only one bucket, then all values will be assigned to that bucket
104
4
    if (num_buckets == 1) {
105
0
        return total_values;
106
0
    }
107
108
    // To calculate the maximum value count in each bucket, we first calculate a conservative upper
109
    // bound, which is equal to 2 * total_values / (max_buckets - 1) + 1. This upper bound may exceed
110
    // the actual maximum value count, but it does not underestimate it. The subsequent binary search
111
    // algorithm will approach the actual maximum value count.
112
4
    size_t upper_bucket_values = 2 * total_values / (num_buckets - 1) + 1;
113
114
    // Initialize the lower bound to 0
115
4
    size_t lower_bucket_values = 0;
116
117
    // Perform a binary search to find the maximum number of values that can fit into each bucket
118
4
    int search_step = 0;
119
4
    const int max_search_steps =
120
4
            10; // Limit the number of search steps to avoid excessive iteration
121
122
30
    while (upper_bucket_values > lower_bucket_values + 1 && search_step < max_search_steps) {
123
        // Calculate the midpoint of the upper and lower bounds
124
26
        const size_t bucket_values = (upper_bucket_values + lower_bucket_values) / 2;
125
126
        // Check if the given number of values can be assigned to the desired number of buckets
127
26
        if (can_assign_into_buckets(value_map, bucket_values, num_buckets)) {
128
            // If it can, then set the upper bound to the midpoint
129
12
            upper_bucket_values = bucket_values;
130
14
        } else {
131
            // If it can't, then set the lower bound to the midpoint
132
14
            lower_bucket_values = bucket_values;
133
14
        }
134
        // Increment the search step counter
135
26
        ++search_step;
136
26
    }
137
138
4
    return upper_bucket_values;
139
4
}
_ZN5doris27calculate_bucket_max_valuesINS_11DateV2ValueINS_19DateTimeV2ValueTypeEEEEEmRKSt3mapIT_mSt4lessIS5_ESaISt4pairIKS5_mEEEm
Line
Count
Source
93
4
size_t calculate_bucket_max_values(const std::map<T, size_t>& value_map, const size_t num_buckets) {
94
    // Ensure that the value map is not empty
95
4
    assert(!value_map.empty());
96
97
    // Calculate the total number of values in the map using std::accumulate()
98
4
    size_t total_values = 0;
99
400
    for (const auto& [value, count] : value_map) {
100
400
        total_values += count;
101
400
    }
102
103
    // If there is only one bucket, then all values will be assigned to that bucket
104
4
    if (num_buckets == 1) {
105
0
        return total_values;
106
0
    }
107
108
    // To calculate the maximum value count in each bucket, we first calculate a conservative upper
109
    // bound, which is equal to 2 * total_values / (max_buckets - 1) + 1. This upper bound may exceed
110
    // the actual maximum value count, but it does not underestimate it. The subsequent binary search
111
    // algorithm will approach the actual maximum value count.
112
4
    size_t upper_bucket_values = 2 * total_values / (num_buckets - 1) + 1;
113
114
    // Initialize the lower bound to 0
115
4
    size_t lower_bucket_values = 0;
116
117
    // Perform a binary search to find the maximum number of values that can fit into each bucket
118
4
    int search_step = 0;
119
4
    const int max_search_steps =
120
4
            10; // Limit the number of search steps to avoid excessive iteration
121
122
30
    while (upper_bucket_values > lower_bucket_values + 1 && search_step < max_search_steps) {
123
        // Calculate the midpoint of the upper and lower bounds
124
26
        const size_t bucket_values = (upper_bucket_values + lower_bucket_values) / 2;
125
126
        // Check if the given number of values can be assigned to the desired number of buckets
127
26
        if (can_assign_into_buckets(value_map, bucket_values, num_buckets)) {
128
            // If it can, then set the upper bound to the midpoint
129
12
            upper_bucket_values = bucket_values;
130
14
        } else {
131
            // If it can't, then set the lower bound to the midpoint
132
14
            lower_bucket_values = bucket_values;
133
14
        }
134
        // Increment the search step counter
135
26
        ++search_step;
136
26
    }
137
138
4
    return upper_bucket_values;
139
4
}
Unexecuted instantiation: _ZN5doris27calculate_bucket_max_valuesINS_16TimeStampNsValueEEEmRKSt3mapIT_mSt4lessIS3_ESaISt4pairIKS3_mEEEm
Unexecuted instantiation: _ZN5doris27calculate_bucket_max_valuesINS_16TimestampTzValueEEEmRKSt3mapIT_mSt4lessIS3_ESaISt4pairIKS3_mEEEm
_ZN5doris27calculate_bucket_max_valuesIoEEmRKSt3mapIT_mSt4lessIS2_ESaISt4pairIKS2_mEEEm
Line
Count
Source
93
8
size_t calculate_bucket_max_values(const std::map<T, size_t>& value_map, const size_t num_buckets) {
94
    // Ensure that the value map is not empty
95
8
    assert(!value_map.empty());
96
97
    // Calculate the total number of values in the map using std::accumulate()
98
8
    size_t total_values = 0;
99
40
    for (const auto& [value, count] : value_map) {
100
40
        total_values += count;
101
40
    }
102
103
    // If there is only one bucket, then all values will be assigned to that bucket
104
8
    if (num_buckets == 1) {
105
0
        return total_values;
106
0
    }
107
108
    // To calculate the maximum value count in each bucket, we first calculate a conservative upper
109
    // bound, which is equal to 2 * total_values / (max_buckets - 1) + 1. This upper bound may exceed
110
    // the actual maximum value count, but it does not underestimate it. The subsequent binary search
111
    // algorithm will approach the actual maximum value count.
112
8
    size_t upper_bucket_values = 2 * total_values / (num_buckets - 1) + 1;
113
114
    // Initialize the lower bound to 0
115
8
    size_t lower_bucket_values = 0;
116
117
    // Perform a binary search to find the maximum number of values that can fit into each bucket
118
8
    int search_step = 0;
119
8
    const int max_search_steps =
120
8
            10; // Limit the number of search steps to avoid excessive iteration
121
122
8
    while (upper_bucket_values > lower_bucket_values + 1 && search_step < max_search_steps) {
123
        // Calculate the midpoint of the upper and lower bounds
124
0
        const size_t bucket_values = (upper_bucket_values + lower_bucket_values) / 2;
125
126
        // Check if the given number of values can be assigned to the desired number of buckets
127
0
        if (can_assign_into_buckets(value_map, bucket_values, num_buckets)) {
128
            // If it can, then set the upper bound to the midpoint
129
0
            upper_bucket_values = bucket_values;
130
0
        } else {
131
            // If it can't, then set the lower bound to the midpoint
132
0
            lower_bucket_values = bucket_values;
133
0
        }
134
        // Increment the search step counter
135
0
        ++search_step;
136
0
    }
137
138
8
    return upper_bucket_values;
139
8
}
140
141
/**
142
 * Greedy equi-height histogram construction algorithm, inspired by the MySQL
143
 * equi_height implementation(https://dev.mysql.com/doc/dev/mysql-server/latest/equi__height_8h.html).
144
 *
145
 * Given an ordered collection of [value, count] pairs and a maximum bucket
146
 * size, construct a histogram by inserting values into a bucket while keeping
147
 * track of its size. If the insertion of a value into a non-empty bucket
148
 * causes the bucket to exceed the maximum size, create a new empty bucket and
149
 * continue.
150
 *
151
 * The algorithm guarantees a selectivity estimation error of at most ~2 *
152
 * #values / #buckets, often less. Values with a higher relative frequency are
153
 * guaranteed to be placed in singleton buckets.
154
 *
155
 * The minimum composite bucket size is used to minimize the worst case
156
 * selectivity estimation error. In general, the algorithm will adapt to the
157
 * data distribution to minimize the size of composite buckets. The heavy values
158
 * can be placed in singleton buckets and the remaining values will be evenly
159
 * spread across the remaining buckets, leading to a lower composite bucket size.
160
 *
161
 * Note: The term "value" refers to an entry in a column and the actual value
162
 * of an entry. The ordered_map is an ordered collection of [distinct value,
163
 * value count] pairs. For example, a Value_map<String> could contain the pairs ["a", 1], ["b", 2]
164
 * to represent one "a" value and two "b" values.
165
 *
166
 * @param buckets A vector of empty buckets that will be populated with data.
167
 * @param ordered_map An ordered map of distinct values and their counts.
168
 * @param max_num_buckets The maximum number of buckets that can be used.
169
 *
170
 * @return True if the buckets were successfully built, false otherwise.
171
 */
172
template <typename T>
173
bool build_histogram(std::vector<Bucket<T>>& buckets, const std::map<T, size_t>& ordered_map,
174
154
                     const size_t max_num_buckets) {
175
    // If the input map is empty, there is nothing to build.
176
154
    if (ordered_map.empty()) {
177
38
        return false;
178
38
    }
179
180
    // Calculate the maximum number of values that can be assigned to each bucket.
181
116
    auto bucket_max_values = calculate_bucket_max_values(ordered_map, max_num_buckets);
182
183
    // Ensure that the capacity is at least max_num_buckets in order to avoid the overhead of additional
184
    // allocations when inserting buckets.
185
116
    buckets.clear();
186
116
    buckets.reserve(max_num_buckets);
187
188
    // Initialize bucket variables.
189
116
    size_t distinct_values_count = 0;
190
116
    size_t values_count = 0;
191
116
    size_t cumulative_values = 0;
192
193
    // Record how many values still need to be assigned.
194
116
    auto remaining_distinct_values = ordered_map.size();
195
196
116
    auto it = ordered_map.begin();
197
198
    // Lower value of the current bucket.
199
116
    const T* lower_value = &it->first;
200
201
    // Iterate over the ordered map of distinct values and their counts.
202
7.85k
    for (; it != ordered_map.end(); ++it) {
203
7.73k
        const auto count = it->second;
204
7.73k
        const auto current_value = it->first;
205
206
        // Update the bucket counts and track the number of distinct values assigned.
207
7.73k
        distinct_values_count++;
208
7.73k
        remaining_distinct_values--;
209
7.73k
        values_count += count;
210
7.73k
        cumulative_values += count;
211
212
        // Check whether the current value should be added to the current bucket.
213
7.73k
        auto next = std::next(it);
214
7.73k
        size_t remaining_empty_buckets = max_num_buckets - buckets.size() - 1;
215
216
7.73k
        if (next != ordered_map.end() && remaining_distinct_values > remaining_empty_buckets &&
217
7.73k
            values_count + next->second <= bucket_max_values) {
218
            // If the current value is the last in the input map and there are more remaining
219
            // distinct values than empty buckets and adding the value does not cause the bucket
220
            // to exceed its max size, skip adding the value to the current bucket.
221
7.41k
            continue;
222
7.41k
        }
223
224
        // Finalize the current bucket and add it to our collection of buckets.
225
324
        auto pre_sum = cumulative_values - values_count;
226
227
324
        Bucket<T> new_bucket(*lower_value, current_value, distinct_values_count, values_count,
228
324
                             pre_sum);
229
324
        buckets.push_back(new_bucket);
230
231
        // Reset variables for the next bucket.
232
324
        if (next != ordered_map.end()) {
233
208
            lower_value = &next->first;
234
208
        }
235
324
        values_count = 0;
236
324
        distinct_values_count = 0;
237
324
    }
238
239
116
    return true;
240
154
}
_ZN5doris15build_histogramIiEEbRSt6vectorINS_6BucketIT_EESaIS4_EERKSt3mapIS3_mSt4lessIS3_ESaISt4pairIKS3_mEEEm
Line
Count
Source
174
78
                     const size_t max_num_buckets) {
175
    // If the input map is empty, there is nothing to build.
176
78
    if (ordered_map.empty()) {
177
6
        return false;
178
6
    }
179
180
    // Calculate the maximum number of values that can be assigned to each bucket.
181
72
    auto bucket_max_values = calculate_bucket_max_values(ordered_map, max_num_buckets);
182
183
    // Ensure that the capacity is at least max_num_buckets in order to avoid the overhead of additional
184
    // allocations when inserting buckets.
185
72
    buckets.clear();
186
72
    buckets.reserve(max_num_buckets);
187
188
    // Initialize bucket variables.
189
72
    size_t distinct_values_count = 0;
190
72
    size_t values_count = 0;
191
72
    size_t cumulative_values = 0;
192
193
    // Record how many values still need to be assigned.
194
72
    auto remaining_distinct_values = ordered_map.size();
195
196
72
    auto it = ordered_map.begin();
197
198
    // Lower value of the current bucket.
199
72
    const T* lower_value = &it->first;
200
201
    // Iterate over the ordered map of distinct values and their counts.
202
570
    for (; it != ordered_map.end(); ++it) {
203
498
        const auto count = it->second;
204
498
        const auto current_value = it->first;
205
206
        // Update the bucket counts and track the number of distinct values assigned.
207
498
        distinct_values_count++;
208
498
        remaining_distinct_values--;
209
498
        values_count += count;
210
498
        cumulative_values += count;
211
212
        // Check whether the current value should be added to the current bucket.
213
498
        auto next = std::next(it);
214
498
        size_t remaining_empty_buckets = max_num_buckets - buckets.size() - 1;
215
216
498
        if (next != ordered_map.end() && remaining_distinct_values > remaining_empty_buckets &&
217
498
            values_count + next->second <= bucket_max_values) {
218
            // If the current value is the last in the input map and there are more remaining
219
            // distinct values than empty buckets and adding the value does not cause the bucket
220
            // to exceed its max size, skip adding the value to the current bucket.
221
394
            continue;
222
394
        }
223
224
        // Finalize the current bucket and add it to our collection of buckets.
225
104
        auto pre_sum = cumulative_values - values_count;
226
227
104
        Bucket<T> new_bucket(*lower_value, current_value, distinct_values_count, values_count,
228
104
                             pre_sum);
229
104
        buckets.push_back(new_bucket);
230
231
        // Reset variables for the next bucket.
232
104
        if (next != ordered_map.end()) {
233
32
            lower_value = &next->first;
234
32
        }
235
104
        values_count = 0;
236
104
        distinct_values_count = 0;
237
104
    }
238
239
72
    return true;
240
78
}
Unexecuted instantiation: _ZN5doris15build_histogramIhEEbRSt6vectorINS_6BucketIT_EESaIS4_EERKSt3mapIS3_mSt4lessIS3_ESaISt4pairIKS3_mEEEm
_ZN5doris15build_histogramIaEEbRSt6vectorINS_6BucketIT_EESaIS4_EERKSt3mapIS3_mSt4lessIS3_ESaISt4pairIKS3_mEEEm
Line
Count
Source
174
8
                     const size_t max_num_buckets) {
175
    // If the input map is empty, there is nothing to build.
176
8
    if (ordered_map.empty()) {
177
4
        return false;
178
4
    }
179
180
    // Calculate the maximum number of values that can be assigned to each bucket.
181
4
    auto bucket_max_values = calculate_bucket_max_values(ordered_map, max_num_buckets);
182
183
    // Ensure that the capacity is at least max_num_buckets in order to avoid the overhead of additional
184
    // allocations when inserting buckets.
185
4
    buckets.clear();
186
4
    buckets.reserve(max_num_buckets);
187
188
    // Initialize bucket variables.
189
4
    size_t distinct_values_count = 0;
190
4
    size_t values_count = 0;
191
4
    size_t cumulative_values = 0;
192
193
    // Record how many values still need to be assigned.
194
4
    auto remaining_distinct_values = ordered_map.size();
195
196
4
    auto it = ordered_map.begin();
197
198
    // Lower value of the current bucket.
199
4
    const T* lower_value = &it->first;
200
201
    // Iterate over the ordered map of distinct values and their counts.
202
404
    for (; it != ordered_map.end(); ++it) {
203
400
        const auto count = it->second;
204
400
        const auto current_value = it->first;
205
206
        // Update the bucket counts and track the number of distinct values assigned.
207
400
        distinct_values_count++;
208
400
        remaining_distinct_values--;
209
400
        values_count += count;
210
400
        cumulative_values += count;
211
212
        // Check whether the current value should be added to the current bucket.
213
400
        auto next = std::next(it);
214
400
        size_t remaining_empty_buckets = max_num_buckets - buckets.size() - 1;
215
216
400
        if (next != ordered_map.end() && remaining_distinct_values > remaining_empty_buckets &&
217
400
            values_count + next->second <= bucket_max_values) {
218
            // If the current value is the last in the input map and there are more remaining
219
            // distinct values than empty buckets and adding the value does not cause the bucket
220
            // to exceed its max size, skip adding the value to the current bucket.
221
380
            continue;
222
380
        }
223
224
        // Finalize the current bucket and add it to our collection of buckets.
225
20
        auto pre_sum = cumulative_values - values_count;
226
227
20
        Bucket<T> new_bucket(*lower_value, current_value, distinct_values_count, values_count,
228
20
                             pre_sum);
229
20
        buckets.push_back(new_bucket);
230
231
        // Reset variables for the next bucket.
232
20
        if (next != ordered_map.end()) {
233
16
            lower_value = &next->first;
234
16
        }
235
20
        values_count = 0;
236
20
        distinct_values_count = 0;
237
20
    }
238
239
4
    return true;
240
8
}
_ZN5doris15build_histogramIsEEbRSt6vectorINS_6BucketIT_EESaIS4_EERKSt3mapIS3_mSt4lessIS3_ESaISt4pairIKS3_mEEEm
Line
Count
Source
174
8
                     const size_t max_num_buckets) {
175
    // If the input map is empty, there is nothing to build.
176
8
    if (ordered_map.empty()) {
177
4
        return false;
178
4
    }
179
180
    // Calculate the maximum number of values that can be assigned to each bucket.
181
4
    auto bucket_max_values = calculate_bucket_max_values(ordered_map, max_num_buckets);
182
183
    // Ensure that the capacity is at least max_num_buckets in order to avoid the overhead of additional
184
    // allocations when inserting buckets.
185
4
    buckets.clear();
186
4
    buckets.reserve(max_num_buckets);
187
188
    // Initialize bucket variables.
189
4
    size_t distinct_values_count = 0;
190
4
    size_t values_count = 0;
191
4
    size_t cumulative_values = 0;
192
193
    // Record how many values still need to be assigned.
194
4
    auto remaining_distinct_values = ordered_map.size();
195
196
4
    auto it = ordered_map.begin();
197
198
    // Lower value of the current bucket.
199
4
    const T* lower_value = &it->first;
200
201
    // Iterate over the ordered map of distinct values and their counts.
202
404
    for (; it != ordered_map.end(); ++it) {
203
400
        const auto count = it->second;
204
400
        const auto current_value = it->first;
205
206
        // Update the bucket counts and track the number of distinct values assigned.
207
400
        distinct_values_count++;
208
400
        remaining_distinct_values--;
209
400
        values_count += count;
210
400
        cumulative_values += count;
211
212
        // Check whether the current value should be added to the current bucket.
213
400
        auto next = std::next(it);
214
400
        size_t remaining_empty_buckets = max_num_buckets - buckets.size() - 1;
215
216
400
        if (next != ordered_map.end() && remaining_distinct_values > remaining_empty_buckets &&
217
400
            values_count + next->second <= bucket_max_values) {
218
            // If the current value is the last in the input map and there are more remaining
219
            // distinct values than empty buckets and adding the value does not cause the bucket
220
            // to exceed its max size, skip adding the value to the current bucket.
221
380
            continue;
222
380
        }
223
224
        // Finalize the current bucket and add it to our collection of buckets.
225
20
        auto pre_sum = cumulative_values - values_count;
226
227
20
        Bucket<T> new_bucket(*lower_value, current_value, distinct_values_count, values_count,
228
20
                             pre_sum);
229
20
        buckets.push_back(new_bucket);
230
231
        // Reset variables for the next bucket.
232
20
        if (next != ordered_map.end()) {
233
16
            lower_value = &next->first;
234
16
        }
235
20
        values_count = 0;
236
20
        distinct_values_count = 0;
237
20
    }
238
239
4
    return true;
240
8
}
_ZN5doris15build_histogramIlEEbRSt6vectorINS_6BucketIT_EESaIS4_EERKSt3mapIS3_mSt4lessIS3_ESaISt4pairIKS3_mEEEm
Line
Count
Source
174
8
                     const size_t max_num_buckets) {
175
    // If the input map is empty, there is nothing to build.
176
8
    if (ordered_map.empty()) {
177
4
        return false;
178
4
    }
179
180
    // Calculate the maximum number of values that can be assigned to each bucket.
181
4
    auto bucket_max_values = calculate_bucket_max_values(ordered_map, max_num_buckets);
182
183
    // Ensure that the capacity is at least max_num_buckets in order to avoid the overhead of additional
184
    // allocations when inserting buckets.
185
4
    buckets.clear();
186
4
    buckets.reserve(max_num_buckets);
187
188
    // Initialize bucket variables.
189
4
    size_t distinct_values_count = 0;
190
4
    size_t values_count = 0;
191
4
    size_t cumulative_values = 0;
192
193
    // Record how many values still need to be assigned.
194
4
    auto remaining_distinct_values = ordered_map.size();
195
196
4
    auto it = ordered_map.begin();
197
198
    // Lower value of the current bucket.
199
4
    const T* lower_value = &it->first;
200
201
    // Iterate over the ordered map of distinct values and their counts.
202
404
    for (; it != ordered_map.end(); ++it) {
203
400
        const auto count = it->second;
204
400
        const auto current_value = it->first;
205
206
        // Update the bucket counts and track the number of distinct values assigned.
207
400
        distinct_values_count++;
208
400
        remaining_distinct_values--;
209
400
        values_count += count;
210
400
        cumulative_values += count;
211
212
        // Check whether the current value should be added to the current bucket.
213
400
        auto next = std::next(it);
214
400
        size_t remaining_empty_buckets = max_num_buckets - buckets.size() - 1;
215
216
400
        if (next != ordered_map.end() && remaining_distinct_values > remaining_empty_buckets &&
217
400
            values_count + next->second <= bucket_max_values) {
218
            // If the current value is the last in the input map and there are more remaining
219
            // distinct values than empty buckets and adding the value does not cause the bucket
220
            // to exceed its max size, skip adding the value to the current bucket.
221
380
            continue;
222
380
        }
223
224
        // Finalize the current bucket and add it to our collection of buckets.
225
20
        auto pre_sum = cumulative_values - values_count;
226
227
20
        Bucket<T> new_bucket(*lower_value, current_value, distinct_values_count, values_count,
228
20
                             pre_sum);
229
20
        buckets.push_back(new_bucket);
230
231
        // Reset variables for the next bucket.
232
20
        if (next != ordered_map.end()) {
233
16
            lower_value = &next->first;
234
16
        }
235
20
        values_count = 0;
236
20
        distinct_values_count = 0;
237
20
    }
238
239
4
    return true;
240
8
}
_ZN5doris15build_histogramInEEbRSt6vectorINS_6BucketIT_EESaIS4_EERKSt3mapIS3_mSt4lessIS3_ESaISt4pairIKS3_mEEEm
Line
Count
Source
174
8
                     const size_t max_num_buckets) {
175
    // If the input map is empty, there is nothing to build.
176
8
    if (ordered_map.empty()) {
177
4
        return false;
178
4
    }
179
180
    // Calculate the maximum number of values that can be assigned to each bucket.
181
4
    auto bucket_max_values = calculate_bucket_max_values(ordered_map, max_num_buckets);
182
183
    // Ensure that the capacity is at least max_num_buckets in order to avoid the overhead of additional
184
    // allocations when inserting buckets.
185
4
    buckets.clear();
186
4
    buckets.reserve(max_num_buckets);
187
188
    // Initialize bucket variables.
189
4
    size_t distinct_values_count = 0;
190
4
    size_t values_count = 0;
191
4
    size_t cumulative_values = 0;
192
193
    // Record how many values still need to be assigned.
194
4
    auto remaining_distinct_values = ordered_map.size();
195
196
4
    auto it = ordered_map.begin();
197
198
    // Lower value of the current bucket.
199
4
    const T* lower_value = &it->first;
200
201
    // Iterate over the ordered map of distinct values and their counts.
202
404
    for (; it != ordered_map.end(); ++it) {
203
400
        const auto count = it->second;
204
400
        const auto current_value = it->first;
205
206
        // Update the bucket counts and track the number of distinct values assigned.
207
400
        distinct_values_count++;
208
400
        remaining_distinct_values--;
209
400
        values_count += count;
210
400
        cumulative_values += count;
211
212
        // Check whether the current value should be added to the current bucket.
213
400
        auto next = std::next(it);
214
400
        size_t remaining_empty_buckets = max_num_buckets - buckets.size() - 1;
215
216
400
        if (next != ordered_map.end() && remaining_distinct_values > remaining_empty_buckets &&
217
400
            values_count + next->second <= bucket_max_values) {
218
            // If the current value is the last in the input map and there are more remaining
219
            // distinct values than empty buckets and adding the value does not cause the bucket
220
            // to exceed its max size, skip adding the value to the current bucket.
221
380
            continue;
222
380
        }
223
224
        // Finalize the current bucket and add it to our collection of buckets.
225
20
        auto pre_sum = cumulative_values - values_count;
226
227
20
        Bucket<T> new_bucket(*lower_value, current_value, distinct_values_count, values_count,
228
20
                             pre_sum);
229
20
        buckets.push_back(new_bucket);
230
231
        // Reset variables for the next bucket.
232
20
        if (next != ordered_map.end()) {
233
16
            lower_value = &next->first;
234
16
        }
235
20
        values_count = 0;
236
20
        distinct_values_count = 0;
237
20
    }
238
239
4
    return true;
240
8
}
_ZN5doris15build_histogramIfEEbRSt6vectorINS_6BucketIT_EESaIS4_EERKSt3mapIS3_mSt4lessIS3_ESaISt4pairIKS3_mEEEm
Line
Count
Source
174
8
                     const size_t max_num_buckets) {
175
    // If the input map is empty, there is nothing to build.
176
8
    if (ordered_map.empty()) {
177
4
        return false;
178
4
    }
179
180
    // Calculate the maximum number of values that can be assigned to each bucket.
181
4
    auto bucket_max_values = calculate_bucket_max_values(ordered_map, max_num_buckets);
182
183
    // Ensure that the capacity is at least max_num_buckets in order to avoid the overhead of additional
184
    // allocations when inserting buckets.
185
4
    buckets.clear();
186
4
    buckets.reserve(max_num_buckets);
187
188
    // Initialize bucket variables.
189
4
    size_t distinct_values_count = 0;
190
4
    size_t values_count = 0;
191
4
    size_t cumulative_values = 0;
192
193
    // Record how many values still need to be assigned.
194
4
    auto remaining_distinct_values = ordered_map.size();
195
196
4
    auto it = ordered_map.begin();
197
198
    // Lower value of the current bucket.
199
4
    const T* lower_value = &it->first;
200
201
    // Iterate over the ordered map of distinct values and their counts.
202
404
    for (; it != ordered_map.end(); ++it) {
203
400
        const auto count = it->second;
204
400
        const auto current_value = it->first;
205
206
        // Update the bucket counts and track the number of distinct values assigned.
207
400
        distinct_values_count++;
208
400
        remaining_distinct_values--;
209
400
        values_count += count;
210
400
        cumulative_values += count;
211
212
        // Check whether the current value should be added to the current bucket.
213
400
        auto next = std::next(it);
214
400
        size_t remaining_empty_buckets = max_num_buckets - buckets.size() - 1;
215
216
400
        if (next != ordered_map.end() && remaining_distinct_values > remaining_empty_buckets &&
217
400
            values_count + next->second <= bucket_max_values) {
218
            // If the current value is the last in the input map and there are more remaining
219
            // distinct values than empty buckets and adding the value does not cause the bucket
220
            // to exceed its max size, skip adding the value to the current bucket.
221
380
            continue;
222
380
        }
223
224
        // Finalize the current bucket and add it to our collection of buckets.
225
20
        auto pre_sum = cumulative_values - values_count;
226
227
20
        Bucket<T> new_bucket(*lower_value, current_value, distinct_values_count, values_count,
228
20
                             pre_sum);
229
20
        buckets.push_back(new_bucket);
230
231
        // Reset variables for the next bucket.
232
20
        if (next != ordered_map.end()) {
233
16
            lower_value = &next->first;
234
16
        }
235
20
        values_count = 0;
236
20
        distinct_values_count = 0;
237
20
    }
238
239
4
    return true;
240
8
}
_ZN5doris15build_histogramIdEEbRSt6vectorINS_6BucketIT_EESaIS4_EERKSt3mapIS3_mSt4lessIS3_ESaISt4pairIKS3_mEEEm
Line
Count
Source
174
8
                     const size_t max_num_buckets) {
175
    // If the input map is empty, there is nothing to build.
176
8
    if (ordered_map.empty()) {
177
4
        return false;
178
4
    }
179
180
    // Calculate the maximum number of values that can be assigned to each bucket.
181
4
    auto bucket_max_values = calculate_bucket_max_values(ordered_map, max_num_buckets);
182
183
    // Ensure that the capacity is at least max_num_buckets in order to avoid the overhead of additional
184
    // allocations when inserting buckets.
185
4
    buckets.clear();
186
4
    buckets.reserve(max_num_buckets);
187
188
    // Initialize bucket variables.
189
4
    size_t distinct_values_count = 0;
190
4
    size_t values_count = 0;
191
4
    size_t cumulative_values = 0;
192
193
    // Record how many values still need to be assigned.
194
4
    auto remaining_distinct_values = ordered_map.size();
195
196
4
    auto it = ordered_map.begin();
197
198
    // Lower value of the current bucket.
199
4
    const T* lower_value = &it->first;
200
201
    // Iterate over the ordered map of distinct values and their counts.
202
404
    for (; it != ordered_map.end(); ++it) {
203
400
        const auto count = it->second;
204
400
        const auto current_value = it->first;
205
206
        // Update the bucket counts and track the number of distinct values assigned.
207
400
        distinct_values_count++;
208
400
        remaining_distinct_values--;
209
400
        values_count += count;
210
400
        cumulative_values += count;
211
212
        // Check whether the current value should be added to the current bucket.
213
400
        auto next = std::next(it);
214
400
        size_t remaining_empty_buckets = max_num_buckets - buckets.size() - 1;
215
216
400
        if (next != ordered_map.end() && remaining_distinct_values > remaining_empty_buckets &&
217
400
            values_count + next->second <= bucket_max_values) {
218
            // If the current value is the last in the input map and there are more remaining
219
            // distinct values than empty buckets and adding the value does not cause the bucket
220
            // to exceed its max size, skip adding the value to the current bucket.
221
380
            continue;
222
380
        }
223
224
        // Finalize the current bucket and add it to our collection of buckets.
225
20
        auto pre_sum = cumulative_values - values_count;
226
227
20
        Bucket<T> new_bucket(*lower_value, current_value, distinct_values_count, values_count,
228
20
                             pre_sum);
229
20
        buckets.push_back(new_bucket);
230
231
        // Reset variables for the next bucket.
232
20
        if (next != ordered_map.end()) {
233
16
            lower_value = &next->first;
234
16
        }
235
20
        values_count = 0;
236
20
        distinct_values_count = 0;
237
20
    }
238
239
4
    return true;
240
8
}
Unexecuted instantiation: _ZN5doris15build_histogramINS_7DecimalIiEEEEbRSt6vectorINS_6BucketIT_EESaIS6_EERKSt3mapIS5_mSt4lessIS5_ESaISt4pairIKS5_mEEEm
Unexecuted instantiation: _ZN5doris15build_histogramINS_7DecimalIlEEEEbRSt6vectorINS_6BucketIT_EESaIS6_EERKSt3mapIS5_mSt4lessIS5_ESaISt4pairIKS5_mEEEm
Unexecuted instantiation: _ZN5doris15build_histogramINS_12Decimal128V3EEEbRSt6vectorINS_6BucketIT_EESaIS5_EERKSt3mapIS4_mSt4lessIS4_ESaISt4pairIKS4_mEEEm
Unexecuted instantiation: _ZN5doris15build_histogramINS_7DecimalIN4wide7integerILm256EiEEEEEEbRSt6vectorINS_6BucketIT_EESaIS9_EERKSt3mapIS8_mSt4lessIS8_ESaISt4pairIKS8_mEEEm
_ZN5doris15build_histogramINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEbRSt6vectorINS_6BucketIT_EESaISA_EERKSt3mapIS9_mSt4lessIS9_ESaISt4pairIKS9_mEEEm
Line
Count
Source
174
8
                     const size_t max_num_buckets) {
175
    // If the input map is empty, there is nothing to build.
176
8
    if (ordered_map.empty()) {
177
4
        return false;
178
4
    }
179
180
    // Calculate the maximum number of values that can be assigned to each bucket.
181
4
    auto bucket_max_values = calculate_bucket_max_values(ordered_map, max_num_buckets);
182
183
    // Ensure that the capacity is at least max_num_buckets in order to avoid the overhead of additional
184
    // allocations when inserting buckets.
185
4
    buckets.clear();
186
4
    buckets.reserve(max_num_buckets);
187
188
    // Initialize bucket variables.
189
4
    size_t distinct_values_count = 0;
190
4
    size_t values_count = 0;
191
4
    size_t cumulative_values = 0;
192
193
    // Record how many values still need to be assigned.
194
4
    auto remaining_distinct_values = ordered_map.size();
195
196
4
    auto it = ordered_map.begin();
197
198
    // Lower value of the current bucket.
199
4
    const T* lower_value = &it->first;
200
201
    // Iterate over the ordered map of distinct values and their counts.
202
4.00k
    for (; it != ordered_map.end(); ++it) {
203
4.00k
        const auto count = it->second;
204
4.00k
        const auto current_value = it->first;
205
206
        // Update the bucket counts and track the number of distinct values assigned.
207
4.00k
        distinct_values_count++;
208
4.00k
        remaining_distinct_values--;
209
4.00k
        values_count += count;
210
4.00k
        cumulative_values += count;
211
212
        // Check whether the current value should be added to the current bucket.
213
4.00k
        auto next = std::next(it);
214
4.00k
        size_t remaining_empty_buckets = max_num_buckets - buckets.size() - 1;
215
216
4.00k
        if (next != ordered_map.end() && remaining_distinct_values > remaining_empty_buckets &&
217
4.00k
            values_count + next->second <= bucket_max_values) {
218
            // If the current value is the last in the input map and there are more remaining
219
            // distinct values than empty buckets and adding the value does not cause the bucket
220
            // to exceed its max size, skip adding the value to the current bucket.
221
3.98k
            continue;
222
3.98k
        }
223
224
        // Finalize the current bucket and add it to our collection of buckets.
225
20
        auto pre_sum = cumulative_values - values_count;
226
227
20
        Bucket<T> new_bucket(*lower_value, current_value, distinct_values_count, values_count,
228
20
                             pre_sum);
229
20
        buckets.push_back(new_bucket);
230
231
        // Reset variables for the next bucket.
232
20
        if (next != ordered_map.end()) {
233
16
            lower_value = &next->first;
234
16
        }
235
20
        values_count = 0;
236
20
        distinct_values_count = 0;
237
20
    }
238
239
4
    return true;
240
8
}
_ZN5doris15build_histogramINS_11DateV2ValueINS_15DateV2ValueTypeEEEEEbRSt6vectorINS_6BucketIT_EESaIS7_EERKSt3mapIS6_mSt4lessIS6_ESaISt4pairIKS6_mEEEm
Line
Count
Source
174
4
                     const size_t max_num_buckets) {
175
    // If the input map is empty, there is nothing to build.
176
4
    if (ordered_map.empty()) {
177
0
        return false;
178
0
    }
179
180
    // Calculate the maximum number of values that can be assigned to each bucket.
181
4
    auto bucket_max_values = calculate_bucket_max_values(ordered_map, max_num_buckets);
182
183
    // Ensure that the capacity is at least max_num_buckets in order to avoid the overhead of additional
184
    // allocations when inserting buckets.
185
4
    buckets.clear();
186
4
    buckets.reserve(max_num_buckets);
187
188
    // Initialize bucket variables.
189
4
    size_t distinct_values_count = 0;
190
4
    size_t values_count = 0;
191
4
    size_t cumulative_values = 0;
192
193
    // Record how many values still need to be assigned.
194
4
    auto remaining_distinct_values = ordered_map.size();
195
196
4
    auto it = ordered_map.begin();
197
198
    // Lower value of the current bucket.
199
4
    const T* lower_value = &it->first;
200
201
    // Iterate over the ordered map of distinct values and their counts.
202
404
    for (; it != ordered_map.end(); ++it) {
203
400
        const auto count = it->second;
204
400
        const auto current_value = it->first;
205
206
        // Update the bucket counts and track the number of distinct values assigned.
207
400
        distinct_values_count++;
208
400
        remaining_distinct_values--;
209
400
        values_count += count;
210
400
        cumulative_values += count;
211
212
        // Check whether the current value should be added to the current bucket.
213
400
        auto next = std::next(it);
214
400
        size_t remaining_empty_buckets = max_num_buckets - buckets.size() - 1;
215
216
400
        if (next != ordered_map.end() && remaining_distinct_values > remaining_empty_buckets &&
217
400
            values_count + next->second <= bucket_max_values) {
218
            // If the current value is the last in the input map and there are more remaining
219
            // distinct values than empty buckets and adding the value does not cause the bucket
220
            // to exceed its max size, skip adding the value to the current bucket.
221
380
            continue;
222
380
        }
223
224
        // Finalize the current bucket and add it to our collection of buckets.
225
20
        auto pre_sum = cumulative_values - values_count;
226
227
20
        Bucket<T> new_bucket(*lower_value, current_value, distinct_values_count, values_count,
228
20
                             pre_sum);
229
20
        buckets.push_back(new_bucket);
230
231
        // Reset variables for the next bucket.
232
20
        if (next != ordered_map.end()) {
233
16
            lower_value = &next->first;
234
16
        }
235
20
        values_count = 0;
236
20
        distinct_values_count = 0;
237
20
    }
238
239
4
    return true;
240
4
}
_ZN5doris15build_histogramINS_11DateV2ValueINS_19DateTimeV2ValueTypeEEEEEbRSt6vectorINS_6BucketIT_EESaIS7_EERKSt3mapIS6_mSt4lessIS6_ESaISt4pairIKS6_mEEEm
Line
Count
Source
174
4
                     const size_t max_num_buckets) {
175
    // If the input map is empty, there is nothing to build.
176
4
    if (ordered_map.empty()) {
177
0
        return false;
178
0
    }
179
180
    // Calculate the maximum number of values that can be assigned to each bucket.
181
4
    auto bucket_max_values = calculate_bucket_max_values(ordered_map, max_num_buckets);
182
183
    // Ensure that the capacity is at least max_num_buckets in order to avoid the overhead of additional
184
    // allocations when inserting buckets.
185
4
    buckets.clear();
186
4
    buckets.reserve(max_num_buckets);
187
188
    // Initialize bucket variables.
189
4
    size_t distinct_values_count = 0;
190
4
    size_t values_count = 0;
191
4
    size_t cumulative_values = 0;
192
193
    // Record how many values still need to be assigned.
194
4
    auto remaining_distinct_values = ordered_map.size();
195
196
4
    auto it = ordered_map.begin();
197
198
    // Lower value of the current bucket.
199
4
    const T* lower_value = &it->first;
200
201
    // Iterate over the ordered map of distinct values and their counts.
202
404
    for (; it != ordered_map.end(); ++it) {
203
400
        const auto count = it->second;
204
400
        const auto current_value = it->first;
205
206
        // Update the bucket counts and track the number of distinct values assigned.
207
400
        distinct_values_count++;
208
400
        remaining_distinct_values--;
209
400
        values_count += count;
210
400
        cumulative_values += count;
211
212
        // Check whether the current value should be added to the current bucket.
213
400
        auto next = std::next(it);
214
400
        size_t remaining_empty_buckets = max_num_buckets - buckets.size() - 1;
215
216
400
        if (next != ordered_map.end() && remaining_distinct_values > remaining_empty_buckets &&
217
400
            values_count + next->second <= bucket_max_values) {
218
            // If the current value is the last in the input map and there are more remaining
219
            // distinct values than empty buckets and adding the value does not cause the bucket
220
            // to exceed its max size, skip adding the value to the current bucket.
221
380
            continue;
222
380
        }
223
224
        // Finalize the current bucket and add it to our collection of buckets.
225
20
        auto pre_sum = cumulative_values - values_count;
226
227
20
        Bucket<T> new_bucket(*lower_value, current_value, distinct_values_count, values_count,
228
20
                             pre_sum);
229
20
        buckets.push_back(new_bucket);
230
231
        // Reset variables for the next bucket.
232
20
        if (next != ordered_map.end()) {
233
16
            lower_value = &next->first;
234
16
        }
235
20
        values_count = 0;
236
20
        distinct_values_count = 0;
237
20
    }
238
239
4
    return true;
240
4
}
Unexecuted instantiation: _ZN5doris15build_histogramINS_16TimeStampNsValueEEEbRSt6vectorINS_6BucketIT_EESaIS5_EERKSt3mapIS4_mSt4lessIS4_ESaISt4pairIKS4_mEEEm
Unexecuted instantiation: _ZN5doris15build_histogramINS_16TimestampTzValueEEEbRSt6vectorINS_6BucketIT_EESaIS5_EERKSt3mapIS4_mSt4lessIS4_ESaISt4pairIKS4_mEEEm
_ZN5doris15build_histogramIoEEbRSt6vectorINS_6BucketIT_EESaIS4_EERKSt3mapIS3_mSt4lessIS3_ESaISt4pairIKS3_mEEEm
Line
Count
Source
174
12
                     const size_t max_num_buckets) {
175
    // If the input map is empty, there is nothing to build.
176
12
    if (ordered_map.empty()) {
177
4
        return false;
178
4
    }
179
180
    // Calculate the maximum number of values that can be assigned to each bucket.
181
8
    auto bucket_max_values = calculate_bucket_max_values(ordered_map, max_num_buckets);
182
183
    // Ensure that the capacity is at least max_num_buckets in order to avoid the overhead of additional
184
    // allocations when inserting buckets.
185
8
    buckets.clear();
186
8
    buckets.reserve(max_num_buckets);
187
188
    // Initialize bucket variables.
189
8
    size_t distinct_values_count = 0;
190
8
    size_t values_count = 0;
191
8
    size_t cumulative_values = 0;
192
193
    // Record how many values still need to be assigned.
194
8
    auto remaining_distinct_values = ordered_map.size();
195
196
8
    auto it = ordered_map.begin();
197
198
    // Lower value of the current bucket.
199
8
    const T* lower_value = &it->first;
200
201
    // Iterate over the ordered map of distinct values and their counts.
202
48
    for (; it != ordered_map.end(); ++it) {
203
40
        const auto count = it->second;
204
40
        const auto current_value = it->first;
205
206
        // Update the bucket counts and track the number of distinct values assigned.
207
40
        distinct_values_count++;
208
40
        remaining_distinct_values--;
209
40
        values_count += count;
210
40
        cumulative_values += count;
211
212
        // Check whether the current value should be added to the current bucket.
213
40
        auto next = std::next(it);
214
40
        size_t remaining_empty_buckets = max_num_buckets - buckets.size() - 1;
215
216
40
        if (next != ordered_map.end() && remaining_distinct_values > remaining_empty_buckets &&
217
40
            values_count + next->second <= bucket_max_values) {
218
            // If the current value is the last in the input map and there are more remaining
219
            // distinct values than empty buckets and adding the value does not cause the bucket
220
            // to exceed its max size, skip adding the value to the current bucket.
221
0
            continue;
222
0
        }
223
224
        // Finalize the current bucket and add it to our collection of buckets.
225
40
        auto pre_sum = cumulative_values - values_count;
226
227
40
        Bucket<T> new_bucket(*lower_value, current_value, distinct_values_count, values_count,
228
40
                             pre_sum);
229
40
        buckets.push_back(new_bucket);
230
231
        // Reset variables for the next bucket.
232
40
        if (next != ordered_map.end()) {
233
32
            lower_value = &next->first;
234
32
        }
235
40
        values_count = 0;
236
40
        distinct_values_count = 0;
237
40
    }
238
239
8
    return true;
240
12
}
241
242
template <typename T>
243
bool histogram_to_json(rapidjson::StringBuffer& buffer, const std::vector<Bucket<T>>& buckets,
244
144
                       const DataTypePtr& data_type) {
245
144
    rapidjson::Document doc;
246
144
    doc.SetObject();
247
144
    rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();
248
249
144
    int num_buckets = cast_set<int>(buckets.size());
250
144
    doc.AddMember("num_buckets", num_buckets, allocator);
251
252
144
    rapidjson::Value bucket_arr(rapidjson::kArrayType);
253
144
    bucket_arr.Reserve(num_buckets, allocator);
254
255
144
    std::stringstream ss1;
256
144
    std::stringstream ss2;
257
258
144
    rapidjson::Value lower_val;
259
144
    rapidjson::Value upper_val;
260
261
    // Convert bucket's lower and upper to 2 columns
262
144
    MutableColumnPtr lower_column = data_type->create_column();
263
144
    MutableColumnPtr upper_column = data_type->create_column();
264
300
    for (const auto& bucket : buckets) {
265
        // String type is different, it has to pass in length
266
        // if it is string type , directly use string value
267
300
        if constexpr (!std::is_same_v<T, std::string>) {
268
280
            lower_column->insert_data(reinterpret_cast<const char*>(&bucket.lower), 0);
269
280
            upper_column->insert_data(reinterpret_cast<const char*>(&bucket.upper), 0);
270
280
        }
271
300
    }
272
144
    size_t row_num = 0;
273
274
144
    auto format_options = DataTypeSerDe::get_default_format_options();
275
144
    auto time_zone = cctz::utc_time_zone();
276
144
    format_options.timezone = &time_zone;
277
278
300
    for (const auto& bucket : buckets) {
279
300
        if constexpr (std::is_same_v<T, std::string>) {
280
20
            lower_val.SetString(bucket.lower.data(),
281
20
                                static_cast<rapidjson::SizeType>(bucket.lower.size()), allocator);
282
20
            upper_val.SetString(bucket.upper.data(),
283
20
                                static_cast<rapidjson::SizeType>(bucket.upper.size()), allocator);
284
280
        } else {
285
280
            std::string lower_str = data_type->to_string(*lower_column, row_num, format_options);
286
280
            std::string upper_str = data_type->to_string(*upper_column, row_num, format_options);
287
280
            ++row_num;
288
280
            lower_val.SetString(lower_str.data(),
289
280
                                static_cast<rapidjson::SizeType>(lower_str.size()), allocator);
290
280
            upper_val.SetString(upper_str.data(),
291
280
                                static_cast<rapidjson::SizeType>(upper_str.size()), allocator);
292
280
        }
293
300
        rapidjson::Value bucket_json(rapidjson::kObjectType);
294
300
        bucket_json.AddMember("lower", lower_val, allocator);
295
300
        bucket_json.AddMember("upper", upper_val, allocator);
296
300
        bucket_json.AddMember("ndv", static_cast<int64_t>(bucket.ndv), allocator);
297
300
        bucket_json.AddMember("count", static_cast<int64_t>(bucket.count), allocator);
298
300
        bucket_json.AddMember("pre_sum", static_cast<int64_t>(bucket.pre_sum), allocator);
299
300
300
        bucket_arr.PushBack(bucket_json, allocator);
301
300
    }
302
303
144
    doc.AddMember("buckets", bucket_arr, allocator);
304
144
    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
305
144
    doc.Accept(writer);
306
307
144
    return !buckets.empty() && buffer.GetSize() > 0;
308
144
}
_ZN5doris17histogram_to_jsonIiEEbRN9rapidjson19GenericStringBufferINS1_4UTF8IcEENS1_12CrtAllocatorEEERKSt6vectorINS_6BucketIT_EESaISB_EERKSt10shared_ptrIKNS_9IDataTypeEE
Line
Count
Source
244
68
                       const DataTypePtr& data_type) {
245
68
    rapidjson::Document doc;
246
68
    doc.SetObject();
247
68
    rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();
248
249
68
    int num_buckets = cast_set<int>(buckets.size());
250
68
    doc.AddMember("num_buckets", num_buckets, allocator);
251
252
68
    rapidjson::Value bucket_arr(rapidjson::kArrayType);
253
68
    bucket_arr.Reserve(num_buckets, allocator);
254
255
68
    std::stringstream ss1;
256
68
    std::stringstream ss2;
257
258
68
    rapidjson::Value lower_val;
259
68
    rapidjson::Value upper_val;
260
261
    // Convert bucket's lower and upper to 2 columns
262
68
    MutableColumnPtr lower_column = data_type->create_column();
263
68
    MutableColumnPtr upper_column = data_type->create_column();
264
80
    for (const auto& bucket : buckets) {
265
        // String type is different, it has to pass in length
266
        // if it is string type , directly use string value
267
80
        if constexpr (!std::is_same_v<T, std::string>) {
268
80
            lower_column->insert_data(reinterpret_cast<const char*>(&bucket.lower), 0);
269
80
            upper_column->insert_data(reinterpret_cast<const char*>(&bucket.upper), 0);
270
80
        }
271
80
    }
272
68
    size_t row_num = 0;
273
274
68
    auto format_options = DataTypeSerDe::get_default_format_options();
275
68
    auto time_zone = cctz::utc_time_zone();
276
68
    format_options.timezone = &time_zone;
277
278
80
    for (const auto& bucket : buckets) {
279
        if constexpr (std::is_same_v<T, std::string>) {
280
            lower_val.SetString(bucket.lower.data(),
281
                                static_cast<rapidjson::SizeType>(bucket.lower.size()), allocator);
282
            upper_val.SetString(bucket.upper.data(),
283
                                static_cast<rapidjson::SizeType>(bucket.upper.size()), allocator);
284
80
        } else {
285
80
            std::string lower_str = data_type->to_string(*lower_column, row_num, format_options);
286
80
            std::string upper_str = data_type->to_string(*upper_column, row_num, format_options);
287
80
            ++row_num;
288
80
            lower_val.SetString(lower_str.data(),
289
80
                                static_cast<rapidjson::SizeType>(lower_str.size()), allocator);
290
80
            upper_val.SetString(upper_str.data(),
291
80
                                static_cast<rapidjson::SizeType>(upper_str.size()), allocator);
292
80
        }
293
80
        rapidjson::Value bucket_json(rapidjson::kObjectType);
294
80
        bucket_json.AddMember("lower", lower_val, allocator);
295
80
        bucket_json.AddMember("upper", upper_val, allocator);
296
80
        bucket_json.AddMember("ndv", static_cast<int64_t>(bucket.ndv), allocator);
297
80
        bucket_json.AddMember("count", static_cast<int64_t>(bucket.count), allocator);
298
80
        bucket_json.AddMember("pre_sum", static_cast<int64_t>(bucket.pre_sum), allocator);
299
300
80
        bucket_arr.PushBack(bucket_json, allocator);
301
80
    }
302
303
68
    doc.AddMember("buckets", bucket_arr, allocator);
304
68
    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
305
68
    doc.Accept(writer);
306
307
68
    return !buckets.empty() && buffer.GetSize() > 0;
308
68
}
Unexecuted instantiation: _ZN5doris17histogram_to_jsonIhEEbRN9rapidjson19GenericStringBufferINS1_4UTF8IcEENS1_12CrtAllocatorEEERKSt6vectorINS_6BucketIT_EESaISB_EERKSt10shared_ptrIKNS_9IDataTypeEE
_ZN5doris17histogram_to_jsonIaEEbRN9rapidjson19GenericStringBufferINS1_4UTF8IcEENS1_12CrtAllocatorEEERKSt6vectorINS_6BucketIT_EESaISB_EERKSt10shared_ptrIKNS_9IDataTypeEE
Line
Count
Source
244
8
                       const DataTypePtr& data_type) {
245
8
    rapidjson::Document doc;
246
8
    doc.SetObject();
247
8
    rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();
248
249
8
    int num_buckets = cast_set<int>(buckets.size());
250
8
    doc.AddMember("num_buckets", num_buckets, allocator);
251
252
8
    rapidjson::Value bucket_arr(rapidjson::kArrayType);
253
8
    bucket_arr.Reserve(num_buckets, allocator);
254
255
8
    std::stringstream ss1;
256
8
    std::stringstream ss2;
257
258
8
    rapidjson::Value lower_val;
259
8
    rapidjson::Value upper_val;
260
261
    // Convert bucket's lower and upper to 2 columns
262
8
    MutableColumnPtr lower_column = data_type->create_column();
263
8
    MutableColumnPtr upper_column = data_type->create_column();
264
20
    for (const auto& bucket : buckets) {
265
        // String type is different, it has to pass in length
266
        // if it is string type , directly use string value
267
20
        if constexpr (!std::is_same_v<T, std::string>) {
268
20
            lower_column->insert_data(reinterpret_cast<const char*>(&bucket.lower), 0);
269
20
            upper_column->insert_data(reinterpret_cast<const char*>(&bucket.upper), 0);
270
20
        }
271
20
    }
272
8
    size_t row_num = 0;
273
274
8
    auto format_options = DataTypeSerDe::get_default_format_options();
275
8
    auto time_zone = cctz::utc_time_zone();
276
8
    format_options.timezone = &time_zone;
277
278
20
    for (const auto& bucket : buckets) {
279
        if constexpr (std::is_same_v<T, std::string>) {
280
            lower_val.SetString(bucket.lower.data(),
281
                                static_cast<rapidjson::SizeType>(bucket.lower.size()), allocator);
282
            upper_val.SetString(bucket.upper.data(),
283
                                static_cast<rapidjson::SizeType>(bucket.upper.size()), allocator);
284
20
        } else {
285
20
            std::string lower_str = data_type->to_string(*lower_column, row_num, format_options);
286
20
            std::string upper_str = data_type->to_string(*upper_column, row_num, format_options);
287
20
            ++row_num;
288
20
            lower_val.SetString(lower_str.data(),
289
20
                                static_cast<rapidjson::SizeType>(lower_str.size()), allocator);
290
20
            upper_val.SetString(upper_str.data(),
291
20
                                static_cast<rapidjson::SizeType>(upper_str.size()), allocator);
292
20
        }
293
20
        rapidjson::Value bucket_json(rapidjson::kObjectType);
294
20
        bucket_json.AddMember("lower", lower_val, allocator);
295
20
        bucket_json.AddMember("upper", upper_val, allocator);
296
20
        bucket_json.AddMember("ndv", static_cast<int64_t>(bucket.ndv), allocator);
297
20
        bucket_json.AddMember("count", static_cast<int64_t>(bucket.count), allocator);
298
20
        bucket_json.AddMember("pre_sum", static_cast<int64_t>(bucket.pre_sum), allocator);
299
300
20
        bucket_arr.PushBack(bucket_json, allocator);
301
20
    }
302
303
8
    doc.AddMember("buckets", bucket_arr, allocator);
304
8
    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
305
8
    doc.Accept(writer);
306
307
8
    return !buckets.empty() && buffer.GetSize() > 0;
308
8
}
_ZN5doris17histogram_to_jsonIsEEbRN9rapidjson19GenericStringBufferINS1_4UTF8IcEENS1_12CrtAllocatorEEERKSt6vectorINS_6BucketIT_EESaISB_EERKSt10shared_ptrIKNS_9IDataTypeEE
Line
Count
Source
244
8
                       const DataTypePtr& data_type) {
245
8
    rapidjson::Document doc;
246
8
    doc.SetObject();
247
8
    rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();
248
249
8
    int num_buckets = cast_set<int>(buckets.size());
250
8
    doc.AddMember("num_buckets", num_buckets, allocator);
251
252
8
    rapidjson::Value bucket_arr(rapidjson::kArrayType);
253
8
    bucket_arr.Reserve(num_buckets, allocator);
254
255
8
    std::stringstream ss1;
256
8
    std::stringstream ss2;
257
258
8
    rapidjson::Value lower_val;
259
8
    rapidjson::Value upper_val;
260
261
    // Convert bucket's lower and upper to 2 columns
262
8
    MutableColumnPtr lower_column = data_type->create_column();
263
8
    MutableColumnPtr upper_column = data_type->create_column();
264
20
    for (const auto& bucket : buckets) {
265
        // String type is different, it has to pass in length
266
        // if it is string type , directly use string value
267
20
        if constexpr (!std::is_same_v<T, std::string>) {
268
20
            lower_column->insert_data(reinterpret_cast<const char*>(&bucket.lower), 0);
269
20
            upper_column->insert_data(reinterpret_cast<const char*>(&bucket.upper), 0);
270
20
        }
271
20
    }
272
8
    size_t row_num = 0;
273
274
8
    auto format_options = DataTypeSerDe::get_default_format_options();
275
8
    auto time_zone = cctz::utc_time_zone();
276
8
    format_options.timezone = &time_zone;
277
278
20
    for (const auto& bucket : buckets) {
279
        if constexpr (std::is_same_v<T, std::string>) {
280
            lower_val.SetString(bucket.lower.data(),
281
                                static_cast<rapidjson::SizeType>(bucket.lower.size()), allocator);
282
            upper_val.SetString(bucket.upper.data(),
283
                                static_cast<rapidjson::SizeType>(bucket.upper.size()), allocator);
284
20
        } else {
285
20
            std::string lower_str = data_type->to_string(*lower_column, row_num, format_options);
286
20
            std::string upper_str = data_type->to_string(*upper_column, row_num, format_options);
287
20
            ++row_num;
288
20
            lower_val.SetString(lower_str.data(),
289
20
                                static_cast<rapidjson::SizeType>(lower_str.size()), allocator);
290
20
            upper_val.SetString(upper_str.data(),
291
20
                                static_cast<rapidjson::SizeType>(upper_str.size()), allocator);
292
20
        }
293
20
        rapidjson::Value bucket_json(rapidjson::kObjectType);
294
20
        bucket_json.AddMember("lower", lower_val, allocator);
295
20
        bucket_json.AddMember("upper", upper_val, allocator);
296
20
        bucket_json.AddMember("ndv", static_cast<int64_t>(bucket.ndv), allocator);
297
20
        bucket_json.AddMember("count", static_cast<int64_t>(bucket.count), allocator);
298
20
        bucket_json.AddMember("pre_sum", static_cast<int64_t>(bucket.pre_sum), allocator);
299
300
20
        bucket_arr.PushBack(bucket_json, allocator);
301
20
    }
302
303
8
    doc.AddMember("buckets", bucket_arr, allocator);
304
8
    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
305
8
    doc.Accept(writer);
306
307
8
    return !buckets.empty() && buffer.GetSize() > 0;
308
8
}
_ZN5doris17histogram_to_jsonIlEEbRN9rapidjson19GenericStringBufferINS1_4UTF8IcEENS1_12CrtAllocatorEEERKSt6vectorINS_6BucketIT_EESaISB_EERKSt10shared_ptrIKNS_9IDataTypeEE
Line
Count
Source
244
8
                       const DataTypePtr& data_type) {
245
8
    rapidjson::Document doc;
246
8
    doc.SetObject();
247
8
    rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();
248
249
8
    int num_buckets = cast_set<int>(buckets.size());
250
8
    doc.AddMember("num_buckets", num_buckets, allocator);
251
252
8
    rapidjson::Value bucket_arr(rapidjson::kArrayType);
253
8
    bucket_arr.Reserve(num_buckets, allocator);
254
255
8
    std::stringstream ss1;
256
8
    std::stringstream ss2;
257
258
8
    rapidjson::Value lower_val;
259
8
    rapidjson::Value upper_val;
260
261
    // Convert bucket's lower and upper to 2 columns
262
8
    MutableColumnPtr lower_column = data_type->create_column();
263
8
    MutableColumnPtr upper_column = data_type->create_column();
264
20
    for (const auto& bucket : buckets) {
265
        // String type is different, it has to pass in length
266
        // if it is string type , directly use string value
267
20
        if constexpr (!std::is_same_v<T, std::string>) {
268
20
            lower_column->insert_data(reinterpret_cast<const char*>(&bucket.lower), 0);
269
20
            upper_column->insert_data(reinterpret_cast<const char*>(&bucket.upper), 0);
270
20
        }
271
20
    }
272
8
    size_t row_num = 0;
273
274
8
    auto format_options = DataTypeSerDe::get_default_format_options();
275
8
    auto time_zone = cctz::utc_time_zone();
276
8
    format_options.timezone = &time_zone;
277
278
20
    for (const auto& bucket : buckets) {
279
        if constexpr (std::is_same_v<T, std::string>) {
280
            lower_val.SetString(bucket.lower.data(),
281
                                static_cast<rapidjson::SizeType>(bucket.lower.size()), allocator);
282
            upper_val.SetString(bucket.upper.data(),
283
                                static_cast<rapidjson::SizeType>(bucket.upper.size()), allocator);
284
20
        } else {
285
20
            std::string lower_str = data_type->to_string(*lower_column, row_num, format_options);
286
20
            std::string upper_str = data_type->to_string(*upper_column, row_num, format_options);
287
20
            ++row_num;
288
20
            lower_val.SetString(lower_str.data(),
289
20
                                static_cast<rapidjson::SizeType>(lower_str.size()), allocator);
290
20
            upper_val.SetString(upper_str.data(),
291
20
                                static_cast<rapidjson::SizeType>(upper_str.size()), allocator);
292
20
        }
293
20
        rapidjson::Value bucket_json(rapidjson::kObjectType);
294
20
        bucket_json.AddMember("lower", lower_val, allocator);
295
20
        bucket_json.AddMember("upper", upper_val, allocator);
296
20
        bucket_json.AddMember("ndv", static_cast<int64_t>(bucket.ndv), allocator);
297
20
        bucket_json.AddMember("count", static_cast<int64_t>(bucket.count), allocator);
298
20
        bucket_json.AddMember("pre_sum", static_cast<int64_t>(bucket.pre_sum), allocator);
299
300
20
        bucket_arr.PushBack(bucket_json, allocator);
301
20
    }
302
303
8
    doc.AddMember("buckets", bucket_arr, allocator);
304
8
    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
305
8
    doc.Accept(writer);
306
307
8
    return !buckets.empty() && buffer.GetSize() > 0;
308
8
}
_ZN5doris17histogram_to_jsonInEEbRN9rapidjson19GenericStringBufferINS1_4UTF8IcEENS1_12CrtAllocatorEEERKSt6vectorINS_6BucketIT_EESaISB_EERKSt10shared_ptrIKNS_9IDataTypeEE
Line
Count
Source
244
8
                       const DataTypePtr& data_type) {
245
8
    rapidjson::Document doc;
246
8
    doc.SetObject();
247
8
    rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();
248
249
8
    int num_buckets = cast_set<int>(buckets.size());
250
8
    doc.AddMember("num_buckets", num_buckets, allocator);
251
252
8
    rapidjson::Value bucket_arr(rapidjson::kArrayType);
253
8
    bucket_arr.Reserve(num_buckets, allocator);
254
255
8
    std::stringstream ss1;
256
8
    std::stringstream ss2;
257
258
8
    rapidjson::Value lower_val;
259
8
    rapidjson::Value upper_val;
260
261
    // Convert bucket's lower and upper to 2 columns
262
8
    MutableColumnPtr lower_column = data_type->create_column();
263
8
    MutableColumnPtr upper_column = data_type->create_column();
264
20
    for (const auto& bucket : buckets) {
265
        // String type is different, it has to pass in length
266
        // if it is string type , directly use string value
267
20
        if constexpr (!std::is_same_v<T, std::string>) {
268
20
            lower_column->insert_data(reinterpret_cast<const char*>(&bucket.lower), 0);
269
20
            upper_column->insert_data(reinterpret_cast<const char*>(&bucket.upper), 0);
270
20
        }
271
20
    }
272
8
    size_t row_num = 0;
273
274
8
    auto format_options = DataTypeSerDe::get_default_format_options();
275
8
    auto time_zone = cctz::utc_time_zone();
276
8
    format_options.timezone = &time_zone;
277
278
20
    for (const auto& bucket : buckets) {
279
        if constexpr (std::is_same_v<T, std::string>) {
280
            lower_val.SetString(bucket.lower.data(),
281
                                static_cast<rapidjson::SizeType>(bucket.lower.size()), allocator);
282
            upper_val.SetString(bucket.upper.data(),
283
                                static_cast<rapidjson::SizeType>(bucket.upper.size()), allocator);
284
20
        } else {
285
20
            std::string lower_str = data_type->to_string(*lower_column, row_num, format_options);
286
20
            std::string upper_str = data_type->to_string(*upper_column, row_num, format_options);
287
20
            ++row_num;
288
20
            lower_val.SetString(lower_str.data(),
289
20
                                static_cast<rapidjson::SizeType>(lower_str.size()), allocator);
290
20
            upper_val.SetString(upper_str.data(),
291
20
                                static_cast<rapidjson::SizeType>(upper_str.size()), allocator);
292
20
        }
293
20
        rapidjson::Value bucket_json(rapidjson::kObjectType);
294
20
        bucket_json.AddMember("lower", lower_val, allocator);
295
20
        bucket_json.AddMember("upper", upper_val, allocator);
296
20
        bucket_json.AddMember("ndv", static_cast<int64_t>(bucket.ndv), allocator);
297
20
        bucket_json.AddMember("count", static_cast<int64_t>(bucket.count), allocator);
298
20
        bucket_json.AddMember("pre_sum", static_cast<int64_t>(bucket.pre_sum), allocator);
299
300
20
        bucket_arr.PushBack(bucket_json, allocator);
301
20
    }
302
303
8
    doc.AddMember("buckets", bucket_arr, allocator);
304
8
    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
305
8
    doc.Accept(writer);
306
307
8
    return !buckets.empty() && buffer.GetSize() > 0;
308
8
}
_ZN5doris17histogram_to_jsonIfEEbRN9rapidjson19GenericStringBufferINS1_4UTF8IcEENS1_12CrtAllocatorEEERKSt6vectorINS_6BucketIT_EESaISB_EERKSt10shared_ptrIKNS_9IDataTypeEE
Line
Count
Source
244
8
                       const DataTypePtr& data_type) {
245
8
    rapidjson::Document doc;
246
8
    doc.SetObject();
247
8
    rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();
248
249
8
    int num_buckets = cast_set<int>(buckets.size());
250
8
    doc.AddMember("num_buckets", num_buckets, allocator);
251
252
8
    rapidjson::Value bucket_arr(rapidjson::kArrayType);
253
8
    bucket_arr.Reserve(num_buckets, allocator);
254
255
8
    std::stringstream ss1;
256
8
    std::stringstream ss2;
257
258
8
    rapidjson::Value lower_val;
259
8
    rapidjson::Value upper_val;
260
261
    // Convert bucket's lower and upper to 2 columns
262
8
    MutableColumnPtr lower_column = data_type->create_column();
263
8
    MutableColumnPtr upper_column = data_type->create_column();
264
20
    for (const auto& bucket : buckets) {
265
        // String type is different, it has to pass in length
266
        // if it is string type , directly use string value
267
20
        if constexpr (!std::is_same_v<T, std::string>) {
268
20
            lower_column->insert_data(reinterpret_cast<const char*>(&bucket.lower), 0);
269
20
            upper_column->insert_data(reinterpret_cast<const char*>(&bucket.upper), 0);
270
20
        }
271
20
    }
272
8
    size_t row_num = 0;
273
274
8
    auto format_options = DataTypeSerDe::get_default_format_options();
275
8
    auto time_zone = cctz::utc_time_zone();
276
8
    format_options.timezone = &time_zone;
277
278
20
    for (const auto& bucket : buckets) {
279
        if constexpr (std::is_same_v<T, std::string>) {
280
            lower_val.SetString(bucket.lower.data(),
281
                                static_cast<rapidjson::SizeType>(bucket.lower.size()), allocator);
282
            upper_val.SetString(bucket.upper.data(),
283
                                static_cast<rapidjson::SizeType>(bucket.upper.size()), allocator);
284
20
        } else {
285
20
            std::string lower_str = data_type->to_string(*lower_column, row_num, format_options);
286
20
            std::string upper_str = data_type->to_string(*upper_column, row_num, format_options);
287
20
            ++row_num;
288
20
            lower_val.SetString(lower_str.data(),
289
20
                                static_cast<rapidjson::SizeType>(lower_str.size()), allocator);
290
20
            upper_val.SetString(upper_str.data(),
291
20
                                static_cast<rapidjson::SizeType>(upper_str.size()), allocator);
292
20
        }
293
20
        rapidjson::Value bucket_json(rapidjson::kObjectType);
294
20
        bucket_json.AddMember("lower", lower_val, allocator);
295
20
        bucket_json.AddMember("upper", upper_val, allocator);
296
20
        bucket_json.AddMember("ndv", static_cast<int64_t>(bucket.ndv), allocator);
297
20
        bucket_json.AddMember("count", static_cast<int64_t>(bucket.count), allocator);
298
20
        bucket_json.AddMember("pre_sum", static_cast<int64_t>(bucket.pre_sum), allocator);
299
300
20
        bucket_arr.PushBack(bucket_json, allocator);
301
20
    }
302
303
8
    doc.AddMember("buckets", bucket_arr, allocator);
304
8
    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
305
8
    doc.Accept(writer);
306
307
8
    return !buckets.empty() && buffer.GetSize() > 0;
308
8
}
_ZN5doris17histogram_to_jsonIdEEbRN9rapidjson19GenericStringBufferINS1_4UTF8IcEENS1_12CrtAllocatorEEERKSt6vectorINS_6BucketIT_EESaISB_EERKSt10shared_ptrIKNS_9IDataTypeEE
Line
Count
Source
244
8
                       const DataTypePtr& data_type) {
245
8
    rapidjson::Document doc;
246
8
    doc.SetObject();
247
8
    rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();
248
249
8
    int num_buckets = cast_set<int>(buckets.size());
250
8
    doc.AddMember("num_buckets", num_buckets, allocator);
251
252
8
    rapidjson::Value bucket_arr(rapidjson::kArrayType);
253
8
    bucket_arr.Reserve(num_buckets, allocator);
254
255
8
    std::stringstream ss1;
256
8
    std::stringstream ss2;
257
258
8
    rapidjson::Value lower_val;
259
8
    rapidjson::Value upper_val;
260
261
    // Convert bucket's lower and upper to 2 columns
262
8
    MutableColumnPtr lower_column = data_type->create_column();
263
8
    MutableColumnPtr upper_column = data_type->create_column();
264
20
    for (const auto& bucket : buckets) {
265
        // String type is different, it has to pass in length
266
        // if it is string type , directly use string value
267
20
        if constexpr (!std::is_same_v<T, std::string>) {
268
20
            lower_column->insert_data(reinterpret_cast<const char*>(&bucket.lower), 0);
269
20
            upper_column->insert_data(reinterpret_cast<const char*>(&bucket.upper), 0);
270
20
        }
271
20
    }
272
8
    size_t row_num = 0;
273
274
8
    auto format_options = DataTypeSerDe::get_default_format_options();
275
8
    auto time_zone = cctz::utc_time_zone();
276
8
    format_options.timezone = &time_zone;
277
278
20
    for (const auto& bucket : buckets) {
279
        if constexpr (std::is_same_v<T, std::string>) {
280
            lower_val.SetString(bucket.lower.data(),
281
                                static_cast<rapidjson::SizeType>(bucket.lower.size()), allocator);
282
            upper_val.SetString(bucket.upper.data(),
283
                                static_cast<rapidjson::SizeType>(bucket.upper.size()), allocator);
284
20
        } else {
285
20
            std::string lower_str = data_type->to_string(*lower_column, row_num, format_options);
286
20
            std::string upper_str = data_type->to_string(*upper_column, row_num, format_options);
287
20
            ++row_num;
288
20
            lower_val.SetString(lower_str.data(),
289
20
                                static_cast<rapidjson::SizeType>(lower_str.size()), allocator);
290
20
            upper_val.SetString(upper_str.data(),
291
20
                                static_cast<rapidjson::SizeType>(upper_str.size()), allocator);
292
20
        }
293
20
        rapidjson::Value bucket_json(rapidjson::kObjectType);
294
20
        bucket_json.AddMember("lower", lower_val, allocator);
295
20
        bucket_json.AddMember("upper", upper_val, allocator);
296
20
        bucket_json.AddMember("ndv", static_cast<int64_t>(bucket.ndv), allocator);
297
20
        bucket_json.AddMember("count", static_cast<int64_t>(bucket.count), allocator);
298
20
        bucket_json.AddMember("pre_sum", static_cast<int64_t>(bucket.pre_sum), allocator);
299
300
20
        bucket_arr.PushBack(bucket_json, allocator);
301
20
    }
302
303
8
    doc.AddMember("buckets", bucket_arr, allocator);
304
8
    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
305
8
    doc.Accept(writer);
306
307
8
    return !buckets.empty() && buffer.GetSize() > 0;
308
8
}
Unexecuted instantiation: _ZN5doris17histogram_to_jsonINS_7DecimalIiEEEEbRN9rapidjson19GenericStringBufferINS3_4UTF8IcEENS3_12CrtAllocatorEEERKSt6vectorINS_6BucketIT_EESaISD_EERKSt10shared_ptrIKNS_9IDataTypeEE
Unexecuted instantiation: _ZN5doris17histogram_to_jsonINS_7DecimalIlEEEEbRN9rapidjson19GenericStringBufferINS3_4UTF8IcEENS3_12CrtAllocatorEEERKSt6vectorINS_6BucketIT_EESaISD_EERKSt10shared_ptrIKNS_9IDataTypeEE
Unexecuted instantiation: _ZN5doris17histogram_to_jsonINS_12Decimal128V3EEEbRN9rapidjson19GenericStringBufferINS2_4UTF8IcEENS2_12CrtAllocatorEEERKSt6vectorINS_6BucketIT_EESaISC_EERKSt10shared_ptrIKNS_9IDataTypeEE
Unexecuted instantiation: _ZN5doris17histogram_to_jsonINS_7DecimalIN4wide7integerILm256EiEEEEEEbRN9rapidjson19GenericStringBufferINS6_4UTF8IcEENS6_12CrtAllocatorEEERKSt6vectorINS_6BucketIT_EESaISG_EERKSt10shared_ptrIKNS_9IDataTypeEE
_ZN5doris17histogram_to_jsonINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEbRN9rapidjson19GenericStringBufferINS7_4UTF8IcEENS7_12CrtAllocatorEEERKSt6vectorINS_6BucketIT_EESaISH_EERKSt10shared_ptrIKNS_9IDataTypeEE
Line
Count
Source
244
8
                       const DataTypePtr& data_type) {
245
8
    rapidjson::Document doc;
246
8
    doc.SetObject();
247
8
    rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();
248
249
8
    int num_buckets = cast_set<int>(buckets.size());
250
8
    doc.AddMember("num_buckets", num_buckets, allocator);
251
252
8
    rapidjson::Value bucket_arr(rapidjson::kArrayType);
253
8
    bucket_arr.Reserve(num_buckets, allocator);
254
255
8
    std::stringstream ss1;
256
8
    std::stringstream ss2;
257
258
8
    rapidjson::Value lower_val;
259
8
    rapidjson::Value upper_val;
260
261
    // Convert bucket's lower and upper to 2 columns
262
8
    MutableColumnPtr lower_column = data_type->create_column();
263
8
    MutableColumnPtr upper_column = data_type->create_column();
264
20
    for (const auto& bucket : buckets) {
265
        // String type is different, it has to pass in length
266
        // if it is string type , directly use string value
267
        if constexpr (!std::is_same_v<T, std::string>) {
268
            lower_column->insert_data(reinterpret_cast<const char*>(&bucket.lower), 0);
269
            upper_column->insert_data(reinterpret_cast<const char*>(&bucket.upper), 0);
270
        }
271
20
    }
272
8
    size_t row_num = 0;
273
274
8
    auto format_options = DataTypeSerDe::get_default_format_options();
275
8
    auto time_zone = cctz::utc_time_zone();
276
8
    format_options.timezone = &time_zone;
277
278
20
    for (const auto& bucket : buckets) {
279
20
        if constexpr (std::is_same_v<T, std::string>) {
280
20
            lower_val.SetString(bucket.lower.data(),
281
20
                                static_cast<rapidjson::SizeType>(bucket.lower.size()), allocator);
282
20
            upper_val.SetString(bucket.upper.data(),
283
20
                                static_cast<rapidjson::SizeType>(bucket.upper.size()), allocator);
284
        } else {
285
            std::string lower_str = data_type->to_string(*lower_column, row_num, format_options);
286
            std::string upper_str = data_type->to_string(*upper_column, row_num, format_options);
287
            ++row_num;
288
            lower_val.SetString(lower_str.data(),
289
                                static_cast<rapidjson::SizeType>(lower_str.size()), allocator);
290
            upper_val.SetString(upper_str.data(),
291
                                static_cast<rapidjson::SizeType>(upper_str.size()), allocator);
292
        }
293
20
        rapidjson::Value bucket_json(rapidjson::kObjectType);
294
20
        bucket_json.AddMember("lower", lower_val, allocator);
295
20
        bucket_json.AddMember("upper", upper_val, allocator);
296
20
        bucket_json.AddMember("ndv", static_cast<int64_t>(bucket.ndv), allocator);
297
20
        bucket_json.AddMember("count", static_cast<int64_t>(bucket.count), allocator);
298
20
        bucket_json.AddMember("pre_sum", static_cast<int64_t>(bucket.pre_sum), allocator);
299
300
20
        bucket_arr.PushBack(bucket_json, allocator);
301
20
    }
302
303
8
    doc.AddMember("buckets", bucket_arr, allocator);
304
8
    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
305
8
    doc.Accept(writer);
306
307
8
    return !buckets.empty() && buffer.GetSize() > 0;
308
8
}
_ZN5doris17histogram_to_jsonINS_11DateV2ValueINS_15DateV2ValueTypeEEEEEbRN9rapidjson19GenericStringBufferINS4_4UTF8IcEENS4_12CrtAllocatorEEERKSt6vectorINS_6BucketIT_EESaISE_EERKSt10shared_ptrIKNS_9IDataTypeEE
Line
Count
Source
244
4
                       const DataTypePtr& data_type) {
245
4
    rapidjson::Document doc;
246
4
    doc.SetObject();
247
4
    rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();
248
249
4
    int num_buckets = cast_set<int>(buckets.size());
250
4
    doc.AddMember("num_buckets", num_buckets, allocator);
251
252
4
    rapidjson::Value bucket_arr(rapidjson::kArrayType);
253
4
    bucket_arr.Reserve(num_buckets, allocator);
254
255
4
    std::stringstream ss1;
256
4
    std::stringstream ss2;
257
258
4
    rapidjson::Value lower_val;
259
4
    rapidjson::Value upper_val;
260
261
    // Convert bucket's lower and upper to 2 columns
262
4
    MutableColumnPtr lower_column = data_type->create_column();
263
4
    MutableColumnPtr upper_column = data_type->create_column();
264
20
    for (const auto& bucket : buckets) {
265
        // String type is different, it has to pass in length
266
        // if it is string type , directly use string value
267
20
        if constexpr (!std::is_same_v<T, std::string>) {
268
20
            lower_column->insert_data(reinterpret_cast<const char*>(&bucket.lower), 0);
269
20
            upper_column->insert_data(reinterpret_cast<const char*>(&bucket.upper), 0);
270
20
        }
271
20
    }
272
4
    size_t row_num = 0;
273
274
4
    auto format_options = DataTypeSerDe::get_default_format_options();
275
4
    auto time_zone = cctz::utc_time_zone();
276
4
    format_options.timezone = &time_zone;
277
278
20
    for (const auto& bucket : buckets) {
279
        if constexpr (std::is_same_v<T, std::string>) {
280
            lower_val.SetString(bucket.lower.data(),
281
                                static_cast<rapidjson::SizeType>(bucket.lower.size()), allocator);
282
            upper_val.SetString(bucket.upper.data(),
283
                                static_cast<rapidjson::SizeType>(bucket.upper.size()), allocator);
284
20
        } else {
285
20
            std::string lower_str = data_type->to_string(*lower_column, row_num, format_options);
286
20
            std::string upper_str = data_type->to_string(*upper_column, row_num, format_options);
287
20
            ++row_num;
288
20
            lower_val.SetString(lower_str.data(),
289
20
                                static_cast<rapidjson::SizeType>(lower_str.size()), allocator);
290
20
            upper_val.SetString(upper_str.data(),
291
20
                                static_cast<rapidjson::SizeType>(upper_str.size()), allocator);
292
20
        }
293
20
        rapidjson::Value bucket_json(rapidjson::kObjectType);
294
20
        bucket_json.AddMember("lower", lower_val, allocator);
295
20
        bucket_json.AddMember("upper", upper_val, allocator);
296
20
        bucket_json.AddMember("ndv", static_cast<int64_t>(bucket.ndv), allocator);
297
20
        bucket_json.AddMember("count", static_cast<int64_t>(bucket.count), allocator);
298
20
        bucket_json.AddMember("pre_sum", static_cast<int64_t>(bucket.pre_sum), allocator);
299
300
20
        bucket_arr.PushBack(bucket_json, allocator);
301
20
    }
302
303
4
    doc.AddMember("buckets", bucket_arr, allocator);
304
4
    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
305
4
    doc.Accept(writer);
306
307
4
    return !buckets.empty() && buffer.GetSize() > 0;
308
4
}
_ZN5doris17histogram_to_jsonINS_11DateV2ValueINS_19DateTimeV2ValueTypeEEEEEbRN9rapidjson19GenericStringBufferINS4_4UTF8IcEENS4_12CrtAllocatorEEERKSt6vectorINS_6BucketIT_EESaISE_EERKSt10shared_ptrIKNS_9IDataTypeEE
Line
Count
Source
244
4
                       const DataTypePtr& data_type) {
245
4
    rapidjson::Document doc;
246
4
    doc.SetObject();
247
4
    rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();
248
249
4
    int num_buckets = cast_set<int>(buckets.size());
250
4
    doc.AddMember("num_buckets", num_buckets, allocator);
251
252
4
    rapidjson::Value bucket_arr(rapidjson::kArrayType);
253
4
    bucket_arr.Reserve(num_buckets, allocator);
254
255
4
    std::stringstream ss1;
256
4
    std::stringstream ss2;
257
258
4
    rapidjson::Value lower_val;
259
4
    rapidjson::Value upper_val;
260
261
    // Convert bucket's lower and upper to 2 columns
262
4
    MutableColumnPtr lower_column = data_type->create_column();
263
4
    MutableColumnPtr upper_column = data_type->create_column();
264
20
    for (const auto& bucket : buckets) {
265
        // String type is different, it has to pass in length
266
        // if it is string type , directly use string value
267
20
        if constexpr (!std::is_same_v<T, std::string>) {
268
20
            lower_column->insert_data(reinterpret_cast<const char*>(&bucket.lower), 0);
269
20
            upper_column->insert_data(reinterpret_cast<const char*>(&bucket.upper), 0);
270
20
        }
271
20
    }
272
4
    size_t row_num = 0;
273
274
4
    auto format_options = DataTypeSerDe::get_default_format_options();
275
4
    auto time_zone = cctz::utc_time_zone();
276
4
    format_options.timezone = &time_zone;
277
278
20
    for (const auto& bucket : buckets) {
279
        if constexpr (std::is_same_v<T, std::string>) {
280
            lower_val.SetString(bucket.lower.data(),
281
                                static_cast<rapidjson::SizeType>(bucket.lower.size()), allocator);
282
            upper_val.SetString(bucket.upper.data(),
283
                                static_cast<rapidjson::SizeType>(bucket.upper.size()), allocator);
284
20
        } else {
285
20
            std::string lower_str = data_type->to_string(*lower_column, row_num, format_options);
286
20
            std::string upper_str = data_type->to_string(*upper_column, row_num, format_options);
287
20
            ++row_num;
288
20
            lower_val.SetString(lower_str.data(),
289
20
                                static_cast<rapidjson::SizeType>(lower_str.size()), allocator);
290
20
            upper_val.SetString(upper_str.data(),
291
20
                                static_cast<rapidjson::SizeType>(upper_str.size()), allocator);
292
20
        }
293
20
        rapidjson::Value bucket_json(rapidjson::kObjectType);
294
20
        bucket_json.AddMember("lower", lower_val, allocator);
295
20
        bucket_json.AddMember("upper", upper_val, allocator);
296
20
        bucket_json.AddMember("ndv", static_cast<int64_t>(bucket.ndv), allocator);
297
20
        bucket_json.AddMember("count", static_cast<int64_t>(bucket.count), allocator);
298
20
        bucket_json.AddMember("pre_sum", static_cast<int64_t>(bucket.pre_sum), allocator);
299
300
20
        bucket_arr.PushBack(bucket_json, allocator);
301
20
    }
302
303
4
    doc.AddMember("buckets", bucket_arr, allocator);
304
4
    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
305
4
    doc.Accept(writer);
306
307
4
    return !buckets.empty() && buffer.GetSize() > 0;
308
4
}
Unexecuted instantiation: _ZN5doris17histogram_to_jsonINS_16TimeStampNsValueEEEbRN9rapidjson19GenericStringBufferINS2_4UTF8IcEENS2_12CrtAllocatorEEERKSt6vectorINS_6BucketIT_EESaISC_EERKSt10shared_ptrIKNS_9IDataTypeEE
Unexecuted instantiation: _ZN5doris17histogram_to_jsonINS_16TimestampTzValueEEEbRN9rapidjson19GenericStringBufferINS2_4UTF8IcEENS2_12CrtAllocatorEEERKSt6vectorINS_6BucketIT_EESaISC_EERKSt10shared_ptrIKNS_9IDataTypeEE
_ZN5doris17histogram_to_jsonIoEEbRN9rapidjson19GenericStringBufferINS1_4UTF8IcEENS1_12CrtAllocatorEEERKSt6vectorINS_6BucketIT_EESaISB_EERKSt10shared_ptrIKNS_9IDataTypeEE
Line
Count
Source
244
12
                       const DataTypePtr& data_type) {
245
12
    rapidjson::Document doc;
246
12
    doc.SetObject();
247
12
    rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();
248
249
12
    int num_buckets = cast_set<int>(buckets.size());
250
12
    doc.AddMember("num_buckets", num_buckets, allocator);
251
252
12
    rapidjson::Value bucket_arr(rapidjson::kArrayType);
253
12
    bucket_arr.Reserve(num_buckets, allocator);
254
255
12
    std::stringstream ss1;
256
12
    std::stringstream ss2;
257
258
12
    rapidjson::Value lower_val;
259
12
    rapidjson::Value upper_val;
260
261
    // Convert bucket's lower and upper to 2 columns
262
12
    MutableColumnPtr lower_column = data_type->create_column();
263
12
    MutableColumnPtr upper_column = data_type->create_column();
264
40
    for (const auto& bucket : buckets) {
265
        // String type is different, it has to pass in length
266
        // if it is string type , directly use string value
267
40
        if constexpr (!std::is_same_v<T, std::string>) {
268
40
            lower_column->insert_data(reinterpret_cast<const char*>(&bucket.lower), 0);
269
40
            upper_column->insert_data(reinterpret_cast<const char*>(&bucket.upper), 0);
270
40
        }
271
40
    }
272
12
    size_t row_num = 0;
273
274
12
    auto format_options = DataTypeSerDe::get_default_format_options();
275
12
    auto time_zone = cctz::utc_time_zone();
276
12
    format_options.timezone = &time_zone;
277
278
40
    for (const auto& bucket : buckets) {
279
        if constexpr (std::is_same_v<T, std::string>) {
280
            lower_val.SetString(bucket.lower.data(),
281
                                static_cast<rapidjson::SizeType>(bucket.lower.size()), allocator);
282
            upper_val.SetString(bucket.upper.data(),
283
                                static_cast<rapidjson::SizeType>(bucket.upper.size()), allocator);
284
40
        } else {
285
40
            std::string lower_str = data_type->to_string(*lower_column, row_num, format_options);
286
40
            std::string upper_str = data_type->to_string(*upper_column, row_num, format_options);
287
40
            ++row_num;
288
40
            lower_val.SetString(lower_str.data(),
289
40
                                static_cast<rapidjson::SizeType>(lower_str.size()), allocator);
290
40
            upper_val.SetString(upper_str.data(),
291
40
                                static_cast<rapidjson::SizeType>(upper_str.size()), allocator);
292
40
        }
293
40
        rapidjson::Value bucket_json(rapidjson::kObjectType);
294
40
        bucket_json.AddMember("lower", lower_val, allocator);
295
40
        bucket_json.AddMember("upper", upper_val, allocator);
296
40
        bucket_json.AddMember("ndv", static_cast<int64_t>(bucket.ndv), allocator);
297
40
        bucket_json.AddMember("count", static_cast<int64_t>(bucket.count), allocator);
298
40
        bucket_json.AddMember("pre_sum", static_cast<int64_t>(bucket.pre_sum), allocator);
299
300
40
        bucket_arr.PushBack(bucket_json, allocator);
301
40
    }
302
303
12
    doc.AddMember("buckets", bucket_arr, allocator);
304
12
    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
305
12
    doc.Accept(writer);
306
307
12
    return !buckets.empty() && buffer.GetSize() > 0;
308
12
}
309
} // namespace  doris