53     return (elem == 0) ? 0x27ffb80800000000 : 0x47fffffe87ffffff;
    93     return high > 1 ? false : tok_map[high] & (1ULL << low);
   101 inline bool is_PGNdigit(
unsigned char ch) { 
return ch >= 
'0' && ch <= 
'9'; }
   110     return (ch == 
' ' || ch == 
'\n' || ch == 
'\r' || ch == 
'\t' || ch == 
'\v');
   128     auto n_chars = std::distance(tok.first, tok.second);
   130         if (std::equal(tok.first, tok.first + 3, 
"1-0"))
   132         if (std::equal(tok.first, tok.first + 3, 
"0-1"))
   134         if (std::equal(tok.first, tok.first + 3, 
"1/2"))
   136         if (std::equal(tok.first, tok.first + 3, 
"1:0"))
   138         if (std::equal(tok.first, tok.first + 3, 
"0:1"))
   140     } 
else if (n_chars == 7) {
   141         if (std::equal(tok.first, tok.first + 7, 
"1/2-1/2") ||
   142             std::equal(tok.first, tok.first + 7, 
"1/2:1/2"))
   157 template <
typename TInput, 
typename TVisitor>
   167         return parser.visitPGN_EndOfLine();
   179         return parser.visitPGN_ResultFinal(
'*');
   182         return parser.visitPGN_VariationStart();
   185         return parser.visitPGN_VariationEnd();
   190             auto skip_spaces = [&]() {
   192                 while (spaces.first != spaces.second) {
   193                     if (*spaces.first++ == 
'\n')
   194                         parser.visitPGN_EndOfLine();
   201             auto value = input.read_until(
']');
   205             if (value.first != value.second && *value.first == 
'"') {
   206                 auto is_terminated = [&]() {
   207                     for (
auto it = value.first; it != value.second; ++it) {
   210                         if (*it == 
'\\' && ++it == value.second)
   216                 while (!input.last_column() && !is_terminated()) {
   217                     value.second = input.read_until(
']').second;
   221             while (value.first != value.second) {
   222                 auto last_ch = *--value.second;
   223                 if (last_ch == 
'"') {
   231                     parser.visitPGN_EndOfLine();
   233             return parser.visitPGN_TagPair(tag, value);
   236         parser.visitPGN_inputUnexpectedPGNHeader();
   240         return parser.visitPGN_Comment(input.read_until(
'}'));
   243         return parser.visitPGN_Comment(input.read_line());
   246         if (input.first_column()) {
   247             return parser.visitPGN_Escape(input.read_line());
   249         return parser.visitPGN_Unknown(
   250             input.read_token([](
char c) { return c == 
'%'; }));
   253         return parser.visitPGN_NAG(input.read_token(
is_PGNdigit));
   257         return parser.visitPGN_Suffix(
   258             input.read_token([](
char c) { return c == 
'!' || c == 
'?'; }));
   264     bool epd = (section < 0 && std::count(tok.first, tok.second, 
'/') == 7);
   268         tok.second = input.read_line().second;
   269         parser.visitPGN_EPD(tok);
   273     auto notdigit = std::find_if_not(tok.first, tok.second, 
is_PGNdigit);
   274     if (notdigit == tok.first)
   275         return parser.visitPGN_SANMove(tok);
   277     if (notdigit == tok.second)
   278         return parser.visitPGN_MoveNum(tok);
   281         return parser.visitPGN_ResultFinal(result);
   283     return parser.visitPGN_Unknown(tok);
   287     const char* 
const begin_;
   288     const char* 
const end_;
   293         : begin_(begin), end_(end), it_(begin) {}
   303         assert(it_ != begin_ && it_ != end_);
   308     bool eof()
 const { 
return it_ == end_; };
   311     std::size_t 
n_read()
 const { 
return std::distance(begin_, it_); }
   334         auto second = (it_ == end_) ? it_ : it_++;
   335         return {first, second};
   339     template <
typename Cond>
   342         it_ = std::find_if_not(it_, end_, cond);
   348     template <
typename Cond>
   350         assert(it_ != begin_);
   351         auto first = it_ - 1;
   352         it_ = std::find_if_not(it_, end_, cond);
   370 template <
typename TVisitor>
   377                 parser.visitPGN_inputEOF();
   382     return {input.
n_read(), section >= 0};
   401 template <
bool unescape = false, 
typename TString>
   403     std::size_t n_newlines = 0;
   404     for (std::size_t i = pos, n = str.size(); i < n; ++i) {
   405         unsigned char ch = str[i];
   408             unsigned char nxt = (i + 1 != n) ? str[i + 1] : 0;
   409             if (nxt < 0x80 || nxt > 0xBF) {
   410                 str[i] = 
static_cast<unsigned char>(ch & 0xBF);
   411                 str.insert(str.begin() + i, 
static_cast<unsigned char>(0xC3));
   415         } 
else if (ch == 
'\n' || ch == 
'\r' || ch == 
'\t' || ch == 
'\v') {
   432         } 
else if (unescape && ch == 
'\\' && i + 1 != n) {
   436             if (str[i + 1] == 
'\\' || str[i + 1] == 
'"') {
   453 template <
typename TString> 
void escape_string(TString& str, std::size_t pos) {
   454     auto it = str.begin() + pos;
   456         it = std::find_if(it, str.end(),
   457                           [](
char ch) { 
return ch == 
'\\' || ch == 
'\"'; });
   459             it = str.insert(it, 
'\\') + 2;
   470 template <
typename TView> std::size_t 
trim(TView& str) {
   471     std::size_t n_newlines = 0;
   472     auto is_space = [&n_newlines](
char ch) {
   475         } 
else if (ch != 
' ' && ch != 
'\r' && ch != 
'\t' && ch != 
'\v') {
   480     str.first = std::find_if_not(str.first, str.second, is_space);
   482     using RevIt = std::reverse_iterator<decltype(str.first)>;
   484         std::find_if_not(RevIt(str.second), RevIt(str.first), is_space).base();
   491 #endif // _PGN_LEXER_H 
std::pair< std::size_t, bool > parse_game(pgn_impl::InputMemory input, TVisitor &&parser)
Read a PGN game from memory, grouping characters in tokens and dispatching them to a PGN parser...
char is_PGNtermination(TView tok)
Checks if a token is the game termination marker. 
int find(const char *filename)
find() - search for a database. 
bool is_PGNdigit(unsigned char ch)
Checks if the given character is one of the 10 decimal digits: 0123456789. 
bool is_PGNsymbol(unsigned char ch)
Checks if the given character is a PGN symbol. 
std::size_t trim(TView &str)
Trim leading and trailing white spaces. 
bool is_PGNwhitespace(unsigned char ch)
Checks if the given character is a white space ("white space characters include space, newline, and tab characters"). 
void escape_string(TString &str, std::size_t pos)
Escape quote and backslash chars according to the PGN standard: "A quote inside a string is represent...
constexpr unsigned long long init_symbol_map(unsigned elem)
Creates a 128 bits bitmap of PGN symbol characters. 
std::size_t normalize(TString &str, std::size_t pos)
Normalize white spaces and converts Latin-1 chars to UTF-8 sequences. 
bool parse_token(char ch, TInput &input, TVisitor &parser, int §ion)
Read a token and dispatch it to a PGN parser.