#ifndef UTIL_H #define UTIL_H #include #include #include #include #include #include #include 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 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 std::vector split(std::string_view view) { std::vector v; auto callback = [&v](const std::string_view& s) { v.push_back(s); }; accumulate(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 std::basic_istream& skip(std::basic_istream& 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 >> res; * * // ... * * return 0 * } * ``` */ template std::basic_istream& skip(std::basic_istream& 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,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,Int>> Int pick(Int area, Int border) { return area - border / 2 + 1; } } // namespace util #endif //UTIL_H