Skip to content
Snippets Groups Projects
Commit b235ebbd authored by Vasileios Karakasis's avatar Vasileios Karakasis
Browse files

Added line context information to swc_parser.

Notable difference: parse_record() now throws only an swc_parse_error.
In case of an invalid_argument raised by the cell_record constructor,
this is caught and rethrown as a swc_parse_error with line information
attached.
parent 26a4ef29
No related branches found
No related tags found
No related merge requests found
...@@ -13,7 +13,7 @@ namespace io ...@@ -13,7 +13,7 @@ namespace io
// //
// cell_record implementation // cell_record implementation
// //
void cell_record::renumber(id_type new_id, std::map<id_type, id_type> &idmap) void cell_record::renumber(id_type new_id, std::map<id_type, id_type> &idmap)
{ {
auto old_id = id_; auto old_id = id_;
...@@ -79,26 +79,26 @@ std::ostream &operator<<(std::ostream &os, const cell_record &cell) ...@@ -79,26 +79,26 @@ std::ostream &operator<<(std::ostream &os, const cell_record &cell)
// //
// Utility functions // Utility functions
// //
bool starts_with(const std::string &str, const std::string &prefix) bool starts_with(const std::string &str, const std::string &prefix)
{ {
return (str.find(prefix) == 0); return (str.find(prefix) == 0);
} }
void check_parse_status(const std::istream &is) void check_parse_status(const std::istream &is, const swc_parser &parser)
{ {
if (is.fail()) { if (is.fail()) {
// If we try to read past the eof; fail bit will also be set // If we try to read past the eof; fail bit will also be set
throw swc_parse_error("could not parse value"); throw swc_parse_error("could not parse value", parser.lineno());
} }
} }
template<typename T> template<typename T>
T parse_value_strict(std::istream &is) T parse_value_strict(std::istream &is, const swc_parser &parser)
{ {
T val; T val;
check_parse_status(is >> val); check_parse_status(is >> val, parser);
// everything's fine // everything's fine
return val; return val;
...@@ -106,10 +106,10 @@ T parse_value_strict(std::istream &is) ...@@ -106,10 +106,10 @@ T parse_value_strict(std::istream &is)
// specialize parsing for cell types // specialize parsing for cell types
template<> template<>
cell_record::kind parse_value_strict(std::istream &is) cell_record::kind parse_value_strict(std::istream &is, const swc_parser &parser)
{ {
cell_record::id_type val; cell_record::id_type val;
check_parse_status(is >> val); check_parse_status(is >> val, parser);
// Let cell_record's constructor check for the type validity // Let cell_record's constructor check for the type validity
return static_cast<cell_record::kind>(val); return static_cast<cell_record::kind>(val);
...@@ -117,13 +117,14 @@ cell_record::kind parse_value_strict(std::istream &is) ...@@ -117,13 +117,14 @@ cell_record::kind parse_value_strict(std::istream &is)
// //
// swc_parser implementation // swc_parser implementation
// //
std::istream &swc_parser::parse_record(std::istream &is, cell_record &cell) std::istream &swc_parser::parse_record(std::istream &is, cell_record &cell)
{ {
while (!is.eof() && !is.bad()) { while (!is.eof() && !is.bad()) {
// consume empty and comment lines first // consume empty and comment lines first
std::getline(is, linebuff_); std::getline(is, linebuff_);
++lineno_;
if (!linebuff_.empty() && !starts_with(linebuff_, comment_prefix_)) if (!linebuff_.empty() && !starts_with(linebuff_, comment_prefix_))
break; break;
} }
...@@ -140,23 +141,29 @@ std::istream &swc_parser::parse_record(std::istream &is, cell_record &cell) ...@@ -140,23 +141,29 @@ std::istream &swc_parser::parse_record(std::istream &is, cell_record &cell)
} }
if (is.fail()) { if (is.fail()) {
throw swc_parse_error("too long line detected"); throw swc_parse_error("too long line detected", lineno_);
} }
std::istringstream line(linebuff_); std::istringstream line(linebuff_);
cell = parse_record(line); try {
cell = parse_record(line);
} catch (std::invalid_argument &e) {
// Rethrow as a parse error
throw swc_parse_error(e.what(), lineno_);
}
return is; return is;
} }
cell_record swc_parser::parse_record(std::istringstream &is) cell_record swc_parser::parse_record(std::istringstream &is)
{ {
auto id = parse_value_strict<int>(is); auto id = parse_value_strict<int>(is, *this);
auto type = parse_value_strict<cell_record::kind>(is); auto type = parse_value_strict<cell_record::kind>(is, *this);
auto x = parse_value_strict<float>(is); auto x = parse_value_strict<float>(is, *this);
auto y = parse_value_strict<float>(is); auto y = parse_value_strict<float>(is, *this);
auto z = parse_value_strict<float>(is); auto z = parse_value_strict<float>(is, *this);
auto r = parse_value_strict<float>(is); auto r = parse_value_strict<float>(is, *this);
auto parent_id = parse_value_strict<cell_record::id_type>(is); auto parent_id = parse_value_strict<cell_record::id_type>(is, *this);
// Convert to zero-based, leaving parent_id as-is if -1 // Convert to zero-based, leaving parent_id as-is if -1
if (parent_id != -1) { if (parent_id != -1) {
......
...@@ -166,13 +166,23 @@ private: ...@@ -166,13 +166,23 @@ private:
class swc_parse_error : public std::runtime_error class swc_parse_error : public std::runtime_error
{ {
public: public:
explicit swc_parse_error(const char *msg) explicit swc_parse_error(const char *msg, std::size_t lineno)
: std::runtime_error(msg) : std::runtime_error(msg)
, lineno_(lineno)
{ } { }
explicit swc_parse_error(const std::string &msg) explicit swc_parse_error(const std::string &msg, std::size_t lineno)
: std::runtime_error(msg) : std::runtime_error(msg)
, lineno_(lineno)
{ } { }
std::size_t lineno() const
{
return lineno_;
}
private:
std::size_t lineno_;
}; };
class swc_parser class swc_parser
...@@ -182,13 +192,20 @@ public: ...@@ -182,13 +192,20 @@ public:
std::string comment_prefix) std::string comment_prefix)
: delim_(delim) : delim_(delim)
, comment_prefix_(comment_prefix) , comment_prefix_(comment_prefix)
, lineno_(0)
{ } { }
swc_parser() swc_parser()
: delim_(" ") : delim_(" ")
, comment_prefix_("#") , comment_prefix_("#")
, lineno_(0)
{ } { }
std::size_t lineno() const
{
return lineno_;
}
std::istream &parse_record(std::istream &is, cell_record &cell); std::istream &parse_record(std::istream &is, cell_record &cell);
private: private:
...@@ -198,6 +215,7 @@ private: ...@@ -198,6 +215,7 @@ private:
std::string delim_; std::string delim_;
std::string comment_prefix_; std::string comment_prefix_;
std::string linebuff_; std::string linebuff_;
std::size_t lineno_;
}; };
......
...@@ -129,7 +129,7 @@ TEST(swc_parser, invalid_input) ...@@ -129,7 +129,7 @@ TEST(swc_parser, invalid_input)
std::istringstream is( std::istringstream is(
"1 10 14.566132 34.873772 7.857000 0.717830 -1\n"); "1 10 14.566132 34.873772 7.857000 0.717830 -1\n");
cell_record cell; cell_record cell;
EXPECT_THROW(is >> cell, std::invalid_argument); EXPECT_THROW(is >> cell, swc_parse_error);
} }
} }
...@@ -340,12 +340,12 @@ TEST(cell_record_ranges, raw) ...@@ -340,12 +340,12 @@ TEST(cell_record_ranges, raw)
} }
{ {
// Check iterator increments
std::stringstream is; std::stringstream is;
is << "1 1 14.566132 34.873772 7.857000 0.717830 -1\n"; is << "1 1 14.566132 34.873772 7.857000 0.717830 -1\n";
// Check postfix operator++
auto iter = get_cell_records<swc_io_raw>(is).begin(); auto iter = get_cell_records<swc_io_raw>(is).begin();
auto iend = get_cell_records<swc_io_raw>(is).end(); auto iend = get_cell_records<swc_io_raw>(is).end();
cell_record c; cell_record c;
EXPECT_NO_THROW(c = *iter++); EXPECT_NO_THROW(c = *iter++);
...@@ -355,4 +355,24 @@ TEST(cell_record_ranges, raw) ...@@ -355,4 +355,24 @@ TEST(cell_record_ranges, raw)
// Try to read past eof // Try to read past eof
EXPECT_THROW(*iter, std::out_of_range); EXPECT_THROW(*iter, std::out_of_range);
} }
{
// Check parse error context
std::stringstream is;
is << "1 1 14.566132 34.873772 7.857000 0.717830 -1\n";
is << "2 1 14.566132 34.873772 7.857000 0.717830 1\n";
is << "3 10 14.566132 34.873772 7.857000 0.717830 1\n";
is << "4 1 14.566132 34.873772 7.857000 0.717830 1\n";
std::vector<cell_record> cells;
try {
for (auto c : get_cell_records<swc_io_raw>(is)) {
cells.push_back(c);
}
FAIL() << "expected an exception";
} catch (const swc_parse_error &e) {
EXPECT_EQ(3u, e.lineno());
}
}
} }
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment