0

I have the following directory tree :

test_dir
  a
    f3.txt
  b
    f1.txt
    f2.txt

I want to traverse this folder and print it as follows :

test_dir
  b
    f2.txt
    f1.txt
  a
    f3.txt

For this I developed the following code snippet :

struct EntryInfo {
    std::filesystem::path path_;
    std::filesystem::file_type type_;
    std::uint32_t level_;
};

void PrintTree(ostream& dst,
               const path& p,
               const filesystem::file_status& status,
               std::vector<EntryInfo>& info,
               std::uint32_t level)
{
    if (status.type() == std::filesystem::file_type::directory) {
        info.push_back({p, std::filesystem::file_type::directory, level});
        for (const auto & entry : std::filesystem::directory_iterator(p)) {
            PrintTree(dst, entry.path(), entry.status(), info, level + 1);
        }
    } else {
        info.push_back({p, std::filesystem::file_type::regular, level});
    }
}

void PrintTree(ostream& dst, const path& p)
{
    std::vector<EntryInfo> info;
    for (const auto & entry : std::filesystem::directory_iterator(p)) {
        PrintTree(dst, entry.path(), entry.status(), info, 1);
    }

    std::sort(info.begin(), info.end(), [](const EntryInfo& lhs, const EntryInfo& rhs) {
        // smth here?
        return true;
    });

    std::cout << p.string() << std::endl;

    for (const auto& item : info) {
        std::cout << std::string(item.level_*2, ' ') << item.path_.filename().string() << std::endl;
    }

Is it possible to sort this vector to get the desired order of items to be printed? Or I'm wrong trying to store entries inside a vector? What is the right thing to do here? Any ideas are highly appreciated

Here is a small test case I expect to pass :

#include <cassert>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <string_view>
#include <vector>
#include <algorithm>

using namespace std;
using filesystem::path;

path operator""_p(const char* data, std::size_t sz) {
    return path(data, data + sz);
}

int main() {
    error_code err;
    filesystem::remove_all("test_dir", err);
    filesystem::create_directories("test_dir"_p / "a"_p, err);
    filesystem::create_directories("test_dir"_p / "b"_p, err);

    ofstream("test_dir"_p / "b"_p / "f1.txt"_p);
    ofstream("test_dir"_p / "b"_p / "f2.txt"_p);
    ofstream("test_dir"_p / "a"_p / "f3.txt"_p);

    ostringstream out;
    PrintTree(out, "test_dir"_p);
    assert(out.str() ==
        "test_dir\n"
        "  b\n"
        "    f2.txt\n"
        "    f1.txt\n"
        "  a\n"
        "    f3.txt\n"sv
    );
}
Dmitry
  • 1,912
  • 2
  • 18
  • 29
  • what determines the desired output? You want to sort in reverse alphabetical order? You just need to implement the predicate for sorting. `return true;` is not correct and actually causes undefined behavior, because the comparator must implement a strict weak orderin – 463035818_is_not_an_ai Apr 20 '21 at 10:46
  • Does this answer your Question? https://stackoverflow.com/questions/1380463/sorting-a-vector-of-custom-objects – 463035818_is_not_an_ai Apr 20 '21 at 10:47
  • I'm aware how to sort a custom object inside a vector but I doubt that for this scenario I'm doing the right thing storing items in vector and then trying to sort it...to be honest I don't have any ideas to implement lambda here (( – Dmitry Apr 20 '21 at 10:50
  • how to implement the lambda depends on how you want to sort the elements, only you know that. Is it reverse alphabetical order? – 463035818_is_not_an_ai Apr 20 '21 at 10:51
  • yes, it's a reverse alphabetical order but only for items that are on the same level - I put a desired output for my test scenario – Dmitry Apr 20 '21 at 10:53

1 Answers1

0

Here is a solution I got

struct EntryInfo {
    std::filesystem::path path_;
    std::filesystem::file_type type_;
};

void PrintTree(ostream& dst,
               const path& p,
               std::uint32_t level)
{
    std::string lead(level*2, ' ');
    dst << lead << p.filename().string() << "\n";

    std::vector<EntryInfo> directory_data;
    for (const auto & entry : std::filesystem::directory_iterator(p)) {
        directory_data.push_back({entry.path(), entry.status().type()});
    }

    std::sort(directory_data.begin(), directory_data.end(),
              [](const EntryInfo& lhs, const EntryInfo& rhs) {
        return (lhs.type_ > rhs.type_) ||
                ((lhs.type_ == rhs.type_) &&
                (lhs.path_.filename().string() > rhs.path_.filename().string()));
    });

    std::string lead_((level+1)*2, ' ');
    for (const auto& item : directory_data) {
        if (item.type_ == std::filesystem::file_type::directory) {
            PrintTree(dst, item.path_, level + 1);
        } else {
            dst << lead_ << item.path_.filename().string() << "\n";
        }
    }
}

void PrintTree(ostream& dst, const path& p)
{
    PrintTree(dst, p, 0);
}
Dmitry
  • 1,912
  • 2
  • 18
  • 29