NexusForce 1.0.0
A rigorously engineered full-stack C++ backend library.
载入中...
搜索中...
未找到
radix_router.hpp
浏览该文件的文档.
1#ifndef NEFORCE_NETWORK_HTTP_RADIX_ROUTER_HPP__
2#define NEFORCE_NETWORK_HTTP_RADIX_ROUTER_HPP__
3
12
15NEFORCE_BEGIN_NAMESPACE__
16NEFORCE_BEGIN_HTTP__
17
22
29class route_trie {
30public:
31 using handler_type = function<void(http_request&, http_response&)>;
32
33 struct node {
34 string segment;
36 size_t param_index = numeric_traits<size_t>::max();
37 size_t wildcard_index = numeric_traits<size_t>::max();
38 string param_name;
39 handler_type handler;
40 bool has_handler = false;
41 };
42
43private:
44 vector<node> nodes_{1};
45
46public:
47 route_trie() = default;
48
54 void insert(const string& pattern, handler_type handler) {
55 if (pattern.empty() || pattern.front() != '/') {
56 return;
57 }
58
59 size_t node_idx = 0;
60 size_t pos = 1;
61
62 while (pos <= pattern.length()) {
63 size_t slash = pattern.find('/', pos);
64 if (slash == string::npos) {
65 slash = pattern.length();
66 }
67
68 const string_view segment = pattern.view(pos, slash - pos);
69 pos = slash + 1;
70
71 if (segment.empty()) {
72 continue;
73 }
74
75 if (segment[0] == ':') {
76 string pname(segment.substr(1));
77 if (nodes_[node_idx].param_index == numeric_traits<size_t>::max()) {
78 nodes_[node_idx].param_index = nodes_.size();
79 nodes_.emplace_back();
80 nodes_.back().segment = pname;
81 }
82 node_idx = nodes_[node_idx].param_index;
83 nodes_[node_idx].param_name = pname;
84 } else if (segment[0] == '*' && segment.length() == 1) {
85 if (nodes_[node_idx].wildcard_index == numeric_traits<size_t>::max()) {
86 nodes_[node_idx].wildcard_index = nodes_.size();
87 nodes_.emplace_back();
88 nodes_.back().segment = "*";
89 }
90 node_idx = nodes_[node_idx].wildcard_index;
91 } else {
92 string seg(segment);
93 auto& children = nodes_[node_idx].children;
94 auto it = children.find(seg);
95 if (it == children.end()) {
96 children[seg] = nodes_.size();
97 nodes_.emplace_back();
98 nodes_.back().segment = seg;
99 node_idx = nodes_.size() - 1;
100 } else {
101 node_idx = it->second;
102 }
103 }
104 }
105
106 nodes_[node_idx].handler = move(handler);
107 nodes_[node_idx].has_handler = true;
108 }
109
117 NEFORCE_NODISCARD handler_type match(const string& path, bool case_sensitive,
118 vector<pair<string, string>>& params) {
119 if (path.empty() || path.front() != '/') {
120 return handler_type{};
121 }
122
123 size_t node_idx = 0;
124 size_t pos = 1;
125
126 while (pos <= path.length()) {
127 size_t slash = path.find('/', pos);
128 if (slash == string::npos) {
129 slash = path.length();
130 }
131
132 string_view segment = path.view(pos, slash - pos);
133 pos = slash + 1;
134
135 if (segment.empty()) {
136 continue;
137 }
138
139 const node& current = nodes_[node_idx];
140
141 const string seg_key(segment);
142 if (!case_sensitive) {
143 bool found = false;
144 for (const auto& child: current.children) {
145 string key_lower = child.first;
146 if (key_lower.lowercase() == seg_key.lowercase()) {
147 node_idx = child.second;
148 found = true;
149 break;
150 }
151 }
152 if (found) {
153 continue;
154 }
155 } else {
156 auto it = current.children.find(seg_key);
157 if (it != current.children.end()) {
158 node_idx = it->second;
159 continue;
160 }
161 }
162
163 if (current.param_index != numeric_traits<size_t>::max()) {
164 params.emplace_back(nodes_[current.param_index].param_name, string(segment));
165 node_idx = current.param_index;
166 continue;
167 }
168
169 if (current.wildcard_index != numeric_traits<size_t>::max()) {
170 string remaining;
171 remaining.reserve(path.length() - (slash - segment.length()));
172 remaining.append(segment);
173 if (slash < path.length()) {
174 remaining += path.view(slash);
175 }
176 params.emplace_back("*", remaining);
177 node_idx = current.wildcard_index;
178 break;
179 }
180
181 return handler_type{};
182 }
183
184 if (nodes_[node_idx].has_handler) {
185 return nodes_[node_idx].handler;
186 }
187 return handler_type{};
188 }
189
193 NEFORCE_NODISCARD bool contains_path(const string& path, bool case_sensitive) const {
194 if (path.empty() || path.front() != '/') {
195 return false;
196 }
197
198 size_t node_idx = 0;
199 size_t pos = 1;
200
201 while (pos <= path.length()) {
202 size_t slash = path.find('/', pos);
203 if (slash == string::npos) {
204 slash = path.length();
205 }
206
207 string_view segment = path.view(pos, slash - pos);
208 pos = slash + 1;
209
210 if (segment.empty()) {
211 continue;
212 }
213
214 const node& current = nodes_[node_idx];
215
216 string seg_key(segment);
217 if (!case_sensitive) {
218 seg_key = seg_key.lowercase();
219 bool found = false;
220 for (const auto& child: current.children) {
221 string key_lower = child.first;
222 if (key_lower.lowercase() == seg_key) {
223 node_idx = child.second;
224 found = true;
225 break;
226 }
227 }
228 if (found) {
229 continue;
230 }
231 } else {
232 auto it = current.children.find(seg_key);
233 if (it != current.children.end()) {
234 node_idx = it->second;
235 continue;
236 }
237 }
238
239 if (current.param_index != numeric_traits<size_t>::max()) {
240 node_idx = current.param_index;
241 continue;
242 }
243
244 if (current.wildcard_index != numeric_traits<size_t>::max()) {
245 return true;
246 }
247
248 return false;
249 }
250
251 return nodes_[node_idx].has_handler;
252 }
253
255 void clear() {
256 nodes_.clear();
257 nodes_.emplace_back();
258 }
259
261 NEFORCE_NODISCARD size_t size() const noexcept { return nodes_.size(); }
262};
263 // HTTP
265
266NEFORCE_END_HTTP__
267NEFORCE_END_NAMESPACE__
268#endif // NEFORCE_NETWORK_HTTP_RADIX_ROUTER_HPP__
constexpr size_type length() const noexcept
获取字符串长度
constexpr bool empty() const noexcept
检查是否为空
constexpr basic_string_view substr(const size_type off=0, const size_type count=npos) const
获取子视图
constexpr view_type view() const noexcept
获取字符串视图
constexpr size_type length() const noexcept
获取字符串长度
constexpr size_type find(const basic_string &other, const size_type n=0) const noexcept
查找子串
constexpr bool empty() const noexcept
检查是否为空
constexpr basic_string & append(size_type n, value_type value)
追加多个相同字符
constexpr size_type size() const noexcept
获取字符数
constexpr basic_string & lowercase() noexcept(noexcept(_NEFORCE transform(begin(), end(), begin(), _NEFORCE to_lowercase< CharT >)))
转换为小写
static constexpr size_type npos
constexpr void reserve(const size_type n)
预留容量
constexpr reference front() noexcept
访问第一个字符
函数包装器主模板声明
handler_type match(const string &path, bool case_sensitive, vector< pair< string, string > > &params)
匹配路径
void clear()
清除所有路由规则
size_t size() const noexcept
获取 trie 节点总数
bool contains_path(const string &path, bool case_sensitive) const
检查路径是否存在
void insert(const string &pattern, handler_type handler)
插入路由规则
static constexpr T max() noexcept
获取类型的最大值
文件路径类
string_view view() const noexcept
获取路径字符串视图
bool empty() const noexcept
检查路径是否为空
动态大小数组容器
通用函数包装器
http_server_response http_response
HTTP响应类型别名
http_server_request http_request
HTTP请求类型别名
constexpr Iterator2 move(Iterator1 first, Iterator1 last, Iterator2 result) noexcept(noexcept(inner::__move_aux(first, last, result)))
移动范围元素
basic_string_view< char > string_view
字符字符串视图
HTTP服务器消息结构
存储两个值的元组对