Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fileutil: use std::filesystem #11426

Merged
merged 2 commits into from Feb 13, 2023
Merged

Conversation

shuffle2
Copy link
Contributor

@shuffle2 shuffle2 commented Jan 10, 2023

replaces most stuff

incorporates #10955

needs #10994 to be merged first for platforms that didn't previously use std::filesystem to compile

@shuffle2
Copy link
Contributor Author

Poke on this?

int prev_depth = 0;
std::stack<FSTEntry*> dir_fsts;
dir_fsts.push(&parent_entry);
for (auto it = fs::recursive_directory_iterator(directory_path, error);
Copy link
Contributor

@iwubcode iwubcode Feb 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This segment comes across as a bit confusing with the stack and the depth comparisons. Am I right in assuming we are just trying to come up with a tree of FSTEntrys? And that we can't rely on recursive_directory_iterator alone because its order is undefined?

If so, we could improve things from a readability standpoint (not sure if it's more expensive) by avoiding it altogether:

void RecurseTreeHelper(auto& fst_entry, auto fs_path)
{
	for (auto it = fs::directory_iterator(fs_path, error); it != fs::directory_iterator();
	 it.increment(error))
	{
		auto child_entry = dirent_to_fstent(*it);
		RecurseTreeHelper(child_entry, *it);
		fst_entry.children.emplace_back(std::move(child_entry));
	}
	fst_entry.size += fst_entry.children.size();
	for (auto& child : fst_entry.children)
		if (child.isDirectory)
			fst_entry.size += child.size;
}

Could also do this with a lambda but it's a little klunky: https://stackoverflow.com/questions/2067988/recursive-lambda-functions-in-c11

If I'm completely missing the point, let me know.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main complication I was working around is that dolphin expects to return the size of all entries (see calc_dir_size), so you need to account for that as well.

Also:

  • you must be careful that you don't cause some iterators to become invalidated that will be used in the future.
  • I also generally try to avoid recursion where possible, and here the stack seems pretty normal way to do that. I don't feel super strongly about it here, but I'm probably not going to change it - maybe change it in a future PR if you'd like?

Copy link
Contributor

@iwubcode iwubcode Feb 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I didn't take into account the dir size. Should be easy enough to fix (EDIT: possibly fixed now) but I get your points. Out of curiosity, do you avoid recursion due to concerns about stack size or just not liking it? (I've seen both)

FWIW, I do see what you're doing and it seems like it should work but it isn't intuitive enough to me that I can readily sign off on it. Unfortunately, we only have unit tests for deletion otherwise I'd have a bit more confidence. But yeah this is pretty minor, the code overall looks really good. Great work!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, mainly stack size. It's much easier to accidentally run out of stack than heap.

when i made the commit, i made a unittest that compared an fstentry tree of my entire C:\ drive using the old+new code and it was identical, altho it's just a random test :)

Copy link
Contributor

@AdmiralCurtiss AdmiralCurtiss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks fine to me. I do agree with iwubcode that it would be good to have unit tests for this stuff so we can know it doesn't change behavior, but what can you do...

I'm curious why you removed that GetExePath() optimization but otherwise I think we should just merge this and hope for the best.

static const std::string dolphin_path = [] {
std::string result;
#ifdef _WIN32
auto dolphin_exe_path = GetModuleName(nullptr);
if (dolphin_exe_path)
{
std::unique_ptr<TCHAR[], decltype(&std::free)> dolphin_exe_expanded_path{
_tfullpath(nullptr, dolphin_exe_path->c_str(), 0), std::free};
if (dolphin_exe_expanded_path)
{
result = TStrToUTF8(dolphin_exe_expanded_path.get());
}
else
{
result = TStrToUTF8(*dolphin_exe_path);
}
}
auto exe_path = GetModuleName(nullptr);
if (!exe_path)
return {};
std::error_code error;
auto exe_path_absolute = fs::absolute(exe_path.value(), error);
if (error)
return {};
return PathToString(exe_path_absolute);
#elif defined(__APPLE__)
result = GetBundleDirectory();
return GetBundleDirectory();
#else
char dolphin_exe_path[PATH_MAX];
ssize_t len = ::readlink("/proc/self/exe", dolphin_exe_path, sizeof(dolphin_exe_path));
if (len == -1 || len == sizeof(dolphin_exe_path))
{
len = 0;
}
dolphin_exe_path[len] = '\0';
result = dolphin_exe_path;
char dolphin_exe_path[PATH_MAX];
ssize_t len = ::readlink("/proc/self/exe", dolphin_exe_path, sizeof(dolphin_exe_path));
if (len == -1 || len == sizeof(dolphin_exe_path))
{
len = 0;
}
dolphin_exe_path[len] = '\0';
return dolphin_exe_path;
#endif
return result;
}();
return dolphin_path;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason you removed this construct? As far as I can tell this is supposed to be an optimization so the exe path is only constructed once instead of on every call to GetExePath(), but granted I don't know how critical this optimization actually is. It's been there since forever.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly I just thought the lambda-into-static was ugly. On windows I dont think it provides any important speedup as the data is just fetched from the PEB and so at most you pay a string conversion/copy cost (and afaik it's not called often). But yea, caching it isn't terrible in itself.

@AdmiralCurtiss
Copy link
Contributor

Well I tested this for a few minutes and everything seems to work as expected, so here goes nothing...

@AdmiralCurtiss AdmiralCurtiss merged commit 8f91cb6 into dolphin-emu:master Feb 13, 2023
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
3 participants