126 lines
3.1 KiB
C++
126 lines
3.1 KiB
C++
#pragma once
|
|
|
|
#include "util.hpp"
|
|
|
|
namespace iguana {
|
|
// return true when it==end
|
|
template <typename It>
|
|
IGUANA_INLINE bool skip_space_till_end(It &&it, It &&end) {
|
|
while (it != end && (static_cast<uint8_t>(*it) < 33)) ++it;
|
|
return it == end;
|
|
}
|
|
|
|
// will not skip '\n'
|
|
template <typename It>
|
|
IGUANA_INLINE auto skip_till_newline(It &&it, It &&end) {
|
|
if (it == end)
|
|
IGUANA_UNLIKELY { return it; }
|
|
std::decay_t<decltype(it)> res = it;
|
|
while ((it != end) && (*it != '\n')) {
|
|
if (*it == ' ')
|
|
IGUANA_UNLIKELY {
|
|
res = it;
|
|
while (it != end && *it == ' ') ++it;
|
|
}
|
|
else if (*it == '#')
|
|
IGUANA_UNLIKELY {
|
|
if (*(it - 1) == ' ') {
|
|
// it - 1 should be legal because this func is for parse value
|
|
while ((it != end) && *it != '\n') {
|
|
++it;
|
|
}
|
|
return res;
|
|
}
|
|
else {
|
|
++it;
|
|
}
|
|
}
|
|
else
|
|
IGUANA_LIKELY { ++it; }
|
|
}
|
|
return (*(it - 1) == ' ') ? res : it;
|
|
}
|
|
|
|
template <char... C, typename It>
|
|
IGUANA_INLINE auto skip_till(It &&it, It &&end) {
|
|
if (it == end)
|
|
IGUANA_UNLIKELY { return it; }
|
|
std::decay_t<decltype(it)> res = it;
|
|
while ((it != end) && (!((... || (*it == C))))) {
|
|
if (*it == '\n')
|
|
IGUANA_UNLIKELY { throw std::runtime_error("\\n is not expected"); }
|
|
else if (*it == ' ')
|
|
IGUANA_UNLIKELY {
|
|
res = it;
|
|
while (it != end && *it == ' ') ++it;
|
|
}
|
|
else if (*it == '#')
|
|
IGUANA_UNLIKELY {
|
|
if (*(it - 1) == ' ')
|
|
IGUANA_UNLIKELY {
|
|
// it - 1 may be illegal
|
|
while ((it != end) && *it != '\n') {
|
|
++it;
|
|
}
|
|
return res;
|
|
}
|
|
}
|
|
else
|
|
IGUANA_LIKELY { ++it; }
|
|
}
|
|
|
|
if (it == end)
|
|
IGUANA_UNLIKELY {
|
|
static constexpr char b[] = {C..., '\0'};
|
|
std::string error = std::string("Expected one of these: ").append(b);
|
|
throw std::runtime_error(error);
|
|
}
|
|
++it; // skip
|
|
return (*(it - 2) == ' ') ? res : it - 1;
|
|
}
|
|
|
|
// If there are '\n' , return indentation
|
|
// If not, return minspaces + space
|
|
// If Throw == true, check res < minspaces
|
|
template <bool Throw = true, typename It>
|
|
IGUANA_INLINE size_t skip_space_and_lines(It &&it, It &&end, size_t minspaces) {
|
|
size_t res = minspaces;
|
|
while (it != end) {
|
|
if (*it == '\n') {
|
|
++it;
|
|
res = 0;
|
|
auto start = it;
|
|
// skip the --- line
|
|
if ((it != end) && (*it == '-'))
|
|
IGUANA_UNLIKELY {
|
|
auto line_end = skip_till<false, '\n'>(it, end);
|
|
auto line = std::string_view(
|
|
&*start, static_cast<size_t>(std::distance(start, line_end)));
|
|
if (line != "---") {
|
|
it = start;
|
|
}
|
|
}
|
|
}
|
|
else if (*it == ' ' || *it == '\t') {
|
|
++it;
|
|
++res;
|
|
}
|
|
else if (*it == '#') {
|
|
while (it != end && *it != '\n') {
|
|
++it;
|
|
}
|
|
res = 0;
|
|
}
|
|
else {
|
|
if constexpr (Throw) {
|
|
if (res < minspaces)
|
|
IGUANA_UNLIKELY { throw std::runtime_error("Indentation problem"); }
|
|
}
|
|
return res;
|
|
}
|
|
}
|
|
return res; // throw in certain situations ?
|
|
}
|
|
|
|
} // namespace iguana
|