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
|
#ifndef UTIL_H
#define UTIL_H
#include <algorithm>
#include <cstring>
#include <stdexcept>
#include <string>
#include <string_view>
#include <type_traits>
#include <vector>
namespace util
{
namespace separators
{
constexpr char SPACE[] = " ";
constexpr char COLON[] = ":";
constexpr char SEMICOLON[] = ";";
constexpr char COMMA[] = ",";
}
/** @brief Trims a string view.
*
* @param the string view.
*/
inline void trim(std::string_view& view)
{
std::string_view spaces{ " \f\r\n\t\v" };
if (auto n = view.find_first_not_of(spaces); n != view.npos)
{
view.remove_prefix(n);
}
if (auto n = view.find_last_not_of(spaces); n != view.npos)
{
view.remove_suffix(view.size() - n - 1);
}
}
/** @brief Split a string view according to a delimiter.
*
* This function applies a custom callable to all substring of a string
* view generated by splitting it according to a delimiter.
*
* @tparam delim the delimiter to split the string view.
* @tparam Accumulate a callable to call on each substring.
* @param view the string view.
* @param the callable object.
*/
template<const char* delim, typename Accumulate>
void accumulate(std::string_view view, Accumulate acc)
{
size_t from{}, to;
std::string elem;
while ((to = view.find(delim, from)) != std::string_view::npos) {
auto sub = view.substr(from, to - from);
trim(sub);
acc(sub);
from = to + std::strlen(delim);
}
auto sub = view.substr(from);
if (not sub.empty())
{
trim(sub);
acc(sub);
}
}
/** @brief Split a string view according to a delimiter.
*
* Specialized version of `util::accumulate` collecting the split
* `std::string_view` in a `std::vector`.
*
* @tparam delim the delimiter to split the string view.
* @param view the string view.
*
* @see util::accumulate;
*/
template<const char* delim>
std::vector<std::string_view> split(std::string_view view)
{
std::vector<std::string_view> v;
auto callback = [&v](const std::string_view& s) { v.push_back(s); };
accumulate<delim>(view, callback);
return v;
}
/** @brief Discard element from stream by type.
*
* @tparam T the type of the element to discard.
* @param stream the input stream.
*
* @return the input stream.
*/
template<typename T, typename CharT, typename Traits>
std::basic_istream<CharT, Traits>& skip(std::basic_istream<CharT, Traits>& stream)
{
T discard;
return stream >> discard;
}
/** @brief Skip token in stream.
*
* @tparam keyword the token to skip.
* @param stream the input stream.
*
* @return the input stream.
*
* @note The token needs to be declared as a `const char[]`, but normally,
* string literals are `const char*`.
*
* ```cpp
* constexpr char RESULT[] = "Result:";
*
* int main(int argc, char* argv[])
* {
* int res;
* std::istringstream in{ "Result: 42"}
* in >> skip<RESULT> >> res;
*
* // ...
*
* return 0
* }
* ```
*/
template<const char* keyword, typename CharT, typename Traits>
std::basic_istream<CharT, Traits>& skip(std::basic_istream<CharT, Traits>& stream)
{
std::string word;
stream >> word;
if (word != keyword)
{
throw std::invalid_argument("Malformed input");
}
return stream;
}
/* @brief Compute the area of a planar simple polygon.
*
* @tparam Int integral coordinate type.
* @param first start of an iterator over pairs of 'Int'.
* @param last end of an iterator over pairs of 'Int'.
*
* @see https://en.wikipedia.org/wiki/Shoelace_formula#Triangle_formula
*/
template<typename Int, typename InputIt, typename = std::enable_if_t<std::is_integral_v<Int>,Int>>
Int shoelace(InputIt first, InputIt last)
{
Int result{};
auto [x1, y1] = *first;
while(first++ != last)
{
auto [x2, y2] = *first;
result += x1 * y2 - x2 * y1;
x1 = x2; y1 = y2;
}
return std::abs(result / 2);
}
/* @brief Return the number of integral coordinates inside a planar
* simple polygon.
*
* @tparam Int integral return type.
* @param area the area of the polygon.
* @param border the number of integral coordinates on the polygon's
* boundary.
*
* @see https://en.wikipedia.org/wiki/Pick%27s_theorem#Formula
*/
template<typename Int = int, typename = std::enable_if_t<std::is_integral_v<Int>,Int>>
Int pick(Int area, Int border)
{
return area - border / 2 + 1;
}
} // namespace util
#endif //UTIL_H
|