Coverage Report

Created: 2026-09-29 06:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/storage/index/inverted/setting.h
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#pragma once
19
20
#include <unicode/utf8.h>
21
22
#include <algorithm>
23
#include <boost/algorithm/string.hpp>
24
#include <boost/algorithm/string/split.hpp>
25
#include <boost/algorithm/string/trim.hpp>
26
#include <boost/regex.hpp>
27
#include <unordered_map>
28
#include <unordered_set>
29
#include <utility>
30
#include <vector>
31
32
#include "common/exception.h"
33
34
namespace doris::segment_v2::inverted_index {
35
36
class Settings {
37
public:
38
2.75k
    Settings() = default;
39
    Settings(std::unordered_map<std::string, std::string> args) : _args(std::move(args)) {}
40
3.12k
    Settings(const Settings&) = default;
41
1.45k
    Settings(Settings&&) = default;
42
7.71k
    ~Settings() = default;
43
44
1.77k
    void set(const std::string& key, const std::string& value) {
45
1.77k
        _args.insert_or_assign(key, value);
46
1.77k
    }
47
48
97
    bool empty() const { return _args.empty(); }
49
50
10.4k
    bool get_bool(const std::string& key, bool default_value) const {
51
10.4k
        auto it = _args.find(key);
52
10.4k
        if (it != _args.end()) {
53
4.72k
            std::string value = it->second;
54
4.72k
            std::transform(value.begin(), value.end(), value.begin(),
55
21.4k
                           [](unsigned char c) { return std::tolower(c); });
56
4.72k
            if (value == "true" || value == "1") {
57
2.17k
                return true;
58
2.55k
            } else if (value == "false" || value == "0") {
59
2.54k
                return false;
60
2.54k
            }
61
4.72k
        }
62
5.70k
        return default_value;
63
10.4k
    }
64
65
3.74k
    int32_t get_int(const std::string& key, int32_t default_value) const {
66
3.74k
        auto it = _args.find(key);
67
3.74k
        if (it != _args.end()) {
68
373
            try {
69
373
                size_t pos;
70
373
                int32_t num = std::stoi(it->second, &pos);
71
373
                if (pos == it->second.size()) {
72
369
                    return num;
73
369
                }
74
373
            } catch (...) {
75
2
                throw Exception(ErrorCode::INVALID_ARGUMENT,
76
2
                                "stoi failed (invalid argument or out of range): " + it->second);
77
2
            }
78
373
        }
79
3.37k
        return default_value;
80
3.74k
    }
81
82
1.23k
    std::string get_string(const std::string& key, const std::string& default_value = "") const {
83
1.23k
        auto it = _args.find(key);
84
1.23k
        if (it != _args.end()) {
85
181
            return it->second;
86
181
        }
87
1.05k
        return default_value;
88
1.23k
    }
89
90
190
    std::vector<std::string> get_entry_list(const std::string& key) const {
91
190
        static const boost::regex sep(R"((?<=\])\s*,\s*(?=\[))");
92
190
        std::vector<std::string> lists;
93
190
        auto it = _args.find(key);
94
190
        if (it != _args.end()) {
95
107
            std::string trimmed_input = boost::algorithm::trim_copy(it->second);
96
107
            if (trimmed_input.empty()) {
97
2
                return lists;
98
2
            }
99
100
105
            auto validate_single = [&](const std::string& item, const std::string& prefix) {
101
88
                if (item.size() < 2 || item.front() != '[' || item.back() != ']') {
102
2
                    throw Exception(ErrorCode::INVALID_ARGUMENT,
103
2
                                    prefix + key + " must be enclosed in []");
104
2
                }
105
86
                int depth = 0;
106
656
                for (size_t i = 0; i + 1 < item.size(); ++i) {
107
570
                    char c = item[i];
108
570
                    if (c == '[') {
109
86
                        ++depth;
110
484
                    } else if (c == ']') {
111
0
                        --depth;
112
0
                        if (depth == 0) {
113
0
                            throw Exception(ErrorCode::INVALID_ARGUMENT,
114
0
                                            prefix + key + " must be enclosed in []");
115
0
                        }
116
0
                    }
117
570
                }
118
86
            };
119
120
105
            if (boost::regex_search(trimmed_input, sep)) {
121
34
                boost::sregex_token_iterator regex_it(trimmed_input.begin(), trimmed_input.end(),
122
34
                                                      sep, -1);
123
34
                boost::sregex_token_iterator end;
124
122
                for (; regex_it != end; ++regex_it) {
125
88
                    std::string item = boost::algorithm::trim_copy(regex_it->str());
126
88
                    validate_single(item, "Each item in ");
127
88
                    std::string content = item.substr(1, item.size() - 2);
128
88
                    if (!content.empty()) {
129
84
                        lists.emplace_back(content);
130
84
                    }
131
88
                }
132
71
            } else {
133
71
                if (trimmed_input.size() < 2 || trimmed_input.front() != '[' ||
134
71
                    trimmed_input.back() != ']') {
135
4
                    throw Exception(ErrorCode::INVALID_ARGUMENT,
136
4
                                    "Item in " + key + " must be enclosed in []");
137
4
                }
138
67
                std::string content = trimmed_input.substr(1, trimmed_input.size() - 2);
139
67
                if (!content.empty()) {
140
65
                    lists.emplace_back(content);
141
65
                }
142
67
            }
143
105
        }
144
184
        return lists;
145
190
    }
146
147
166
    std::unordered_set<std::string> get_word_set(const std::string& key) const {
148
166
        std::unordered_set<std::string> sets;
149
166
        auto it = _args.find(key);
150
166
        if (it != _args.end()) {
151
50
            std::vector<std::string> lists;
152
50
            boost::split(lists, it->second, boost::is_any_of(","));
153
70
            for (auto& str : lists) {
154
70
                boost::trim(str);
155
70
                if (!str.empty()) {
156
64
                    sets.insert(str);
157
64
                }
158
70
            }
159
50
        }
160
166
        return sets;
161
166
    }
162
163
    std::string to_string() {
164
        std::string result;
165
        for (const auto& [key, value] : _args) {
166
            if (!result.empty()) {
167
                result += ", ";
168
            }
169
            result += key + "=" + value;
170
        }
171
        return result;
172
    }
173
174
0
    std::vector<std::pair<std::string, std::string>> sorted_entries() const {
175
0
        std::vector<std::pair<std::string, std::string>> entries(_args.begin(), _args.end());
176
0
        std::sort(entries.begin(), entries.end());
177
0
        return entries;
178
0
    }
179
180
private:
181
    std::unordered_map<std::string, std::string> _args;
182
};
183
184
} // namespace doris::segment_v2::inverted_index