Cache the value for absolute path in FileSpec.

Checking if a path is absolute can be expensive and currently the result is not cached in the FileSpec object. This patch adds caching and also code to clear the cache if the file is modified.

Differential Revision: https://reviews.llvm.org/D130396
This commit is contained in:
Greg Clayton 2022-07-28 13:31:41 -07:00
parent 529a3d87a7
commit dc0f452e85
3 changed files with 61 additions and 12 deletions

View File

@ -416,10 +416,24 @@ protected:
// Convenience method for setting the file without changing the style.
void SetFile(llvm::StringRef path);
/// Called anytime m_directory or m_filename is changed to clear any cached
/// state in this object.
void PathWasModified() {
m_is_resolved = false;
m_absolute = Absolute::Calculate;
}
enum class Absolute : uint8_t {
Calculate,
Yes,
No
};
// Member variables
ConstString m_directory; ///< The uniqued directory path
ConstString m_filename; ///< The uniqued filename path
mutable bool m_is_resolved = false; ///< True if this path has been resolved.
mutable Absolute m_absolute = Absolute::Calculate; ///< Cache absoluteness.
Style m_style; ///< The syntax that this path uses (e.g. Windows / Posix)
};

View File

@ -170,9 +170,7 @@ void FileSpec::SetFile(llvm::StringRef pathname) { SetFile(pathname, m_style); }
// up into a directory and filename and stored as uniqued string values for
// quick comparison and efficient memory usage.
void FileSpec::SetFile(llvm::StringRef pathname, Style style) {
m_filename.Clear();
m_directory.Clear();
m_is_resolved = false;
Clear();
m_style = (style == Style::native) ? GetNativeStyle() : style;
if (pathname.empty())
@ -259,6 +257,7 @@ Stream &lldb_private::operator<<(Stream &s, const FileSpec &f) {
void FileSpec::Clear() {
m_directory.Clear();
m_filename.Clear();
PathWasModified();
}
// Compare two FileSpec objects. If "full" is true, then both the directory and
@ -332,26 +331,32 @@ FileSpec::Style FileSpec::GetPathStyle() const { return m_style; }
void FileSpec::SetDirectory(ConstString directory) {
m_directory = directory;
PathWasModified();
}
void FileSpec::SetDirectory(llvm::StringRef directory) {
m_directory = ConstString(directory);
PathWasModified();
}
void FileSpec::SetFilename(ConstString filename) {
m_filename = filename;
PathWasModified();
}
void FileSpec::SetFilename(llvm::StringRef filename) {
m_filename = ConstString(filename);
PathWasModified();
}
void FileSpec::ClearFilename() {
m_filename.Clear();
PathWasModified();
}
void FileSpec::ClearDirectory() {
m_directory.Clear();
PathWasModified();
}
// Extract the directory and path into a fixed buffer. This is needed as the
@ -488,18 +493,22 @@ bool FileSpec::IsRelative() const {
}
bool FileSpec::IsAbsolute() const {
llvm::SmallString<64> current_path;
GetPath(current_path, false);
// Check if we have cached if this path is absolute to avoid recalculating.
if (m_absolute != Absolute::Calculate)
return m_absolute == Absolute::Yes;
// Early return if the path is empty.
if (current_path.empty())
return false;
m_absolute = Absolute::No;
// We consider paths starting with ~ to be absolute.
if (current_path[0] == '~')
return true;
llvm::SmallString<64> path;
GetPath(path, false);
return llvm::sys::path::is_absolute(current_path, m_style);
if (!path.empty()) {
// We consider paths starting with ~ to be absolute.
if (path[0] == '~' || llvm::sys::path::is_absolute(path, m_style))
m_absolute = Absolute::Yes;
}
return m_absolute == Absolute::Yes;
}
void FileSpec::MakeAbsolute(const FileSpec &dir) {

View File

@ -450,3 +450,29 @@ TEST(FileSpecTest, OperatorBool) {
EXPECT_FALSE(FileSpec(""));
EXPECT_TRUE(FileSpec("/foo/bar"));
}
TEST(FileSpecTest, TestAbsoluteCaching) {
// Test that if we modify a path that we recalculate if a path is relative
// or absolute correctly. The test below calls set accessors and functions
// that change the path and verifies that the FileSpec::IsAbsolute() returns
// the correct value.
FileSpec file = PosixSpec("/tmp/a");
EXPECT_TRUE(file.IsAbsolute());
file.ClearDirectory();
EXPECT_FALSE(file.IsAbsolute());
file.SetDirectory("/tmp");
EXPECT_TRUE(file.IsAbsolute());
file.SetDirectory(".");
EXPECT_FALSE(file.IsAbsolute());
file.SetPath("/log.txt");
EXPECT_TRUE(file.IsAbsolute());
file.RemoveLastPathComponent();
EXPECT_TRUE(file.IsAbsolute());
file.ClearFilename();
EXPECT_FALSE(file.IsAbsolute());
file.AppendPathComponent("foo.txt");
EXPECT_FALSE(file.IsAbsolute());
file.PrependPathComponent("/tmp");
EXPECT_TRUE(file.IsAbsolute());
}