Convert GetFilesInFolderHelper to use BFS (#268)

This function has a huge stack frame (> 8k, thanks to tinydir), and is
called recursively. I have seen this function causing some stack
overflows. So convert it to BFS to avoid that.
This commit is contained in:
yshui 2018-01-08 17:09:19 +00:00 committed by Fangrui Song
parent 0ef5aec3fc
commit b644b54614

View File

@ -140,49 +140,53 @@ static void GetFilesInFolderHelper(
bool recursive, bool recursive,
std::string output_prefix, std::string output_prefix,
const std::function<void(const std::string&)>& handler) { const std::function<void(const std::string&)>& handler) {
tinydir_dir dir; std::queue<std::pair<std::string, std::string>> q;
if (tinydir_open(&dir, folder.c_str()) == -1) { q.push(make_pair(folder, output_prefix));
LOG_S(WARNING) << "Unable to open directory " << folder; while(!q.empty()) {
goto bail; tinydir_dir dir;
} if (tinydir_open(&dir, q.front().first.c_str()) == -1) {
LOG_S(WARNING) << "Unable to open directory " << folder;
while (dir.has_next) {
tinydir_file file;
if (tinydir_readfile(&dir, &file) == -1) {
LOG_S(WARNING) << "Unable to read file " << file.name
<< " when reading directory " << folder;
goto bail; goto bail;
} }
// Skip all dot files. while (dir.has_next) {
// tinydir_file file;
// The nested ifs are intentional, branching order is subtle here. if (tinydir_readfile(&dir, &file) == -1) {
// LOG_S(WARNING) << "Unable to read file " << file.name
// Note that in the future if we do support dot directories/files, we must << " when reading directory " << folder;
// always ignore the '.' and '..' directories otherwise this will loop goto bail;
// infinitely. }
if (file.name[0] != '.') {
if (file.is_dir) { // Skip all dot files.
if (recursive) { //
std::string child_dir = output_prefix + file.name + "/"; // The nested ifs are intentional, branching order is subtle here.
if (!IsSymLink(child_dir)) //
GetFilesInFolderHelper(file.path, true /*recursive*/, child_dir, // Note that in the future if we do support dot directories/files, we must
handler); // always ignore the '.' and '..' directories otherwise this will loop
// infinitely.
if (file.name[0] != '.') {
if (file.is_dir) {
if (recursive) {
std::string child_dir = output_prefix + file.name + "/";
if (!IsSymLink(child_dir))
q.push(make_pair(file.path, child_dir));
}
} else {
handler(q.front().second + file.name);
} }
} else { }
handler(output_prefix + file.name);
if (tinydir_next(&dir) == -1) {
LOG_S(WARNING) << "Unable to fetch next file when reading directory "
<< folder;
goto bail;
} }
} }
if (tinydir_next(&dir) == -1) { bail:
LOG_S(WARNING) << "Unable to fetch next file when reading directory " tinydir_close(&dir);
<< folder; q.pop();
goto bail;
}
} }
bail:
tinydir_close(&dir);
} }
std::vector<std::string> GetFilesInFolder(std::string folder, std::vector<std::string> GetFilesInFolder(std::string folder,