forked from redpanda-data/redpanda
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstring_switch.h
More file actions
218 lines (193 loc) · 6.2 KB
/
string_switch.h
File metadata and controls
218 lines (193 loc) · 6.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
/*
* Copyright 2020 Redpanda Data, Inc.
*
* Use of this software is governed by the Business Source License
* included in the file licenses/BSL.md
*
* As of the Change Date specified in that file, in accordance with
* the Business Source License, use of this software will be governed
* by the Apache License, Version 2.0
*/
#pragma once
#include <optional>
#include <regex>
#include <stdexcept>
#include <string>
// an adaptation of https://llvm.org/doxygen/StringSwitch_8h_source.html
// with a smaller surface area
// TODO(agallego) - enable the following methods in c++20
// https://en.cppreference.com/w/cpp/string/basic_string_view/starts_with
// when std::string_view adds them
// string_switch& EndsWith(std::string_view S, T value);
// string_switch& starts_with(std::string_view S, T value);
/// A switch()-like statement whose match_all are string literals.
///
/// The string_switch class is a simple form of a switch() statement that
/// determines whether the given string matches one of the given string
/// literals. The template type parameter \p T is the type of the value that
/// will be returned from the string-switch expression. For example,
/// the following code switches on the name of a color in \c argv[i]:
///
/// \code
/// Color color = string_switch<Color>(argv[i])
/// .match("red", Red)
/// .match("orange", Orange)
/// .match("yellow", Yellow)
/// .match("green", Green)
/// .match("blue", Blue)
/// .match("indigo", Indigo)
/// .match_all("violet", "purple", Violet)
/// .default_match(UnknownColor);
/// \endcode
template<typename T, typename R = T>
class string_switch {
/// The string we are matching.
const std::string_view view;
/// The pointer to the result of this switch statement, once known,
/// null before that.
std::optional<T> result;
public:
constexpr explicit string_switch(std::string_view S)
: view(S)
, result() {}
// string_switch is not copyable.
string_switch(const string_switch&) = delete;
// string_switch is not assignable due to 'view' being 'const'.
void operator=(const string_switch&) = delete;
void operator=(string_switch&& other) = delete;
string_switch(string_switch&& other)
: view(other.view)
, result(std::move(other.result)) {}
~string_switch() = default;
// match-sensitive match matchers
constexpr string_switch& match(std::string_view S, T value) {
if (!result && view == S) {
result = std::move(value);
}
return *this;
}
constexpr string_switch& starts_with(std::string_view S, T value) {
if (!result && view.starts_with(S)) {
result = std::move(value);
}
return *this;
}
constexpr string_switch& ends_with(std::string_view S, T value) {
if (!result && view.ends_with(S)) {
result = std::move(value);
}
return *this;
}
constexpr string_switch&
match_all(std::string_view S0, std::string_view S1, T value) {
return match(S0, value).match(S1, value);
}
constexpr string_switch& match_all(
std::string_view S0, std::string_view S1, std::string_view S2, T value) {
return match(S0, value).match_all(S1, S2, value);
}
constexpr string_switch& match_all(
std::string_view S0,
std::string_view S1,
std::string_view S2,
std::string_view S3,
T value) {
return match(S0, value).match_all(S1, S2, S3, value);
}
constexpr string_switch& match_all(
std::string_view S0,
std::string_view S1,
std::string_view S2,
std::string_view S3,
std::string_view S4,
T value) {
return match(S0, value).match_all(S1, S2, S3, S4, value);
}
constexpr string_switch& match_all(
std::string_view S0,
std::string_view S1,
std::string_view S2,
std::string_view S3,
std::string_view S4,
std::string_view S5,
T value) {
return match(S0, value).match_all(S1, S2, S3, S4, S5, value);
}
constexpr string_switch& match_all(
std::string_view S0,
std::string_view S1,
std::string_view S2,
std::string_view S3,
std::string_view S4,
std::string_view S5,
std::string_view S6,
T value) {
return match(S0, value).match_all(S1, S2, S3, S4, S5, S6, value);
}
constexpr string_switch& match_all(
std::string_view S0,
std::string_view S1,
std::string_view S2,
std::string_view S3,
std::string_view S4,
std::string_view S5,
std::string_view S6,
std::string_view S7,
T value) {
return match(S0, value).match_all(S1, S2, S3, S4, S5, S6, S7, value);
}
constexpr string_switch& match_all(
std::string_view S0,
std::string_view S1,
std::string_view S2,
std::string_view S3,
std::string_view S4,
std::string_view S5,
std::string_view S6,
std::string_view S7,
std::string_view S8,
T value) {
return match(S0, value).match_all(
S1, S2, S3, S4, S5, S6, S7, S8, value);
}
constexpr string_switch& match_all(
std::string_view S0,
std::string_view S1,
std::string_view S2,
std::string_view S3,
std::string_view S4,
std::string_view S5,
std::string_view S6,
std::string_view S7,
std::string_view S8,
std::string_view S9,
T value) {
return match(S0, value).match_all(
S1, S2, S3, S4, S5, S6, S7, S8, S9, value);
}
constexpr string_switch& match_expr(std::string_view expr, T value) {
if (
!result
&& std::regex_search(
std::string{view.data(), view.size()},
std::regex{expr.data(), expr.size()})) {
result = std::move(value);
}
return *this;
}
constexpr R default_match(T value) {
if (result) {
return std::move(*result);
}
return value;
}
constexpr operator R() { // NOLINT
if (!result) {
throw std::runtime_error(
std::string(
"Fell off the end of a string-switch while matching: ")
+ std::string(view));
}
return std::move(*result);
}
};