Coverage Report

Created: 2026-08-17 23:49

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 <utility>
29
#include <vector>
30
31
#include "common/exception.h"
32
33
namespace doris::segment_v2::inverted_index {
34
35
class Settings {
36
public:
37
974
    Settings() = default;
38
176
    Settings(std::unordered_map<std::string, std::string> args) : _args(std::move(args)) {}
39
1.26k
    Settings(const Settings&) = default;
40
340
    Settings(Settings&&) = default;
41
2.75k
    ~Settings() = default;
42
43
710
    void set(const std::string& key, const std::string& value) {
44
710
        _args.insert_or_assign(key, value);
45
710
    }
46
47
203
    bool empty() const { return _args.empty(); }
48
49
3.19k
    bool get_bool(const std::string& key, bool default_value) const {
50
3.19k
        auto it = _args.find(key);
51
3.19k
        if (it != _args.end()) {
52
1.79k
            std::string value = it->second;
53
1.79k
            std::transform(value.begin(), value.end(), value.begin(),
54
8.13k
                           [](unsigned char c) { return std::tolower(c); });
55
1.79k
            if (value == "true" || value == "1") {
56
818
                return true;
57
974
            } else if (value == "false" || value == "0") {
58
972
                return false;
59
972
            }
60
1.79k
        }
61
1.40k
        return default_value;
62
3.19k
    }
63
64
1.59k
    int32_t get_int(const std::string& key, int32_t default_value) const {
65
1.59k
        auto it = _args.find(key);
66
1.59k
        if (it != _args.end()) {
67
204
            try {
68
204
                size_t pos;
69
204
                int32_t num = std::stoi(it->second, &pos);
70
204
                if (pos == it->second.size()) {
71
202
                    return num;
72
202
                }
73
204
            } catch (...) {
74
1
                throw Exception(ErrorCode::INVALID_ARGUMENT,
75
1
                                "stoi failed (invalid argument or out of range): " + it->second);
76
1
            }
77
204
        }
78
1.38k
        return default_value;
79
1.59k
    }
80
81
539
    std::string get_string(const std::string& key, const std::string& default_value = "") const {
82
539
        auto it = _args.find(key);
83
539
        if (it != _args.end()) {
84
73
            return it->second;
85
73
        }
86
466
        return default_value;
87
539
    }
88
89
235
    std::vector<std::string> get_entry_list(const std::string& key) const {
90
235
        static const boost::regex sep(R"((?<=\])\s*,\s*(?=\[))");
91
235
        std::vector<std::string> lists;
92
235
        auto it = _args.find(key);
93
235
        if (it != _args.end()) {
94
221
            std::string trimmed_input = boost::algorithm::trim_copy(it->second);
95
221
            if (trimmed_input.empty()) {
96
1
                return lists;
97
1
            }
98
99
220
            auto validate_single = [&](const std::string& item, const std::string& prefix) {
100
31
                if (item.size() < 2 || item.front() != '[' || item.back() != ']') {
101
1
                    throw Exception(ErrorCode::INVALID_ARGUMENT,
102
1
                                    prefix + key + " must be enclosed in []");
103
1
                }
104
30
                int depth = 0;
105
213
                for (size_t i = 0; i + 1 < item.size(); ++i) {
106
183
                    char c = item[i];
107
183
                    if (c == '[') {
108
30
                        ++depth;
109
153
                    } else if (c == ']') {
110
0
                        --depth;
111
0
                        if (depth == 0) {
112
0
                            throw Exception(ErrorCode::INVALID_ARGUMENT,
113
0
                                            prefix + key + " must be enclosed in []");
114
0
                        }
115
0
                    }
116
183
                }
117
30
            };
118
119
220
            if (boost::regex_search(trimmed_input, sep)) {
120
12
                boost::sregex_token_iterator regex_it(trimmed_input.begin(), trimmed_input.end(),
121
12
                                                      sep, -1);
122
12
                boost::sregex_token_iterator end;
123
43
                for (; regex_it != end; ++regex_it) {
124
31
                    std::string item = boost::algorithm::trim_copy(regex_it->str());
125
31
                    validate_single(item, "Each item in ");
126
31
                    std::string content = item.substr(1, item.size() - 2);
127
31
                    if (!content.empty()) {
128
29
                        lists.emplace_back(content);
129
29
                    }
130
31
                }
131
208
            } else {
132
208
                if (trimmed_input.size() < 2 || trimmed_input.front() != '[' ||
133
208
                    trimmed_input.back() != ']') {
134
2
                    throw Exception(ErrorCode::INVALID_ARGUMENT,
135
2
                                    "Item in " + key + " must be enclosed in []");
136
2
                }
137
206
                std::string content = trimmed_input.substr(1, trimmed_input.size() - 2);
138
206
                if (!content.empty()) {
139
205
                    lists.emplace_back(content);
140
205
                }
141
206
            }
142
220
        }
143
232
        return lists;
144
235
    }
145
146
39
    std::unordered_set<std::string> get_word_set(const std::string& key) const {
147
39
        std::unordered_set<std::string> sets;
148
39
        auto it = _args.find(key);
149
39
        if (it != _args.end()) {
150
21
            std::vector<std::string> lists;
151
21
            boost::split(lists, it->second, boost::is_any_of(","));
152
31
            for (auto& str : lists) {
153
31
                boost::trim(str);
154
31
                if (!str.empty()) {
155
28
                    sets.insert(str);
156
28
                }
157
31
            }
158
21
        }
159
39
        return sets;
160
39
    }
161
162
1
    std::string to_string() {
163
1
        std::string result;
164
2
        for (const auto& [key, value] : _args) {
165
2
            if (!result.empty()) {
166
1
                result += ", ";
167
1
            }
168
2
            result += key + "=" + value;
169
2
        }
170
1
        return result;
171
1
    }
172
173
116
    std::vector<std::pair<std::string, std::string>> sorted_entries() const {
174
116
        std::vector<std::pair<std::string, std::string>> entries(_args.begin(), _args.end());
175
116
        std::sort(entries.begin(), entries.end());
176
116
        return entries;
177
116
    }
178
179
private:
180
    std::unordered_map<std::string, std::string> _args;
181
};
182
183
} // namespace doris::segment_v2::inverted_index