#include #include namespace { template [[gnu::pure]] inline T* gmemchr(T* ptr, char ch, size_t sz) noexcept { return (T*)memchr((void*)ptr, ch, sz * sizeof(T)); } template inline size_t gmemchr_s(T* ptr, char ch, size_t sz) noexcept { if(T* p = gmemchr(ptr, ch, sz)) return (size_t)(p - ptr); else return 0; } template requires(std::is_invocable_v) struct Defer { constexpr explicit Defer(std::nullptr_t) noexcept : f(nullptr) {} constexpr Defer(F&& func) noexcept(std::is_nothrow_move_constructible_v) : f(std::make_unique(std::move(func))) {} constexpr virtual ~Defer() noexcept(std::is_nothrow_invocable_v) { if(f) (*f)(); } constexpr Defer(Defer&& m) noexcept : f(std::move(m.f)) {} constexpr Defer(const Defer& p) noexcept requires(std::is_copy_constructible_v) : f(p.f ? *p.f : nullptr) {} constexpr Defer& operator=(Defer&& m) noexcept(std::is_nothrow_move_constructible_v) { if(this != std::addressof(m)) { f = std::move(m.f); } return *this; } constexpr Defer& operator=(const Defer& c) noexcept(std::is_nothrow_copy_constructible_v) requires(std::is_copy_constructible_v) { if(this != std::addressof(m)) { if(c.f) f = std::make_unique(*c.f); else f = nullptr; } return *this; } template constexpr decltype(auto) operator()(Args&&... args) noexcept(std::is_nothrow_invocable_v) requires(std::is_invocable_v) { return std::forward>( (*f)() ); } private: std::unique_ptr f; }; template requires(std::is_invocable_v) constexpr auto defer_call(F&& func) noexcept(std::is_nothrow_move_constructible_v) { return Defer{std::move(func)}; } #define $CAT_(a, b) a ## b #define $CAT(a, b) $CAT_(a, b) #define $DEFER(...) const auto $CAT(_$__defer_, __LINE__) = ::defer_call( __VA_ARGS__ ) } namespace Input { struct Parser::_impl { struct { const char* data; size_t len; } src; const char* cur_line; size_t cur_len; }; Parser::Parser(const char* string, size_t len) noexcept : state_(std::make_unique<_impl>()) { state_->cur_line = state_->src.data = string; state_->cur_len = state_->src.len = len; } Parser::~Parser() {} Parser::Parser(Parser&& p) noexcept : state_(std::move(p.state_)) {} Parser& Parser::operator=(Parser&& p) noexcept { if(this != std::addressof(p)) { state_ = std::move(p.state_); } return *this; } bool Parser::try_read_next(Output output) { const char* start = state_->cur_line; const char* end = gmemchr(start, '\n', state_->cur_len); if(!end) return false; size_t diff = (size_t)(end - state_->cur_line); if(diff > 1) { auto string = std::string_view{ start, gmemchr_s(start, ' ', diff - 1) }; for(size_t i=0; string.size() && string.data() < end; i++, string = std::string_view{ start += string.size(), // start = start + last size gmemchr_s(start, ' ', diff - 1) // XXX: <-- this should be `start + string.size()` }) { switch(i) { case 0: output->start = parse_point(string); break; // First point case 1: continue; // Arrow case 2: output->end = parse_point(string); break; // Second point case 3: continue; // Arrow default: goto le; // Next point, quit } } le: end = ((const char*)string.data()) + string.size(); state_->cur_len = (size_t)(end - state_->cur_line); // TODO: Is this the correct length calculation? I don't think it is.... state_->cur_line = end; return true; } else return false; } }