Home > front end >  boost::adaptors::transformed fails with std::filesystem::directory_iterator
boost::adaptors::transformed fails with std::filesystem::directory_iterator

Time:11-10

Why entry is empty inside boost::adaptors::transformed() ? I tried without filter, but it does not help.

#include <boost/range/adaptors.hpp>
#include <boost/static_string/static_string.hpp>
#include <boost/utility/string_view.hpp>
#include <filesystem>

int main() {
    std::filesystem::path root = ".";

    const auto names =
        boost::make_iterator_range(std::filesystem::directory_iterator(root),
                                   std::filesystem::directory_iterator{}) |
        boost::adaptors::filtered([](const std::filesystem::directory_entry& entry) {
            const auto name = entry.path().stem().string();
            const auto suff = entry.path().extension().string();
            return suff == ".cfg" && !boost::string_view(name).starts_with("__");
        }) |
        boost::adaptors::transformed([](const std::filesystem::directory_entry& entry) {
            auto result = boost::static_string<64>{};
            result      = entry.path().stem().string();
            return result;
        });
}

CodePudding user response:

I have copied your image into a self-contained program an cannot see your issue:

Live On Coliru

#include <boost/range/adaptors.hpp>
#include <boost/static_string/static_string.hpp>
#include <boost/utility/string_view.hpp>
#include <filesystem>
#include <iostream>

int main() {
    std::filesystem::path root = ".";

    const auto names =
        boost::make_iterator_range(std::filesystem::directory_iterator(root),
                                   std::filesystem::directory_iterator{}) |
        boost::adaptors::filtered([](const std::filesystem::directory_entry& entry) {
            const auto name = entry.path().stem().string();
            const auto suff = entry.path().extension().string();
            return suff == ".cfg" && !boost::string_view(name).starts_with("__");
        }) |
        boost::adaptors::transformed([](const std::filesystem::directory_entry& entry) {
            auto result = boost::static_string<64>{};
            result      = entry.path().stem().string();
            return result;
        });

    for (auto&& name : names) {
        std::cout << " - " << name << "\n";
    }
}

Creating some files like:

touch test{001..022}.cfg
touch __hidden.cfg

Prints

 - test001
 - test006
 - test013
 - test017
 - test015
 - test021
 - test008
 - test012
 - test016
 - test002
 - test007
 - test005
 - test010
 - test009
 - test020
 - test014
 - test019
 - test022
 - test018
 - test011
 - test004
 - test003

BONUS

Simplification and style:

Live On Coliru

#include <boost/range/adaptors.hpp>
#include <boost/static_string/static_string.hpp>
#include <boost/utility/string_view.hpp>
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;

bool is_config(fs::path const& p) {
    auto name = p.stem().string();

    return p.extension() == ".cfg" &&
        !boost::string_view(name).starts_with("__");
};

auto stem(fs::path const& p) { return boost::static_string<64>{p.stem().string()}; }

auto cfgs(fs::path root) {
    using namespace boost::adaptors;
    auto files = boost::make_iterator_range(fs::directory_iterator(root), {});
    return files | filtered(is_config) | transformed(stem);
}

int main() {
    for (auto cfg : cfgs("."))
        std::cout << " - " << cfg << "\n";
}

Same output, obviously.

CodePudding user response:

UPDATE

const auto root = std::filesystem::path(".");
const auto names = boost::make_iterator_range(
    std::filesystem::directory_iterator(root),
    std::filesystem::directory_iterator {}
) |
boost::adaptors::filtered([](const std::filesystem::directory_entry& entry)
{
    const auto name = entry.path().stem().string();
    const auto suff = entry.path().extension().string();
    return suff == ".cfg" && !boost::string_view(name).starts_with("__");
}) |
boost::adaptors::transformed([](const std::filesystem::directory_entry& entry)
{
    auto result = boost::static_string<64>{};
    result = entry.path().stem().string();
    std::cout << result << std::endl;
    return result;
});

// NEW LINES !!!
std::cout << boost::size(names) << std::endl;
std::cout << boost::size(names) << std::endl;

First call of boost::size() returns right count of names, but second returns 1. I think this is a special behavior of the std::filesystem::directory_iterator

  • Related