-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathurl_scanner.hpp
More file actions
executable file
·144 lines (124 loc) · 3.94 KB
/
Copy pathurl_scanner.hpp
File metadata and controls
executable file
·144 lines (124 loc) · 3.94 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
#pragma once
#include <tuple>
#include <string>
#include <stdexcept>
#include <functional>
namespace cpplask {
template<typename...PARAMS, typename ITERATOR>
bool url_scan2(std::tuple<>, ITERATOR pattern,ITERATOR path,ITERATOR pattern_end,ITERATOR path_end, std::function<void(PARAMS...)>& f, PARAMS... params) {
while (path != path_end && pattern != pattern_end) {
// There maybe some text after the last %, deal with it.
if (*path != *pattern) {
return false;
}
path++;
pattern++;
}
if (path != path_end || pattern != pattern_end) {
return false;
}
f(params...);
return true;
}
template <typename VALUE_TYPE>
class field_handler {
VALUE_TYPE value;
public:
field_handler() : value() { }
bool try_append(char c) {
return value.try_append(c);
}
int get_value() {
return value.get_value();
}
};
template <>
class field_handler<int> {
std::string field;
public:
field_handler() : field() { }
bool try_append(char c) {
if (!std::isdigit(c))
return false;
field += c;
return true;
}
int get_value() {
return std::stoi(field.c_str());
}
};
template <>
class field_handler<std::string> {
std::string field;
public:
field_handler() : field() { }
bool try_append(char c) {
if (c == '/')
return false;
field += c;
return true;
}
std::string get_value() {
return field.c_str();
}
};
struct path_t {
path_t() : str() { }
path_t(std::string str_in) : str(str_in) { }
std::string str;
};
template <>
class field_handler<path_t> {
std::string field;
public:
field_handler() : field() { }
bool try_append(char c) {
field += c;
return true;
}
path_t get_value() {
return path_t (field);
}
};
template<typename... PARAMS, typename... PARAMS_IN, typename... PARAMS_OUT, typename ITERATOR, typename VALUE>
bool url_scan2(std::tuple<VALUE,PARAMS_IN...>, ITERATOR pattern, ITERATOR path, ITERATOR pattern_end, ITERATOR path_end, std::function<void(PARAMS...)>& f, PARAMS_OUT... params) {
// At this point we know there's at least one more % to find as the std::tuple has at least one type in it (PARAMS_IN... could be empty).
// effectively each recursion takes the head of the tuple's types and moves it to the back of the arguments list (PARAMS_OUT).
// this should never happen....
static_assert(sizeof...(PARAMS_IN) + sizeof...(PARAMS_OUT) + 1 == sizeof...(PARAMS), "template error:expected 1+PARAMS_IN+PARAMS_OUT=PARAMS");
// probably pointless templating...
typename ITERATOR::value_type current_pattern;
typename ITERATOR::value_type current_path;
// I feel bad about a while(true) but this genuinely feels like the cleanest
// fastest way. Loop until we see a % or something goes wrong.
while (true) {
current_pattern = *pattern;
current_path = *path;
path++;
pattern++;
if (current_pattern == '%') {
break;
}
else if (current_pattern != current_path) {
return false;
}
else if (pattern == pattern_end || path == path_end) {
return false;
}
}
std::string raw_value(1,current_path);
field_handler<VALUE> int_f;
if (!int_f.try_append(current_path))
return false;
while (int_f.try_append(*path) && path != path_end) {
path++;
};
return url_scan2(std::tuple<PARAMS_IN...>(), pattern, path, pattern_end, path_end, f, params..., int_f.get_value());
}
template<typename... PARAMS>
bool url_scan(std::string pattern, std::string path, std::function<void(PARAMS...)>& f) {
// Have to do something awkward with tuples as parameter unpacking doesn't seem to work properly
// with explicit templates.
return url_scan2(std::tuple<PARAMS...>(), pattern.begin(), path.begin(), pattern.end(), path.end(), f);
}
}