25 #define BOOST_SPIRIT_DEBUG    36 #include <libcwd/buf2str.h>    52 void DatabaseSeekable::load(
void)
    54   if (!Glib::thread_supported())
    55     DoutFatal(dc::fatal, 
"DatabaseSeekable::load: Threading not initialized. Call Glib::init_thread() at the start of main().");
    56   M_file->read_async(sigc::mem_fun(
this,& DatabaseSeekable::read_async_open_ready), M_cancellable);
    59 void DatabaseSeekable::read_async_open_ready(Glib::RefPtr<Gio::AsyncResult>& result)
    61   M_file_input_stream = M_file->read_finish(result);
    62   M_buffer = 
new MemoryBlockList(sigc::mem_fun(*
this,& DatabaseSeekable::need_more_data));
    63   M_read_thread = Glib::Thread::create(sigc::mem_fun(*
this,& DatabaseSeekable::read_thread), 
false);
    64   M_new_block = MemoryBlockNode::create(S_buffer_size);
    66   GInputStream* stream = M_file_input_stream->InputStream::gobj();
    67   g_input_stream_read_async(stream, 
M_new_block->block_begin(), S_buffer_size,
    68       G_PRIORITY_DEFAULT, M_cancellable->gobj(),& DatabaseSeekable::read_async_ready, 
this);
    69   M_processing_finished.connect(sigc::mem_fun(*
this,& DatabaseSeekable::processing_finished));
    72 void DatabaseSeekable::need_more_data(
void)
    74   M_new_block = MemoryBlockNode::create(S_buffer_size);
    75   g_input_stream_read_async(M_file_input_stream->InputStream::gobj(), 
M_new_block->block_begin(), S_buffer_size,
    76       G_PRIORITY_DEFAULT, M_cancellable->gobj(),& DatabaseSeekable::read_async_ready, 
this);
    80 inline void DatabaseSeekable::read_async_ready(GObject* source_object, GAsyncResult* async_res)
    82   GInputStream* stream = M_file_input_stream->InputStream::gobj();
    84   gssize len = g_input_stream_read_finish(stream, async_res,& error);
    86     DoutFatal(dc::core, 
"read_finish() returned -1");
    90     Dout(dc::notice, 
"Appending a block with " << len << 
" bytes to the buffer.");
    97     Dout(dc::notice, 
"g_input_stream_read_finish() returned 0. Closing buffer.");
   106 void DatabaseSeekable::read_async_ready(GObject* source_object, GAsyncResult* async_res, gpointer user_data)
   109   database_seekable->read_async_ready(source_object, async_res);
   112 DatabaseSeekable::~DatabaseSeekable()
   121 timespec& operator-=(timespec& t1, timespec 
const& t2)
   123   t1.tv_sec -= t2.tv_sec;
   124   t1.tv_nsec -= t2.tv_nsec;
   128     t1.tv_nsec += 1000000000L;
   133 timespec& operator+=(timespec& t1, timespec 
const& t2)
   135   t1.tv_sec += t2.tv_sec;
   136   t1.tv_nsec += t2.tv_nsec;
   137   if (t1.tv_nsec > 999999999L)
   140     t1.tv_nsec -= 1000000000L;
   145 std::ostream& operator<<(std::ostream& os, timespec 
const& t1)
   147   return os << t1.tv_sec << 
'.' << std::setfill(
'0') << std::setw(9) << t1.tv_nsec;
   158 #define DEBUG_PARSER 0   161 template<
class ForwardIterator>
   169   ForwardIterator M_line_start;         
   171   ScannerData(ForwardIterator* iter) : M_iter(iter), M_line(1), M_column(0), M_number_of_characters(0), M_line_start(iter->buffer()) { }
   173   void init(ForwardIterator* iter)
   178     M_number_of_characters = 0;
   192 template<
class ForwardIterator>
   196     ForwardIterator 
const M_end;                        
   197     std::vector<ScannerData<ForwardIterator> > M_stack; 
   204     Scanner(ForwardIterator& iter, ForwardIterator 
const end) :
   206         M_current_position(&iter),
   208         M_end(end), M_stack_index(0)
   212         { M_current_position.init(&iter); }
   215     int push_position(
void)
   217       size_t size = M_stack.size();
   218       if (G_UNLIKELY(size <= M_stack_index))
   219         M_stack.push_back(M_current_position);
   221         M_stack[M_stack_index] = M_current_position;
   222       return M_stack_index++;
   225     void pop_position(
int index)
   227       M_current_position = M_stack[index];
   228       M_stack_index = index;
   236     void print_line(
void)
   238       std::string s(M_current_position.M_line_start,* M_current_position.
M_iter);
   239       Dout(dc::parser, 
"Parsed: \"" << buf2str(s.data(), s.length()) << 
"\".");
   252       if (G_UNLIKELY(*M_current_position.
M_iter == M_end))
   253         throw end_of_file_reached;
   256       M_current_position.M_line_start =* M_current_position.
M_iter;
   258       return** M_current_position.
M_iter;
   266       if (G_UNLIKELY(++*M_current_position.
M_iter == M_end))
   274       return** M_current_position.
M_iter;
   287         if (G_UNLIKELY(
is_eol(current_character)))
   288           eat_eol(current_character);
   290           current_character = next_character();
   295     void eat_line(
typename ForwardIterator::value_type& current_character)
   297       while (!
is_eol(current_character))
   298         current_character = next_character();
   302     bool parse_char(
typename ForwardIterator::value_type& current_character, 
char literal)
   304       current_character = next_character();
   305       if (current_character != literal)
   307       current_character = next_character();
   312     bool parse_str(
typename ForwardIterator::value_type& current_character, 
char const* literal)
   314       current_character = next_character();
   315       for (
char const* p = literal;* p; ++p)
   317         if (current_character !=* p)
   319         current_character = next_character();
   330     bool eat_comment(
typename ForwardIterator::value_type& current_character)
   337         if (current_character == 
'{')
   339           while (current_character != 
'}')
   340             current_character = next_character();
   341           current_character = next_character();
   345           eat_line(current_character);
   346           eat_eol(current_character);
   356       eat_white_space(current_character);
   357       while(eat_comment(current_character))
   358         eat_white_space(current_character);
   368     bool eat_eol(
typename ForwardIterator::value_type& current_character)
   371       assert(
is_eol(current_character));
   373       unsigned int line = M_current_position.
M_line + 1;
   376         ++M_current_position.
M_line;
   377         bool saw_carriage_return = (current_character == 
'\r');
   378         current_character = next_character();
   379         if (saw_carriage_return && current_character == 
'\n')
   380           current_character = next_character();
   381         if (current_character == 
'%')
   383           eat_line(current_character);
   387       while (
is_eol(current_character));
   390       M_current_position.M_line_start =* M_current_position.
M_iter;
   394       return M_current_position.
M_line > line;
   406         current_character = next_character();
   408       while(current_character != 
'"');
   410       current_character = next_character();
   414     unsigned int line(
void)
 const { 
return M_current_position.
M_line; }
   433     friend std::ostream& operator<<(std::ostream& os, Scanner<T> 
const& scanner);
   440 std::ostream& operator<<(std::ostream& os, Scanner<T> 
const& const_scanner)
   443   if (*scanner.M_current_position.M_iter == scanner.M_end)
   447     char c =** scanner.M_current_position.M_iter;
   452         os << libcwd::char2str(c);
   475 inline bool decode_tagname(
char& c, scanner_t& scanner)
   489 inline bool correct_string(
char& c, scanner_t& scanner)
   510 inline bool correct_tag_pair(
char& c, scanner_t& scanner)
   518   if (G_UNLIKELY(!decode_tagname(c, scanner)))
   521   if (G_UNLIKELY(!correct_string(c, scanner)))
   524   if (G_UNLIKELY(c != 
']'))
   531 inline bool tag_pair(
char& c, scanner_t& scanner)
   539   if (G_UNLIKELY(!decode_tagname(c, scanner)))
   548   if (G_UNLIKELY(c != 
'"'))
   552   if (G_UNLIKELY(c != 
']'))
   559 bool decode_movetext_section_white(
char& c, scanner_t& scanner) 
throw(
ParseError)
   564 bool decode_movetext_section_black(
char& c, scanner_t& scanner) 
throw(
ParseError)
   569 bool decode_movetext_section(
char& c, scanner_t& scanner)
   572     return decode_movetext_section_white(c, scanner);
   574     return decode_movetext_section_black(c, scanner);
   577 bool decode_game_termination(
char& c, scanner_t& scanner)
   581   if (d == 
'0' && c == 
'-')
   583   else if (d == 
'1' && c == 
'/')
   590 void DatabaseSeekable::read_thread(
void)
   592   Debug(debug::init_thread());
   593   Dout(dc::notice, 
"DatabaseSeekable::read_thread started.");
   595   timespec start_time_real, end_time_real;
   596   timespec start_time_process, end_time_process;
   597   timespec start_time_thread, end_time_thread;
   599   clock_gettime(CLOCK_REALTIME,& start_time_real);
   600   clock_gettime(CLOCK_PROCESS_CPUTIME_ID,& start_time_process);
   601   clock_gettime(CLOCK_THREAD_CPUTIME_ID,& start_time_thread);
   608     int PGN_movetext_section_start;
   610     bool saw_empty_line = 
true;                 
   613     char c = scanner.first_character();
   619       scanner.reset_game_state();
   629         scanner.eat_white_space(c);
   635             PGN_game_start = scanner.push_position();
   639             if ((saw_empty_line && tag_pair(c, scanner)) ||
   640                 (!saw_empty_line && correct_tag_pair(c, scanner)))
   643               Dout(dc::parser, 
"After first tag pair of PGN game: " << scanner.line() << 
':' << scanner.column());
   650           saw_empty_line = scanner.eat_eol(c);
   659         scanner.eat_white_space_and_comments(c);
   662           if (G_UNLIKELY(!tag_pair(c, scanner)))
   664           scanner.eat_white_space_and_comments(c);
   672           PGN_movetext_section_start = scanner.push_position();
   674         if (!decode_movetext_section(c, scanner))
   677           scanner.pop_position(PGN_movetext_section_start);
   681         if (decode_game_termination(c, scanner))
   684           scanner.eat_white_space_and_comments(c);
   688           saw_empty_line = 
true;
   693         Dout(dc::parser, 
"Parsing stopped at " << scanner.line() << 
':' << scanner.column() << 
" at \"" << scanner << 
"\".");
   707   clock_gettime(CLOCK_REALTIME,& end_time_real);
   708   clock_gettime(CLOCK_PROCESS_CPUTIME_ID,& end_time_process);
   709   clock_gettime(CLOCK_THREAD_CPUTIME_ID,& end_time_thread);
   711   end_time_real -= start_time_real;
   712   end_time_process -= start_time_process;
   713   end_time_thread -= start_time_thread;
   718     std::cout << 
"Failure to parse anything." << std::endl;
   721     std::cout << info.length << 
" characters have been parsed successfully." << std::endl;
   724   std::cout << 
"Number of characters: " << scanner.number_of_characters() << 
'\n';
   725   std::cout << 
"Number of lines: " << scanner.line() << 
'\n';
   727   std::cout << 
"Real time                                 : " << end_time_real << 
" seconds.\n";
   728   std::cout << 
"Process time                              : " << end_time_process << 
" seconds.\n";
   729   std::cout << 
"Run time read_thread                      : " << end_time_thread << 
" seconds.\n";
   731   double t = end_time_thread.tv_sec + end_time_thread.tv_nsec * 1e-9;
   732   std::cout << 
"Speed: " << (scanner.number_of_characters() / t / 1048576) << 
" MB/s." << std::endl;
   734   M_processing_finished.emit();
   737 void DatabaseSeekable::processing_finished(
void)
   742   M_slot_open_finished(M_bytes_read);
 This file contains the declaration of class PgnGrammar. 
unsigned int M_line
The current line number, starts at 1. 
A namespace for all chess related objects that are not related to the GUI. 
This file contains the declaration of class pgn::Database. 
Scanner(ForwardIterator& iter, ForwardIterator const end)
Construct a Scanner object. 
Glib::RefPtr< MemoryBlockNode > M_new_block
attr_t is_quote_or_eol(char c)
Test whether a character is a quote or EOL. 
attr_t is_tagname_begin(char c)
Test whether a character could be the first character of a tagname. 
ColorData const white
A constant representing the color white. 
ForwardIterator * M_iter
The current position. 
Character attribute definitions and arrays. 
bool eat_eol(typename ForwardIterator::value_type& current_character)
Eat one or more EOL sequences. 
Color M_to_move
The color that is too move at this point in the game. 
unsigned int number_of_characters(void) const 
Return the total number of characters parsed thus far. 
attr_t is_white_space(char c)
Test whether a character is white space. 
void eat_white_space(typename ForwardIterator::value_type& current_character)
Eat all white space character, return the first non-white-space. 
ForwardIterator::value_type first_character(void)
Return the first character. 
bool eat_comment(typename ForwardIterator::value_type& current_character)
Eat a single comment, if any. 
unsigned int M_column
The current column, starts at 0. 
bool parse_str(typename ForwardIterator::value_type& current_character, char const* literal)
Return true if the string after the current character matches literal. 
unsigned int M_number_of_characters
The number of characters before the current position. 
unsigned int column(void) const 
Return the column. 
Color to_move(void) const 
Return who is expected to move at this moment. 
void decode_string(typename ForwardIterator::value_type& current_character)
Decodes a string. 
This file contains the declaration of class Color. 
Variable data of a Scanner. 
unsigned int line(void) const 
Return the current line number. 
ForwardIterator::value_type next_character(void)
Make the next character the current character. 
attr_t is_comment_start(char c)
Test whether a character is a comment start. 
MemoryBlockList * M_buffer
Linked list of blocks with valid data. 
A color (black or white). 
void process_next_data_block(char const* data, size_t size)
Process next data block. 
A class used to read input from a PGN database. 
void eat_line(typename ForwardIterator::value_type& current_character)
Eat all characters left in the current line up till but not including the EOL. 
void eat_white_space_and_comments(typename ForwardIterator::value_type& current_character)
Eat all white space and all comments encountered, if any. 
attr_t is_eol(char c)
Test whether a character is an end-of-line character. 
attr_t is_tagname_continuation(char c)
Test whether a character could be part of a tagname. 
void reset_game_state(void)
Reset the game state. 
bool parse_char(typename ForwardIterator::value_type& current_character, char literal)
Parse the next character and return true if it equals literal. 
attr_t is_tag_separator_junk(char c)
Test whether a character could tag separator junk.