Skip to content

Instantly share code, notes, and snippets.

@fmorgner
Created June 19, 2017 11:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fmorgner/93f2e1e55ae6a73d227258eb1e1d3990 to your computer and use it in GitHub Desktop.
Save fmorgner/93f2e1e55ae6a73d227258eb1e1d3990 to your computer and use it in GitHub Desktop.
Benchmark for filtering files in C++
// COMPILE WITH: g++ -std=c++1z filter.cpp -o filter -O3 -flto -lhayai_main -lstdc++fs
#include <algorithm>
#include <boost/iterator/filter_iterator.hpp>
#include <experimental/filesystem>
#include <hayai/hayai.hpp>
#include <iterator>
#include <set>
#include <string>
#include <vector>
#include <functional>
namespace fs = std::experimental::filesystem;
auto constexpr test_root = "/home/sophia/test_root"; /*!< The root folder containing the files */
/**
* A filter that accepts everything
*/
auto constexpr true_filter = [](auto const &) {
return true;
};
/**
* A filter that accepts only files
*
* @param entry A 'directory_entry'
*/
auto constexpr file_filter = [](auto const & entry) {
return fs::is_regular_file(entry);
};
/**
* A filter that accepts only files with specific extensions
*
* @param entry A 'directory_entry'
*/
auto constexpr file_extension_filter = [](auto const & entry) {
auto static const kExtensions = std::set<std::string>{".jpg", ".png", ".tga"};
return fs::is_regular_file(entry) && kExtensions.count(entry.path().extension());
};
/**
* Get the number of 'directory_entry' objects in @p root satisfying the @p predicate
*
* @param root The root folder to search in
* @param predicate A predicate to check on the 'directory_entry' objects in @p root
*/
std::size_t get_num_entries(fs::path const & root, std::function<bool (fs::directory_entry const &)> predicate = true_filter)
{
auto && iterator = fs::recursive_directory_iterator{root};
return std::count_if(begin(iterator), end(iterator), predicate);
}
/**
* Get all directory entries in @p root
*
* @param root The root directory
*/
auto no_filter(fs::path const & root)
{
auto && iterator = fs::recursive_directory_iterator{root};
return std::vector<fs::directory_entry>{begin(iterator), end(iterator)};
}
/**
* Get all directory entries in @p root
*
* @note This version preallocates the result vector to the required number of elements
*
* @param root The root directory
*/
auto no_filter_prealloc(fs::path const & root)
{
auto && iterator = fs::recursive_directory_iterator{root};
auto && result = std::vector<fs::directory_entry>{};
result.reserve(get_num_entries(root));
result.insert(result.end(), begin(iterator), end(iterator));
return result;
}
/**
* Get all 'file' directory entries in @p root
*
* @note This version uses the Boost.Iterator library
*
* @param root The root directory
*/
auto boost_file_entries(fs::path const & root)
{
auto && iterator = fs::recursive_directory_iterator{root};
auto && begin = boost::make_filter_iterator(file_filter,
fs::begin(iterator), fs::end(iterator));
auto && end = boost::make_filter_iterator(file_filter,
fs::end(iterator), fs::end(iterator));
return std::vector<fs::directory_entry>{begin, end};
}
/**
* Get all 'file' directory entries in @p root
*
* @note This version uses the Boost.Iterator library
* @note This version preallocates the result vector to the required number of elements
*
* @param root The root directory
*/
auto boost_file_entries_prealloc(fs::path const & root)
{
auto && iterator = fs::recursive_directory_iterator{root};
auto && begin = boost::make_filter_iterator(file_filter,
fs::begin(iterator), fs::end(iterator));
auto && end = boost::make_filter_iterator(file_filter,
fs::end(iterator), fs::end(iterator));
auto && result = std::vector<fs::directory_entry>{};
result.reserve(get_num_entries(root, file_filter));
result.insert(result.end(), begin, end);
return result;
}
/**
* Get all 'file' directory entries with 'image' file extensions in @p root
*
* @note This version uses the Boost.Iterator library
*
* @param root The root directory
*/
auto boost_file_extension_entries(fs::path const & root)
{
auto && iterator = fs::recursive_directory_iterator{root};
auto && begin = boost::make_filter_iterator(file_extension_filter,
fs::begin(iterator), fs::end(iterator));
auto && end = boost::make_filter_iterator(file_extension_filter,
fs::end(iterator), fs::end(iterator));
return std::vector<fs::directory_entry>{begin, end};
}
/**
* Get all 'file' directory entries with 'image' file extensions in @p root
*
* @note This version uses the Boost.Iterator library
* @note This version preallocates the result vector to the required number of elements
*
* @param root The root directory
*/
auto boost_file_extension_entries_prealloc(fs::path const & root)
{
auto && iterator = fs::recursive_directory_iterator{root};
auto && begin = boost::make_filter_iterator(file_extension_filter,
fs::begin(iterator), fs::end(iterator));
auto && end = boost::make_filter_iterator(file_extension_filter,
fs::end(iterator), fs::end(iterator));
auto && result = std::vector<fs::directory_entry>{};
result.reserve(get_num_entries(root, file_extension_filter));
result.insert(result.end(), begin, end);
return result;
}
/**
* Get all 'file' directory entries in @p root
*
* @note This version uses only standard functions
*
* @param root The root directory
*/
auto std_file_entries(fs::path const & root)
{
auto && iterator = fs::recursive_directory_iterator{root};
auto && result = std::vector<fs::directory_entry>{};
copy_if(begin(iterator), end(iterator), back_inserter(result), file_filter);
return result;
}
/**
* Get all 'file' directory entries in @p root
*
* @note This version uses only standard functions
* @note This version preallocates the result vector to the required number of elements
*
* @param root The root directory
*/
auto std_file_entries_prealloc(fs::path const & root)
{
auto && iterator = fs::recursive_directory_iterator{root};
auto && result = std::vector<fs::directory_entry>{};
result.reserve(get_num_entries(root, file_filter));
copy_if(fs::begin(iterator), fs::end(iterator), back_inserter(result), file_filter);
return result;
}
/**
* Get all 'file' directory entries with 'image' file extensions in @p root
*
* @note This version uses only standard functions
*
* @param root The root directory
*/
auto std_file_extension_entries(fs::path const & root)
{
auto && result = std::vector<fs::directory_entry>{};
auto && iterator = fs::recursive_directory_iterator{root};
copy_if(begin(iterator), end(iterator), back_inserter(result), file_extension_filter);
return result;
}
/**
* Get all 'file' directory entries with 'image' file extensions in @p root
*
* @note This version uses only standard functions
* @note This version preallocates the result vector to the required number of elements
*
* @param root The root directory
*/
auto std_file_extension_entries_prealloc(fs::path const & root)
{
auto && iterator = fs::recursive_directory_iterator{root};
auto && result = std::vector<fs::directory_entry>{};
result.reserve(get_num_entries(root, file_extension_filter));
copy_if(begin(iterator), end(iterator), back_inserter(result), file_extension_filter);
return result;
}
auto constexpr kRuns{10};
auto constexpr kIterations{25};
BENCHMARK(FileFilter, NoFilter, kRuns, kIterations) { no_filter(test_root); }
BENCHMARK(FileFilter, NoFilterPrealloc, kRuns, kIterations) { no_filter_prealloc(test_root); }
BENCHMARK(FileFilter, BoostFileFilter, kRuns, kIterations) { boost_file_entries(test_root); }
BENCHMARK(FileFilter, StdFileFilter, kRuns, kIterations) { std_file_entries(test_root); }
BENCHMARK(FileFilter, BoostFileFilterPrealloc, kRuns, kIterations) { boost_file_entries_prealloc(test_root); }
BENCHMARK(FileFilter, StdFileFilterPrealloc, kRuns, kIterations) { std_file_entries_prealloc(test_root); }
BENCHMARK(FileFilter, BoostFileExtensionFilter, kRuns, kIterations) { boost_file_extension_entries(test_root); }
BENCHMARK(FileFilter, StdFileExtensionFilter, kRuns, kIterations) { std_file_extension_entries(test_root); }
BENCHMARK(FileFilter, BoostFileExtensionFilterPrealloc, kRuns, kIterations) { boost_file_extension_entries_prealloc(test_root); }
BENCHMARK(FileFilter, StdFileExtensionFilterPrealloc, kRuns, kIterations) { std_file_extension_entries_prealloc(test_root); }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment