From 4df60e639b7e492ac5f651f2b3aa02055de5549a Mon Sep 17 00:00:00 2001 From: John Ericson Date: Fri, 19 Sep 2025 12:09:46 -0400 Subject: [PATCH] Use shared pointers in the memory source accessor This allows aliasing, like hard links. --- src/libutil-tests/git.cc | 16 ++++++++-------- .../include/nix/util/memory-source-accessor.hh | 16 ++++++++++++---- src/libutil/memory-source-accessor.cc | 6 +++--- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/libutil-tests/git.cc b/src/libutil-tests/git.cc index 6180a4cfc..a06c5896d 100644 --- a/src/libutil-tests/git.cc +++ b/src/libutil-tests/git.cc @@ -233,30 +233,30 @@ TEST_F(GitTest, both_roundrip) .contents{ { "foo", - File::Regular{ + make_ref(File::Regular{ .contents = "hello\n\0\n\tworld!", - }, + }), }, { "bar", - File::Directory{ + make_ref(File::Directory{ .contents = { { "baz", - File::Regular{ + make_ref(File::Regular{ .executable = true, .contents = "good day,\n\0\n\tworld!", - }, + }), }, { "quux", - File::Symlink{ + make_ref(File::Symlink{ .target = "/over/there", - }, + }), }, }, - }, + }), }, }, }; diff --git a/src/libutil/include/nix/util/memory-source-accessor.hh b/src/libutil/include/nix/util/memory-source-accessor.hh index 98c193800..be1d17665 100644 --- a/src/libutil/include/nix/util/memory-source-accessor.hh +++ b/src/libutil/include/nix/util/memory-source-accessor.hh @@ -35,7 +35,7 @@ struct MemorySourceAccessor : virtual SourceAccessor { using Name = std::string; - std::map> contents; + std::map, std::less<>> contents; bool operator==(const Directory &) const noexcept; // TODO libc++ 16 (used by darwin) missing `std::map::operator <=>`, can't do yet. @@ -89,13 +89,21 @@ struct MemorySourceAccessor : virtual SourceAccessor SourcePath addFile(CanonPath path, std::string && contents); }; -inline bool MemorySourceAccessor::File::Directory::operator==( - const MemorySourceAccessor::File::Directory &) const noexcept = default; +inline bool +MemorySourceAccessor::File::Directory::operator==(const MemorySourceAccessor::File::Directory & other) const noexcept +{ + return std::ranges::equal(contents, other.contents, [](const auto & lhs, const auto & rhs) -> bool { + return lhs.first == rhs.first && *lhs.second == *rhs.second; + }); +}; inline bool MemorySourceAccessor::File::Directory::operator<(const MemorySourceAccessor::File::Directory & other) const noexcept { - return contents < other.contents; + return std::ranges::lexicographical_compare( + contents, other.contents, [](const auto & lhs, const auto & rhs) -> bool { + return lhs.first < rhs.first && *lhs.second < *rhs.second; + }); } inline bool MemorySourceAccessor::File::operator==(const MemorySourceAccessor::File &) const noexcept = default; diff --git a/src/libutil/memory-source-accessor.cc b/src/libutil/memory-source-accessor.cc index 363f52a54..c25079497 100644 --- a/src/libutil/memory-source-accessor.cc +++ b/src/libutil/memory-source-accessor.cc @@ -24,11 +24,11 @@ MemorySourceAccessor::File * MemorySourceAccessor::open(const CanonPath & path, i, { std::string{name}, - File::Directory{}, + make_ref(File::Directory{}), }); } } - cur = &i->second; + cur = &*i->second; } if (newF && create) @@ -92,7 +92,7 @@ MemorySourceAccessor::DirEntries MemorySourceAccessor::readDirectory(const Canon if (auto * d = std::get_if(&f->raw)) { DirEntries res; for (auto & [name, file] : d->contents) - res.insert_or_assign(name, file.lstat().type); + res.insert_or_assign(name, file->lstat().type); return res; } else throw Error("file '%s' is not a directory", path);