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.