From 0c8b825c3235dfe8e5c691c9846c950af47c55eb Mon Sep 17 00:00:00 2001 From: Pierre Dejoue Date: Thu, 10 Aug 2023 13:23:15 +0200 Subject: [PATCH] API change: Modify IO error handling --- outputs/invalid_input.txt | 2 +- outputs/validation.csv | 2 +- src/cli/src/main.cpp | 17 ++++---- src/gui/src/err_window.cpp | 6 +++ src/gui/src/err_window.h | 1 + src/gui/src/grid_window.cpp | 4 +- src/gui/src/picross_file.cpp | 4 +- src/picross/include/picross/picross_io.h | 15 +++++-- src/picross/src/picross_io.cpp | 55 ++++++++++++++++++------ src/utils/src/bitmap_io.cpp | 4 +- src/utils/src/picross_file_io.cpp | 16 +++---- src/utils/src/text_io.cpp | 8 ++-- 12 files changed, 88 insertions(+), 46 deletions(-) diff --git a/outputs/invalid_input.txt b/outputs/invalid_input.txt index 635fc02..7673dd7 100644 --- a/outputs/invalid_input.txt +++ b/outputs/invalid_input.txt @@ -1,4 +1,4 @@ -ERROR [invalid_input.txt]: Parsing error [Invalid token GRILL (parsing_state = COLUMN_SECTION)] on line 105: GRILL Beaf +PARSING_ERROR [invalid_input.txt]: [Invalid token GRILL (parsing_state = COLUMN_SECTION)] on line 105: GRILL Beaf GRID 1: Fishy Size: 22x20 Invalid grid. Error message: Number of filled tiles on rows (153) and columns (154) do not match diff --git a/outputs/validation.csv b/outputs/validation.csv index 090cbec..fadbfdf 100644 --- a/outputs/validation.csv +++ b/outputs/validation.csv @@ -1,5 +1,5 @@ File,Grid,Size,Valid,Difficulty,Solutions,Timing (ms),Misc,Linear reductions,Full reductions,Min depth,Max depth,Searched line alternatives -invalid_input.txt,,,ZERO,NOT_APPLICABLE,0,,"Parsing error [Invalid token GRILL (parsing_state = COLUMN_SECTION)] on line 105: GRILL Beaf" +invalid_input.txt,,,ZERO,NOT_APPLICABLE,0,,"PARSING_ERROR [Invalid token GRILL (parsing_state = COLUMN_SECTION)] on line 105: GRILL Beaf" invalid_input.txt,Fishy,22x20,ERR,NOT_APPLICABLE,0,,"Number of filled tiles on rows (153) and columns (154) do not match" invalid_input.txt,False note,10x0,ERR,NOT_APPLICABLE,0,,"Invalid height = 0" invalid_input.txt,Ill-formed,3x3,ERR,NOT_APPLICABLE,0,,"Height = 3 of the grid is too small for constraint: Constraint on a COL: [ 4 ]; min_line_size = 4" diff --git a/src/cli/src/main.cpp b/src/cli/src/main.cpp index bee789c..716cd20 100644 --- a/src/cli/src/main.cpp +++ b/src/cli/src/main.cpp @@ -216,15 +216,16 @@ int main(int argc, char *argv[]) ValidationModeData file_data; file_data.filename = stdutils::string::filename(filepath); - const picross::io::ErrorHandler err_handler_classic = [&return_status, &file_data](std::string_view msg, picross::io::ExitCode code) + const picross::io::ErrorHandler err_handler_classic = [&return_status, &file_data](picross::io::ErrorCodeT code, std::string_view msg) { - std::cout << (code == 0 ? "WARNING" : "ERROR" ) << " [" << file_data.filename << "]: " << msg << std::endl; - if (code != 0) - return_status = code; + std::cout << picross::io::str_error_code(code) << " [" << file_data.filename << "]: " << msg << std::endl; + return_status = code; }; - const picross::io::ErrorHandler err_handler_validation = [&file_data](std::string_view msg, picross::io::ExitCode code) + const picross::io::ErrorHandler err_handler_validation = [&file_data](picross::io::ErrorCodeT code, std::string_view msg) { - file_data.misc = msg.empty() ? std::to_string(code) : msg; + std::ostringstream oss; + oss << picross::io::str_error_code(code) << " " << msg; + file_data.misc = oss.str(); }; const auto format = [&args, &filepath]() -> picross::io::PicrossFileFormat { @@ -391,11 +392,11 @@ int main(int argc, char *argv[]) if (validation_mode) { grid_data.validation_result.validation_code = -1; // ERR - grid_data.misc = "EXCPT " + std::string(e.what()); + grid_data.misc = "EXCEPTION"; } else { - std::cout << "EXCPT [" << file_data.filename << "][" << input_grid.name() << "]: " << e.what() << std::endl; + std::cout << "EXCEPTION [" << file_data.filename << "][" << input_grid.name() << "]: " << e.what() << std::endl; return_status = 5; } } diff --git a/src/gui/src/err_window.cpp b/src/gui/src/err_window.cpp index 249e352..384c432 100644 --- a/src/gui/src/err_window.cpp +++ b/src/gui/src/err_window.cpp @@ -48,3 +48,9 @@ void ErrWindow::print(std::string_view msg) std::lock_guard lock(pImpl->text_buffer_lock); pImpl->text_buffer.appendf("%s\n", msg.data()); } + +void ErrWindow::print(std::string_view hdr, std::string_view msg) +{ + std::lock_guard lock(pImpl->text_buffer_lock); + pImpl->text_buffer.appendf("%s %s\n", hdr.data(), msg.data()); +} diff --git a/src/gui/src/err_window.h b/src/gui/src/err_window.h index c206db1..dc21d49 100644 --- a/src/gui/src/err_window.h +++ b/src/gui/src/err_window.h @@ -13,6 +13,7 @@ class ErrWindow void visit(bool& can_be_erased); void print(std::string_view msg); + void print(std::string_view hdr, std::string_view msg); private: struct Impl; diff --git a/src/gui/src/grid_window.cpp b/src/gui/src/grid_window.cpp index 655b85f..04bc90d 100644 --- a/src/gui/src/grid_window.cpp +++ b/src/gui/src/grid_window.cpp @@ -433,10 +433,10 @@ void GridWindow::save_grid() if (!file_path.empty()) { - const auto err_handler = [this](std::string_view msg, picross::io::ExitCode) + const auto err_handler = [this](picross::io::ErrorCodeT code, std::string_view msg) { std::lock_guard lock(this->text_buffer->mutex); - this->text_buffer->buffer.appendf("%s\n", msg); + this->text_buffer->buffer.appendf("%s %s\n", picross::io::str_error_code(code).c_str(), msg); }; const auto solution = (solutions.empty() || !solutions[0].is_completed()) ? std::nullopt : std::optional(solutions[0]); diff --git a/src/gui/src/picross_file.cpp b/src/gui/src/picross_file.cpp index ec722ab..2d677ba 100644 --- a/src/gui/src/picross_file.cpp +++ b/src/gui/src/picross_file.cpp @@ -23,9 +23,9 @@ void PicrossFile::visit_windows(bool& can_be_erased, Settings& settings) if (!is_file_open) { is_file_open = true; - const auto err_handler = [this](std::string_view msg, picross::io::ExitCode) + const auto err_handler = [this](picross::io::ErrorCodeT code, std::string_view msg) { - this->get_err_window().print(msg); + this->get_err_window().print(picross::io::str_error_code(code), msg); }; std::optional goal; std::vector grids_to_solve = picross::io::parse_picross_file(file_path, file_format, err_handler); diff --git a/src/picross/include/picross/picross_io.h b/src/picross/include/picross/picross_io.h index 28fb9d0..bb3c343 100644 --- a/src/picross/include/picross/picross_io.h +++ b/src/picross/include/picross/picross_io.h @@ -44,10 +44,19 @@ namespace io /* * IO error handling */ -using ExitCode = int; -inline constexpr ExitCode PARSER_ERROR = 1; +using ErrorCodeT = int; +struct ErrorCode +{ + // All codes != 0 + static constexpr ErrorCodeT PARSING_ERROR = 1; + static constexpr ErrorCodeT FILE_ERROR = 2; + static constexpr ErrorCodeT EXCEPTION = 3; + static constexpr ErrorCodeT WARNING = 4; +}; + +std::string str_error_code(ErrorCodeT code); -using ErrorHandler = std::function; +using ErrorHandler = std::function; /* * File parser, native file format diff --git a/src/picross/src/picross_io.cpp b/src/picross/src/picross_io.cpp index 5d07d54..81eca78 100644 --- a/src/picross/src/picross_io.cpp +++ b/src/picross/src/picross_io.cpp @@ -34,6 +34,31 @@ IOGrid::IOGrid(InputGrid&& input_grid, std::optional&& goal) noexcep namespace io { +std::string str_error_code(ErrorCodeT code) +{ + switch (code) + { + case ErrorCode::PARSING_ERROR: + return "PARSING_ERROR"; + + case ErrorCode::FILE_ERROR: + return "FILE_ERROR"; + + case ErrorCode::EXCEPTION: + return "EXCEPTION"; + + case ErrorCode::WARNING: + return "WARNING"; + + default: + { + std::ostringstream oss; + oss << "ERROR_CODE(" << code << ")"; + return oss.str(); + } + } +} + namespace { @@ -55,6 +80,8 @@ struct GridComponents std::optional m_goal; }; +using ParserErrorHandler = std::function; + template class FileParser; @@ -78,7 +105,7 @@ class FileParser { } - void parse_line(const std::string& line_to_parse, std::vector& grids, const ErrorHandler& error_handler) + void parse_line(const std::string& line_to_parse, std::vector& grids, const ParserErrorHandler& error_handler) { std::istringstream iss(line_to_parse); std::string token; @@ -175,11 +202,11 @@ class FileParser return "UNKNOWN"; } - void error_decorator(const ErrorHandler& error_handler, const std::string_view& msg) + void error_decorator(const ParserErrorHandler& error_handler, const std::string_view& msg) { std::ostringstream oss; oss << msg << " (parsing_state = " << parsing_state_str() << ")"; - error_handler(oss.str(), PARSER_ERROR); + error_handler(oss.str()); } private: ParsingState parsing_state; @@ -209,7 +236,7 @@ class FileParser { } - void parse_line(const std::string& line_to_parse, std::vector& grids, const ErrorHandler& error_handler) + void parse_line(const std::string& line_to_parse, std::vector& grids, const ParserErrorHandler& error_handler) { UNUSED(error_handler); @@ -286,11 +313,11 @@ class FileParser return "UNKNOWN"; } - void error_decorator(const ErrorHandler& error_handler, const std::string_view& msg) + void error_decorator(const ParserErrorHandler& error_handler, const std::string_view& msg) { std::ostringstream oss; oss << msg << " (parsing_state = " << parsing_state_str() << ")"; - error_handler(oss.str(), PARSER_ERROR); + error_handler(oss.str()); } private: ParsingState parsing_state; @@ -322,7 +349,7 @@ class FileParser } - void parse_line(const std::string& line_to_parse, std::vector& grids, const ErrorHandler& error_handler) + void parse_line(const std::string& line_to_parse, std::vector& grids, const ParserErrorHandler& error_handler) { std::istringstream iss(line_to_parse); std::string token; @@ -543,14 +570,14 @@ class FileParser return "UNKNOWN"; } - void error_decorator(const ErrorHandler& error_handler, std::string_view msg, std::string_view token = "") + void error_decorator(const ParserErrorHandler& error_handler, std::string_view msg, std::string_view token = "") { std::ostringstream oss; oss << msg << " (parsing_state = " << parsing_state_str(); if (!token.empty()) oss << "; token = " << token; oss << ")"; - error_handler(oss.str(), PARSER_ERROR); + error_handler(oss.str()); } private: ParsingState parsing_state; @@ -587,11 +614,11 @@ std::vector parse_input_file_generic(std::string_view filepath, const Er { line_nb++; std::string line = line_ss.str(); - parser.parse_line(line, grids, [line_nb, &line, &error_handler](std::string_view msg, ExitCode code) + parser.parse_line(line, grids, [line_nb, &line, &error_handler](std::string_view msg) { std::ostringstream oss; - oss << "Parsing error [" << msg << "] on line " << line_nb << ": " << line; - error_handler(oss.str(), code); + oss << "[" << msg << "] on line " << line_nb << ": " << line; + error_handler(ErrorCode::PARSING_ERROR, oss.str()); }); line_ss.str(""); } @@ -614,14 +641,14 @@ std::vector parse_input_file_generic(std::string_view filepath, const Er { std::ostringstream oss; oss << "Cannot open file " << filepath; - error_handler(oss.str(), 1); + error_handler(ErrorCode::FILE_ERROR, oss.str()); } } catch (std::exception& e) { std::ostringstream oss; oss << "Unhandled exception during file parsing: " << e.what(); - error_handler(oss.str(), 2); + error_handler(ErrorCode::EXCEPTION, oss.str()); } return result; diff --git a/src/utils/src/bitmap_io.cpp b/src/utils/src/bitmap_io.cpp index cc47371..0069a10 100644 --- a/src/utils/src/bitmap_io.cpp +++ b/src/utils/src/bitmap_io.cpp @@ -30,7 +30,7 @@ picross::OutputGrid import_bitmap_pbm(const std::string& filepath, const picross } catch(const std::exception& e) { - error_handler(e.what(), 0); + error_handler(picross::io::ErrorCode::EXCEPTION, e.what()); } return picross::OutputGrid(0, 0, picross::Tile::UNKNOWN, "Invalid"); } @@ -49,6 +49,6 @@ void export_bitmap_pbm(const std::string& filepath, const picross::OutputGrid& g } catch (const std::exception& e) { - error_handler(e.what(), 0); + error_handler(picross::io::ErrorCode::EXCEPTION, e.what()); } } diff --git a/src/utils/src/picross_file_io.cpp b/src/utils/src/picross_file_io.cpp index 727bb0f..0a6b06f 100644 --- a/src/utils/src/picross_file_io.cpp +++ b/src/utils/src/picross_file_io.cpp @@ -101,7 +101,7 @@ std::vector parse_picross_file(std::string_view filepath, PicrossFileFor } catch (const std::exception& e) { - error_handler(e.what(), 2); + error_handler(ErrorCode::EXCEPTION, e.what()); } return {}; } @@ -126,7 +126,7 @@ void save_picross_file(std::string_view filepath, PicrossFileFormat format, cons { std::ofstream out(filepath.data()); if (!out.good()) - error_handler("Error writing file " + std::string(filepath), 1); + error_handler(ErrorCode::FILE_ERROR, "Error writing file " + std::string(filepath)); picross::io::write_input_grid_native(out, io_grid); break; } @@ -135,7 +135,7 @@ void save_picross_file(std::string_view filepath, PicrossFileFormat format, cons { std::ofstream out(filepath.data()); if (!out.good()) - error_handler("Error writing file " + std::string(filepath), 1); + error_handler(ErrorCode::FILE_ERROR, "Error writing file " + std::string(filepath)); picross::io::write_input_grid_nin_format(out, io_grid); break; } @@ -144,7 +144,7 @@ void save_picross_file(std::string_view filepath, PicrossFileFormat format, cons { std::ofstream out(filepath.data()); if (!out.good()) - error_handler("Error writing file " + std::string(filepath), 1); + error_handler(ErrorCode::FILE_ERROR, "Error writing file " + std::string(filepath)); picross::io::write_input_grid_non_format(out, io_grid); break; } @@ -152,7 +152,7 @@ void save_picross_file(std::string_view filepath, PicrossFileFormat format, cons case PicrossFileFormat::PBM: { if (!io_grid.m_goal) - error_handler(goal_non_set_error_msg(filepath, format), 2); + error_handler(ErrorCode::WARNING, goal_non_set_error_msg(filepath, format)); export_bitmap_pbm(std::string(filepath), *io_grid.m_goal, error_handler); break; } @@ -160,10 +160,10 @@ void save_picross_file(std::string_view filepath, PicrossFileFormat format, cons case PicrossFileFormat::OutputGrid: { if (!io_grid.m_goal) - error_handler(goal_non_set_error_msg(filepath, format), 2); + error_handler(ErrorCode::WARNING, goal_non_set_error_msg(filepath, format)); std::ofstream out(filepath.data()); if (!out.good()) - error_handler("Error writing file " + std::string(filepath), 1); + error_handler(ErrorCode::FILE_ERROR, "Error writing file " + std::string(filepath)); out << *io_grid.m_goal; break; } @@ -175,7 +175,7 @@ void save_picross_file(std::string_view filepath, PicrossFileFormat format, cons } catch (const std::exception& e) { - error_handler(e.what(), 3); + error_handler(ErrorCode::EXCEPTION, e.what()); } } diff --git a/src/utils/src/text_io.cpp b/src/utils/src/text_io.cpp index db3344b..4a54a77 100644 --- a/src/utils/src/text_io.cpp +++ b/src/utils/src/text_io.cpp @@ -106,20 +106,18 @@ OutputGrid io::parse_output_grid_from_file(std::string_view filepath, const io:: { std::ostringstream oss; oss << "Cannot open file " << filepath; - error_handler(oss.str(), 1); + error_handler(ErrorCode::FILE_ERROR, oss.str()); } } catch (std::logic_error& l) { - std::ostringstream oss; - oss << "Parsing error: " << l.what(); - error_handler(oss.str(), 2); + error_handler(ErrorCode::PARSING_ERROR, l.what()); } catch (std::exception& e) { std::ostringstream oss; oss << "Unhandled exception during file parsing: " << e.what(); - error_handler(oss.str(), 3); + error_handler(ErrorCode::EXCEPTION, oss.str()); } return OutputGrid(0, 0, Tile::UNKNOWN, "Invalid"); }