#pragma once #include #include #include #include "util/for_each.hpp" namespace ztu { template struct prefixed_line_parser { const std::string_view prefix; F parse; }; template struct line_repeating_type {}; static constexpr auto is_repeating = line_repeating_type{}; static constexpr auto is_not_repeating = line_repeating_type{}; template prefixed_line_parser make_line_parser(std::string_view prefix, line_repeating_type, F&& f) { return { prefix, std::forward(f) }; } template E parse_lines(std::istream& in, const bool pedantic, prefixed_line_parser&&... parsers) { auto ec = E{}; std::string line; while (std::getline(in, line)) [[likely]] { parse_current_line: auto line_updated = false; for_each::argument( [&](prefixed_line_parser&& parser) -> bool { if (line.starts_with(parser.prefix)) { const auto prefix_length = parser.prefix.length(); ec = parser.parse(line.substr(prefix_length)); if constexpr (R) { while (std::getline(in, line)) { if (line.starts_with(parser.prefix)) [[likely]] { ec = parser.parse(line.substr(prefix_length)); } else [[unlikely]] { line_updated = true; break; } } } return true; } return false; }, std::forward>(parsers)... ); if (pedantic) { if (ec != E{}) [[unlikely]] { return ec; } } if (line_updated) { goto parse_current_line; } } return E{}; } }