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
//
// cell_record implementation
//
//
void cell_record::renumber(id_type new_id, std::map<id_type, id_type> &idmap)
{
auto old_id = id_;
......@@ -79,26 +79,26 @@ std::ostream &operator<<(std::ostream &os, const cell_record &cell)
//
// Utility functions
//
//
bool starts_with(const std::string &str, const std::string &prefix)
{
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 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>
T parse_value_strict(std::istream &is)
T parse_value_strict(std::istream &is, const swc_parser &parser)
{
T val;
check_parse_status(is >> val);
check_parse_status(is >> val, parser);
// everything's fine
return val;
......@@ -106,10 +106,10 @@ T parse_value_strict(std::istream &is)
// specialize parsing for cell types
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;
check_parse_status(is >> val);
check_parse_status(is >> val, parser);
// Let cell_record's constructor check for the type validity
return static_cast<cell_record::kind>(val);
......@@ -117,13 +117,14 @@ cell_record::kind parse_value_strict(std::istream &is)
//
// swc_parser implementation
//
//
std::istream &swc_parser::parse_record(std::istream &is, cell_record &cell)
{
while (!is.eof() && !is.bad()) {
// consume empty and comment lines first
std::getline(is, linebuff_);
++lineno_;
if (!linebuff_.empty() && !starts_with(linebuff_, comment_prefix_))
break;
}
......@@ -140,23 +141,29 @@ std::istream &swc_parser::parse_record(std::istream &is, cell_record &cell)
}
if (is.fail()) {
throw swc_parse_error("too long line detected");
throw swc_parse_error("too long line detected", lineno_);
}
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;
}
cell_record swc_parser::parse_record(std::istringstream &is)
{
auto id = parse_value_strict<int>(is);
auto type = parse_value_strict<cell_record::kind>(is);
auto x = parse_value_strict<float>(is);
auto y = parse_value_strict<float>(is);
auto z = parse_value_strict<float>(is);
auto r = parse_value_strict<float>(is);
auto parent_id = parse_value_strict<cell_record::id_type>(is);
auto id = parse_value_strict<int>(is, *this);
auto type = parse_value_strict<cell_record::kind>(is, *this);
auto x = parse_value_strict<float>(is, *this);
auto y = parse_value_strict<float>(is, *this);
auto z = parse_value_strict<float>(is, *this);
auto r = parse_value_strict<float>(is, *this);
auto parent_id = parse_value_strict<cell_record::id_type>(is, *this);
// Convert to zero-based, leaving parent_id as-is if -1
if (parent_id != -1) {
......
......@@ -166,13 +166,23 @@ private:
class swc_parse_error : public std::runtime_error
{
public:
explicit swc_parse_error(const char *msg)
explicit swc_parse_error(const char *msg, std::size_t lineno)
: 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)
, lineno_(lineno)
{ }
std::size_t lineno() const
{
return lineno_;
}
private:
std::size_t lineno_;
};
class swc_parser
......@@ -182,13 +192,20 @@ public:
std::string comment_prefix)
: delim_(delim)
, comment_prefix_(comment_prefix)
, lineno_(0)
{ }
swc_parser()
: delim_(" ")
, comment_prefix_("#")
, lineno_(0)
{ }
std::size_t lineno() const
{
return lineno_;
}
std::istream &parse_record(std::istream &is, cell_record &cell);
private:
......@@ -198,6 +215,7 @@ private:
std::string delim_;
std::string comment_prefix_;
std::string linebuff_;
std::size_t lineno_;
};
......
......@@ -129,7 +129,7 @@ TEST(swc_parser, invalid_input)
std::istringstream is(
"1 10 14.566132 34.873772 7.857000 0.717830 -1\n");
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)
}
{
// Check iterator increments
std::stringstream is;
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 iend = get_cell_records<swc_io_raw>(is).end();
auto iend = get_cell_records<swc_io_raw>(is).end();
cell_record c;
EXPECT_NO_THROW(c = *iter++);
......@@ -355,4 +355,24 @@ TEST(cell_record_ranges, raw)
// Try to read past eof
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