11#include <system_error>
16# include <absl/container/node_hash_map.h>
18# include <unordered_map>
28 size_t operator()(
const std::filesystem::path& path)
const noexcept {
return std::filesystem::hash_value(path); }
36using PathMap = absl::node_hash_map<std::filesystem::path, V, PathHash>;
39using PathMap = std::unordered_map<std::filesystem::path, V, PathHash>;
49 if (buf_.starts_with(utf8::Bom)) bom_ = (uint32_t)utf8::Bom.size();
50 rows_.emplace_back(0);
51 for (uint32_t i = 0, e = (uint32_t)buf_.size(); i != e; ++i)
52 if (buf_[i] ==
'\n') rows_.emplace_back(i + 1);
57 const std::filesystem::path&
path()
const {
return path_; }
58 std::string_view
buf()
const {
return buf_; }
61 uint32_t
num_rows()
const {
return (uint32_t)rows_.size() - phantom_(); }
63 Pos end()
const {
return Pos((uint32_t)buf_.size()); }
72 std::pair<uint32_t, uint32_t>
rowcol(
Pos pos)
const {
74 auto row = (uint32_t)(std::ranges::upper_bound(rows_, pos.
off) - rows_.begin());
89 std::string_view
line(uint32_t
row)
const {
92 auto end =
row == rows_.size() ? (uint32_t)buf_.size() : rows_[
row] - 1;
99 auto end = std::min<size_t>(pos.
off, buf_.size());
100 if (
end == 0)
return Pos(0);
110 return Pos((uint32_t)(j ==
end ? i :
end - 1));
118 uint32_t phantom_()
const {
return rows_.size() > 1 && rows_.back() == buf_.size() ? 1 : 0; }
120 std::string_view sub(uint32_t
begin, uint32_t
end)
const {
124 std::filesystem::path path_;
126 std::vector<uint32_t> rows_;
139 std::pair<const Src*, bool>
add(std::filesystem::path path, std::string buf) {
141 auto [i, fresh] = path2src_.try_emplace(std::move(k), std::move(path), std::move(buf));
142 return {&i->second, fresh};
147 std::pair<const Src*, bool>
add(std::filesystem::path path) {
149 if (
auto i = path2src_.find(k); i != path2src_.end())
return {&i->second,
false};
150 auto ifs = std::ifstream(path, std::ios::binary);
151 if (!ifs)
return {
nullptr,
false};
152 auto [i, fresh] = path2src_.try_emplace(std::move(k), std::move(path),
slurp(ifs));
153 return {&i->second, fresh};
157 static std::string
slurp(std::istream& is) {
158 return is ? std::string(std::istreambuf_iterator<char>(is), std::istreambuf_iterator<char>()) : std::string();
167 const Src*
lookup(
const std::filesystem::path& path)
const {
168 auto i = path2src_.find(
key(path));
169 return i == path2src_.
end() ? nullptr : &i->second;
177 static std::filesystem::path
key(
const std::filesystem::path& path) {
181 auto abs = std::filesystem::absolute(path, ec);
182 if (ec)
return path.lexically_normal();
183 auto res = std::filesystem::weakly_canonical(abs, ec);
184 return ec ? abs.lexically_normal() : res;
Interns the text - and the std::filesystem::path - of every file a Loc may point into.
std::pair< const Src *, bool > add(std::filesystem::path path)
As above, but reads the content from path.
static std::filesystem::path key(const std::filesystem::path &path)
The key path is interned under - absolute, symlink-free, and normalized.
const Src * lookup(const std::filesystem::path &path) const
std::pair< const Src *, bool > add(std::filesystem::path path, std::string buf)
static std::string slurp(std::istream &is)
Reads all of is into a std::string.
The content of one source file together with the offsets its rows start at.
std::string_view buf() const
std::string_view line(uint32_t row) const
Text of the 1-based row without its line terminator - or a leading utf8::Bom; empty if row is out of ...
uint32_t num_rows() const
The number of rows the file actually has.
bool contains(Pos pos) const
uint32_t col(Pos pos) const
Src(std::filesystem::path path, std::string buf)
const std::filesystem::path & path() const
Pos prev(Pos pos) const
Start of the last code point before pos - the character a half-open Loc::end points past.
uint32_t row(Pos pos) const
std::pair< uint32_t, uint32_t > rowcol(Pos pos) const
char32_t decode(std::istream &is)
Decodes the next UTF-8 sequence from is into a single char32_t.
constexpr char8_t is_valid234(char8_t c) noexcept
Is the 2nd, 3rd, or 4th byte of an UTF-8 byte sequence valid?
size_t num_code_points(std::string_view str) noexcept
Number of UTF-8 code points in str.
std::unordered_map< std::filesystem::path, V, PathHash > PathMap
Maps a std::filesystem::path to V.
Hashes a std::filesystem::path - consistent with its operator==, which compares lexically.
size_t operator()(const std::filesystem::path &path) const noexcept
Byte offset into a Src; pass around as value.
constexpr Pos()=default
Creates an invalid Position.