aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libutil/position.cc55
-rw-r--r--src/libutil/position.hh42
2 files changed, 73 insertions, 24 deletions
diff --git a/src/libutil/position.cc b/src/libutil/position.cc
index b39a5a1d4..724e560b7 100644
--- a/src/libutil/position.cc
+++ b/src/libutil/position.cc
@@ -29,32 +29,17 @@ std::optional<LinesOfCode> Pos::getCodeLines() const
return std::nullopt;
if (auto source = getSource()) {
-
- std::istringstream iss(*source);
- // count the newlines.
- int count = 0;
- std::string curLine;
- int pl = line - 1;
-
+ LinesIterator lines(*source), end;
LinesOfCode loc;
- do {
- std::getline(iss, curLine);
- ++count;
- if (count < pl)
- ;
- else if (count == pl) {
- loc.prevLineOfCode = curLine;
- } else if (count == pl + 1) {
- loc.errLineOfCode = curLine;
- } else if (count == pl + 2) {
- loc.nextLineOfCode = curLine;
- break;
- }
-
- if (!iss.good())
- break;
- } while (true);
+ if (line > 1)
+ std::advance(lines, line - 2);
+ if (lines != end && line > 1)
+ loc.prevLineOfCode = *lines++;
+ if (lines != end)
+ loc.errLineOfCode = *lines++;
+ if (lines != end)
+ loc.nextLineOfCode = *lines++;
return loc;
}
@@ -109,4 +94,26 @@ std::ostream & operator<<(std::ostream & str, const Pos & pos)
return str;
}
+void Pos::LinesIterator::bump(bool atFirst)
+{
+ if (!atFirst) {
+ pastEnd = input.empty();
+ if (!input.empty() && input[0] == '\r')
+ input.remove_prefix(1);
+ if (!input.empty() && input[0] == '\n')
+ input.remove_prefix(1);
+ }
+
+ // nix line endings are not only \n as eg std::getline assumes, but also
+ // \r\n **and \r alone**. not treating them all the same causes error
+ // reports to not match with line numbers as the parser expects them.
+ auto eol = input.find_first_of("\r\n");
+
+ if (eol > input.size())
+ eol = input.size();
+
+ curLine = input.substr(0, eol);
+ input.remove_prefix(eol);
+}
+
}
diff --git a/src/libutil/position.hh b/src/libutil/position.hh
index a184997ed..9bdf3b4b5 100644
--- a/src/libutil/position.hh
+++ b/src/libutil/position.hh
@@ -67,6 +67,48 @@ struct Pos
bool operator==(const Pos & rhs) const = default;
bool operator!=(const Pos & rhs) const = default;
bool operator<(const Pos & rhs) const;
+
+ struct LinesIterator {
+ using difference_type = size_t;
+ using value_type = std::string_view;
+ using reference = const std::string_view &;
+ using pointer = const std::string_view *;
+ using iterator_category = std::input_iterator_tag;
+
+ LinesIterator(): pastEnd(true) {}
+ explicit LinesIterator(std::string_view input): input(input), pastEnd(input.empty()) {
+ if (!pastEnd)
+ bump(true);
+ }
+
+ LinesIterator & operator++() {
+ bump(false);
+ return *this;
+ }
+ LinesIterator operator++(int) {
+ auto result = *this;
+ ++*this;
+ return result;
+ }
+
+ reference operator*() const { return curLine; }
+ pointer operator->() const { return &curLine; }
+
+ bool operator!=(const LinesIterator & other) const {
+ return !(*this == other);
+ }
+ bool operator==(const LinesIterator & other) const {
+ return (pastEnd && other.pastEnd)
+ || (std::forward_as_tuple(input.size(), input.data())
+ == std::forward_as_tuple(other.input.size(), other.input.data()));
+ }
+
+ private:
+ std::string_view input, curLine;
+ bool pastEnd = false;
+
+ void bump(bool atFirst);
+ };
};
std::ostream & operator<<(std::ostream & str, const Pos & pos);