diff --git a/src/swcio.cpp b/src/swcio.cpp index 32724fe8f38685a593c6d82cdbf27448c26a325a..28e189a6f5a19df31c9ee961ffe0fe79be1a7676 100644 --- a/src/swcio.cpp +++ b/src/swcio.cpp @@ -174,9 +174,8 @@ cell_record swc_parser::parse_record(std::istringstream &is) } -std::vector<cell_record> swc_read_cells(std::istream &is) +cell_record_range_clean::cell_record_range_clean(std::istream &is) { - std::vector<cell_record> cells; std::unordered_set<cell_record::id_type> ids; std::size_t num_trees = 0; @@ -184,40 +183,38 @@ std::vector<cell_record> swc_read_cells(std::istream &is) bool needsort = false; cell_record curr_cell; - while ( !(is >> curr_cell).eof()) { - if (curr_cell.parent() == -1 && ++num_trees > 1) { + for (auto c : swc_get_records<swc_io_raw>(is)) { + if (c.parent() == -1 && ++num_trees > 1) { // only a single tree is allowed break; } - auto inserted = ids.insert(curr_cell.id()); + auto inserted = ids.insert(c.id()); if (inserted.second) { // not a duplicate; insert cell - cells.push_back(curr_cell); - if (!needsort && curr_cell.id() < last_id) { + cells_.push_back(c); + if (!needsort && c.id() < last_id) { needsort = true; } - last_id = curr_cell.id(); + last_id = c.id(); } } if (needsort) { - std::sort(cells.begin(), cells.end()); + std::sort(cells_.begin(), cells_.end()); } // Renumber cells if necessary std::map<cell_record::id_type, cell_record::id_type> idmap; cell_record::id_type next_id = 0; - for (auto &c : cells) { + for (auto &c : cells_) { if (c.id() != next_id) { c.renumber(next_id, idmap); } ++next_id; } - - return std::move(cells); } } // end of nestmc::io diff --git a/src/swcio.hpp b/src/swcio.hpp index 5365c8a5b508f6102e06c08d780cd94a64aeae0b..e267c184b4e462b2015fb8c38866e2133d60b8b1 100644 --- a/src/swcio.hpp +++ b/src/swcio.hpp @@ -221,16 +221,6 @@ private: std::istream &operator>>(std::istream &is, cell_record &cell); -// -// Reads cells from an input stream until an eof is encountered and returns a -// cleaned sequence of cell records. -// -// For more information check here: -// https://github.com/eth-cscs/cell_algorithms/wiki/SWC-file-parsing -// -std::vector<cell_record> swc_read_cells(std::istream &is); - - class cell_record_stream_iterator : public std::iterator<std::forward_iterator_tag, cell_record> { @@ -355,8 +345,42 @@ private: std::istream &is_; }; +// +// Reads cells from an input stream until an eof is encountered and returns a +// cleaned sequence of cell records. +// +// For more information check here: +// https://github.com/eth-cscs/cell_algorithms/wiki/SWC-file-parsing +// + class cell_record_range_clean { +public: + using value_type = cell_record; + using reference = value_type &; + using const_referene = const value_type &; + using iterator = std::vector<cell_record>::iterator; + using const_iterator = std::vector<cell_record>::const_iterator; + + cell_record_range_clean(std::istream &is); + + iterator begin() + { + return cells_.begin(); + } + + iterator end() + { + return cells_.end(); + } + + std::size_t size() + { + return cells_.size(); + } + +private: + std::vector<cell_record> cells_; }; struct swc_io_raw @@ -366,11 +390,11 @@ struct swc_io_raw struct swc_io_clean { - using cell_range_type = cell_record_range_raw; + using cell_range_type = cell_record_range_clean; }; template<typename T = swc_io_clean> - typename T::cell_range_type get_cell_records(std::istream &is) + typename T::cell_range_type swc_get_records(std::istream &is) { return typename T::cell_range_type(is); } diff --git a/tests/test_swcio.cpp b/tests/test_swcio.cpp index c7b282af14e26a4001216ed3cdf322c0a6bd5d09..7ecd5fc013d98e66428d7a85cb658360e4ca6f2d 100644 --- a/tests/test_swcio.cpp +++ b/tests/test_swcio.cpp @@ -186,16 +186,12 @@ TEST(swc_parser, valid_input) swc_input << c << "\n"; swc_input << "# this is a final comment\n"; - try { - std::size_t nr_records = 0; - cell_record cell; - while ( !(swc_input >> cell).eof()) { - ASSERT_LT(nr_records, cells_orig.size()); - expect_cell_equals(cells_orig[nr_records], cell); - ++nr_records; - } - } catch (std::exception &e) { - ADD_FAILURE() << "unexpected exception thrown\n"; + + std::size_t nr_records = 0; + for (auto cell : swc_get_records<swc_io_raw>(swc_input)) { + ASSERT_LT(nr_records, cells_orig.size()); + expect_cell_equals(cells_orig[nr_records], cell); + ++nr_records; } } } @@ -213,8 +209,7 @@ TEST(swc_parser, from_allen_db) // load the cell records into a std::vector std::vector<io::cell_record> nodes; - io::cell_record node; - while( !(fid >> node).eof()) { + for (auto node : io::swc_get_records<io::swc_io_raw>(fid)) { nodes.push_back(std::move(node)); } @@ -234,8 +229,7 @@ TEST(swc_parser, input_cleaning) is << "2 1 14.566132 34.873772 7.857000 0.717830 1\n"; is << "2 1 14.566132 34.873772 7.857000 0.717830 1\n"; - auto cells = swc_read_cells(is); - EXPECT_EQ(2u, cells.size()); + EXPECT_EQ(2u, swc_get_records(is).size()); } { @@ -246,7 +240,7 @@ TEST(swc_parser, input_cleaning) is << "3 1 14.566132 34.873772 7.857000 0.717830 -1\n"; is << "4 1 14.566132 34.873772 7.857000 0.717830 1\n"; - auto cells = swc_read_cells(is); + auto cells = swc_get_records(is); EXPECT_EQ(2u, cells.size()); } @@ -259,14 +253,15 @@ TEST(swc_parser, input_cleaning) is << "1 1 14.566132 34.873772 7.857000 0.717830 -1\n"; std::array<cell_record::id_type, 4> expected_id_list = {{ 0, 1, 2, 3 }}; - auto cells = swc_read_cells(is); - ASSERT_EQ(4u, cells.size()); auto expected_id = expected_id_list.cbegin(); - for (const auto &c : cells) { + for (auto c : swc_get_records(is)) { EXPECT_EQ(*expected_id, c.id()); ++expected_id; } + + // Check that we have read through the whole input + EXPECT_EQ(expected_id_list.end(), expected_id); } { @@ -279,21 +274,23 @@ TEST(swc_parser, input_cleaning) is << "51 1 14.566132 34.873772 7.857000 0.717830 1\n"; is << "61 1 14.566132 34.873772 7.857000 0.717830 51\n"; - auto cells = swc_read_cells(is); std::array<cell_record::id_type, 6> expected_id_list = {{ 0, 1, 2, 3, 4, 5 }}; std::array<cell_record::id_type, 6> expected_parent_list = {{ -1, 0, 1, 1, 0, 4 }}; - ASSERT_EQ(6u, cells.size()); auto expected_id = expected_id_list.cbegin(); auto expected_parent = expected_parent_list.cbegin(); - for (const auto &c : cells) { + for (auto c : swc_get_records(is)) { EXPECT_EQ(*expected_id, c.id()); EXPECT_EQ(*expected_parent, c.parent()); ++expected_id; ++expected_parent; } + + // Check that we have read through the whole input + EXPECT_EQ(expected_id_list.end(), expected_id); + EXPECT_EQ(expected_parent_list.end(), expected_parent); } } @@ -310,7 +307,7 @@ TEST(cell_record_ranges, raw) is << "4 1 14.566132 34.873772 7.857000 0.717830 1\n"; std::vector<cell_record> cells; - for (auto c : get_cell_records<swc_io_raw>(is)) { + for (auto c : swc_get_records<swc_io_raw>(is)) { cells.push_back(c); } @@ -318,8 +315,8 @@ TEST(cell_record_ranges, raw) bool entered = false; auto citer = cells.begin(); - for (auto c : get_cell_records<swc_io_raw>(is)) { - EXPECT_TRUE(c.strict_equals(*citer++)); + for (auto c : swc_get_records<swc_io_raw>(is)) { + expect_cell_equals(c, *citer++); entered = true; } @@ -331,7 +328,7 @@ TEST(cell_record_ranges, raw) std::stringstream is; is << "1 1 14.566132 34.873772 7.857000 0.717830 -1\n"; - auto ibegin = get_cell_records<swc_io_raw>(is).begin(); + auto ibegin = swc_get_records<swc_io_raw>(is).begin(); EXPECT_NO_THROW(++ibegin); EXPECT_THROW(*ibegin, std::out_of_range); @@ -343,8 +340,8 @@ TEST(cell_record_ranges, raw) std::stringstream is; is << "1 1 14.566132 34.873772 7.857000 0.717830 -1\n"; - auto iter = get_cell_records<swc_io_raw>(is).begin(); - auto iend = get_cell_records<swc_io_raw>(is).end(); + auto iter = swc_get_records<swc_io_raw>(is).begin(); + auto iend = swc_get_records<swc_io_raw>(is).end(); cell_record c; EXPECT_NO_THROW(c = *iter++); @@ -365,11 +362,11 @@ TEST(cell_record_ranges, raw) std::vector<cell_record> cells; try { - for (auto c : get_cell_records<swc_io_raw>(is)) { + for (auto c : swc_get_records<swc_io_raw>(is)) { cells.push_back(c); } - FAIL() << "expected an exception"; + ADD_FAILURE() << "expected an exception\n"; } catch (const swc_parse_error &e) { EXPECT_EQ(3u, e.lineno()); }