diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d0dd64..64447e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,7 @@ file(MAKE_DIRECTORY ${PGNP_INCLUDE_DIR}) configure_file(src/PGN.hpp ${PGNP_INCLUDE_DIR}/pgnp.hpp COPYONLY) configure_file(src/HalfMove.hpp ${PGNP_INCLUDE_DIR} COPYONLY) configure_file(src/LargeFileStream.hpp ${PGNP_INCLUDE_DIR} COPYONLY) +configure_file(src/Types.hpp ${PGNP_INCLUDE_DIR} COPYONLY) include_directories(${PGNP_INCLUDE_DIR}) diff --git a/README.md b/README.md index c9f248b..a7c1f12 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,8 @@ PGN specification can be found [here](https://www.chessclub.com/help/PGN-spec). # Features - Basic PGN parsing (tags, move, comments, variations, NAG, etc.) - Merged PGN files parsing (several games in one file) -- Handle very large file (severals GB) -- Very efficient +- Handle very large file (max is 2^(sizeof(unsigned long long)) bytes) +- Efficiency # How to use it ? PGNP can be used as a shared library in your project. diff --git a/src/HalfMove.hpp b/src/HalfMove.hpp index 8edea93..9e90fda 100644 --- a/src/HalfMove.hpp +++ b/src/HalfMove.hpp @@ -1,3 +1,6 @@ +#pragma once + +#include "Types.hpp" #include #include #include @@ -35,11 +38,13 @@ public: std::string Dump(); /// @brief Perform a deep copy of a HalfMove void Copy(HalfMove *copy); - /// @brief Get HalfMove located x down the MainLine - HalfMove* GetHalfMoveAt(int); + /// @brief Get HalfMove located x down the MainLine + HalfMove *GetHalfMoveAt(int); }; struct HalfMoveOutOfRange : public std::exception { - const char *what() const throw() { return "HalfMove distance is out of range"; } + const char *what() const throw() { + return "HalfMove distance is out of range"; + } }; } // namespace pgnp \ No newline at end of file diff --git a/src/LargeFileStream.cpp b/src/LargeFileStream.cpp index 86e2dcf..95e7c1c 100644 --- a/src/LargeFileStream.cpp +++ b/src/LargeFileStream.cpp @@ -23,7 +23,7 @@ void LargeFileStream::ReadNextChunk() { last_read_size = file.gcount(); } -char LargeFileStream::operator[](long loc) { +char LargeFileStream::operator[](ull loc) { // Perform various checks if (eof) { throw ReadToFar(); @@ -42,11 +42,11 @@ char LargeFileStream::operator[](long loc) { } // Goto the right memory chuck - long loc_chunk_count = loc / BUFFER_SIZE; + ull loc_chunk_count = loc / BUFFER_SIZE; while (chuck_count < loc_chunk_count) { ReadNextChunk(); } - long offset = loc - (loc_chunk_count * BUFFER_SIZE); + ull offset = loc - (loc_chunk_count * BUFFER_SIZE); // Ensure for EOF if (!file && offset >= last_read_size) { diff --git a/src/LargeFileStream.hpp b/src/LargeFileStream.hpp index b80d8e4..64a7600 100644 --- a/src/LargeFileStream.hpp +++ b/src/LargeFileStream.hpp @@ -1,9 +1,12 @@ -#define BUFFER_SIZE (1024 * 1024 / 2) +#pragma once +#include "Types.hpp" #include #include #include +#define BUFFER_SIZE (1024 * 1024 / 2) + namespace pgnp { using namespace std; @@ -13,11 +16,11 @@ class LargeFileStream { /// @brief In memory buffer char buffer[BUFFER_SIZE]; /// @brief Number of chuck read minus 1 - long chuck_count; + ull chuck_count; /// @brief Number of byte read during the last file access - long last_read_size; + ull last_read_size; /// @brief Keep track of the file offset (to prevent backward read) - long last_loc; + ull last_loc; /// @brief Use a string as file content std::string content; /// @brief Use to shortcut some methods @@ -34,7 +37,7 @@ public: /// @brief Emulate file access with a string void FromString(std::string content); /// @brief Allow array like access to the file - char operator[](long loc); + char operator[](ull loc); /// @brief Check if we reach the EOF bool IsEOF(); diff --git a/src/PGN.cpp b/src/PGN.cpp index fe83cce..2deb78a 100644 --- a/src/PGN.cpp +++ b/src/PGN.cpp @@ -45,7 +45,7 @@ void PGN::ParseNextGame() { if (IS_EOF) { throw NoGameFound(); } - long loc = GotoNextToken(LastGameEndLoc); + ull loc = GotoNextToken(LastGameEndLoc); if (IS_EOF) { throw NoGameFound(); } @@ -103,7 +103,7 @@ bool PGN::HasTag(std::string key) { return (std::find(tags.begin(), tags.end(), key) != tags.end()); } -long PGN::ParseComment(long loc, HalfMove *hm) { +ull PGN::ParseComment(ull loc, HalfMove *hm) { // Goto next char loc = GotoNextToken(loc); EOF_CHECK(loc); @@ -131,7 +131,7 @@ long PGN::ParseComment(long loc, HalfMove *hm) { return (loc); } -long PGN::ParseHalfMove(long loc, HalfMove *hm) { +ull PGN::ParseHalfMove(ull loc, HalfMove *hm) { // Goto next char loc = GotoNextToken(loc); EOF_CHECK(loc); @@ -249,10 +249,10 @@ long PGN::ParseHalfMove(long loc, HalfMove *hm) { return (loc); } -long PGN::ParseNextTag(long start_loc) { +ull PGN::ParseNextTag(ull start_loc) { // Parse key std::string key; - long keyloc = start_loc + 1; + ull keyloc = start_loc + 1; EOF_CHECK(keyloc); char c = pgn_content[keyloc]; while (!IS_BLANK(c)) { @@ -264,7 +264,7 @@ long PGN::ParseNextTag(long start_loc) { // Parse value std::string value; - long valueloc = GotoNextToken(keyloc) + 1; + ull valueloc = GotoNextToken(keyloc) + 1; EOF_CHECK(keyloc); c = pgn_content[valueloc]; while (c != '"' or IS_EOF) { @@ -312,7 +312,7 @@ std::string PGN::Dump() { return (ss.str()); } -long PGN::GotoNextToken(long loc) { +ull PGN::GotoNextToken(ull loc) { char c = pgn_content[loc]; while (IS_BLANK(c)) { loc++; @@ -331,7 +331,7 @@ long PGN::GotoNextToken(long loc) { return (loc); } -long PGN::GotoEOL(long loc) { +ull PGN::GotoEOL(ull loc) { char c = pgn_content[loc]; while (true) { loc++; diff --git a/src/PGN.hpp b/src/PGN.hpp index 63493d0..0e29ae1 100644 --- a/src/PGN.hpp +++ b/src/PGN.hpp @@ -1,5 +1,8 @@ +#pragma once + #include "HalfMove.hpp" #include "LargeFileStream.hpp" +#include "Types.hpp" #include #include #include @@ -21,7 +24,7 @@ private: LargeFileStream pgn_content; /// @brief Contains the location of the end of the last parsed game (1 PGN /// file may have multiple games) - long LastGameEndLoc; + ull LastGameEndLoc; public: PGN(); @@ -52,16 +55,16 @@ public: private: /// @brief Populate @a tags with by parsing the one starting at location in /// argument - long ParseNextTag(long); + ull ParseNextTag(ull); /// @brief Parse a HalfMove at a specific location into @a pgn_content - long ParseHalfMove(long, HalfMove *); + ull ParseHalfMove(ull, HalfMove *); /// @brief Parse a consecutive sequence of comment - long ParseComment(long, HalfMove *); + ull ParseComment(ull, HalfMove *); /// @brief Get the next non-blank char location ignoring line comments ('%' /// and ';') - long GotoNextToken(long); + ull GotoNextToken(ull); /// @brief Goto the end of the current line - long GotoEOL(long); + ull GotoEOL(ull); }; struct UnexpectedEOF : public std::exception { @@ -82,7 +85,7 @@ struct NoGameFound : public std::exception { struct UnexpectedCharacter : public std::exception { std::string msg; - UnexpectedCharacter(char actual, char required, long loc) { + UnexpectedCharacter(char actual, char required, ull loc) { std::stringstream ss; ss << "Expected \'" << required << "\' at location " << loc << " but read \'" << actual << "\'"; diff --git a/src/Types.hpp b/src/Types.hpp new file mode 100644 index 0000000..88f17e1 --- /dev/null +++ b/src/Types.hpp @@ -0,0 +1,5 @@ +#pragma once + +namespace pgnp { +typedef unsigned long long ull; +} \ No newline at end of file