5,427,813 members and growing! (16,237 online)
Email Password   helpLost your password?
Desktop Development » Files and Folders » General     Intermediate License: The Code Project Open License (CPOL)

Win32 File Name Iteration Boost Way

By mb2sync

A Port of ::FindFirstFile to Boost.Range and Boost.Foreach
VC7.1, C++, .NET, Windows, WinXP, MFC, VS.NET2003, Visual Studio, Dev

Posted: 3 Nov 2005
Updated: 3 Nov 2005
Views: 18,423
Bookmarked: 6 times
Announcements
Want a new Job?



Search    
Advanced Search
Sitemap
10 votes for this Article.
Popularity: 4.42 Rating: 4.42 out of 5
1 vote, 10.0%
1
0 votes, 0.0%
2
0 votes, 0.0%
3
3 votes, 30.0%
4
6 votes, 60.0%
5

Introduction

I was inspired by the excellent article, Win32 File Name Iteration STL Way. I think the problem of the article is that the handle of ::FindFirstFile is managed by iterators. After combating Boost.Range for months, I realized that Boost.Range could remove that complexity. The result was named find_file_range, which is the direct translation from ::FindFirstFile to C++.

Requirements

find_file_range

find_file_range is a model of Single Pass Range whose value_type is WIN32_FIND_DATA. If you are not familiar with Boost.Range concepts, you could regard it as something like a Container which provides Input Iterators:

find_file_range ffrng("*.*");
typedef boost::range_result_iterator<find_file_range>::type iter_t;
for (iter_t it = boost::begin(ffrng), last = boost::end(ffrng); it != last; ++it) {
  std::cout << it->cFileName << std::endl;
}

If you iterate find_file_range twice, the behavior is undefined. This code proves find_file_range is a thin wrapper of ::FindFirstFile, but seems somewhat clumsy. Why must we write the idiom hundreds of times? If you resent it, it will come.

Foreach will Come

Boost.Foreach (accepted into Boost, but not yet part of the release) provides foreach that is missing from C++:

find_file_range ffrng("*.*");
BOOST_FOREACH (WIN32_FIND_DATA& data, ffrng) {
  std::cout << data.cFileName << std::endl;
}

Is this a new language? No, It's C++. The implementation is magical. If you are interested in it, check Conditional Love: FOREACH Redux written by Eric Niebler.

Filtering

One class, one responsibility. find_file_range doesn't offer any filtering using dwFileAttributes of WIN32_FIND_DATA. Instead, Adaptable Predicates named find_file_is_xxx are provided. They are available for boost::make_filter_range, which is a part of Boost.RangeEx:

find_file_range ffrng("*.*");
BOOST_FOREACH (
  WIN32_FIND_DATA& data,
  boost::make_filter_range(ffrng, boost::not1(find_file_is_dots()))
)
{
  std::cout << data.cFileName << std::endl;
}

std::not1 is completely broken by reference-to-reference problem, so you must use boost::not1 from Boost.Functional.

Transforming

As a mark of respect for the original article, find_file_construct template that makes a model of Adaptable Unary Functor is provided for those who want to get cFileName of WIN32_FIND_DATA as a string object. It is available for boost::make_transform_range:

find_file_range ffrng("*.*");
BOOST_FOREACH (
  std::string const& filename,
  boost::make_transform_range(ffrng, find_file_construct<std::string>())
)
{
  std::cout << filename << std::endl;
}

find_file_construct template takes a type Sequence. If your string type is not a Sequence like CString, you could use find_file_stringize instead.

Chain of Range Adaptors

The chain of filtering and transforming is also available:

find_file_range ffrng("*.*");
BOOST_FOREACH (
  std::string const& filename,
  boost::make_transform_range(
    boost::make_filter_range(
      boost::make_filter_range(
        ffrng,
        boost::not1(find_file_is_hidden())
      ),
      boost::not1(find_file_is_directory())
    ),
    find_file_stringize<std::string>()
  )
)
{
  std::cout << filename << std::endl;
}

This chain is lazy and functional, but unreadable. And so Boost.RangeEx provides Range Adaptors:

find_file_range ffrng("*.*");
BOOST_FOREACH (
  std::string const& filename,
  ffrng |
    boost::adaptor::filter(boost::not1(find_file_is_hidden())) |
    boost::adaptor::filter(boost::not1(find_file_is_directory())) |
    boost::adaptor::transform(find_file_construct<std::string>())
)
{
  std::cout << filename << std::endl;
}

This is rather "procedural" and shows the future of C++.

Points of Interest

find_file_range is just like a disposable container and doesn't offer any additional functionalities unlike Boost.Filesystem, but it doesn't demand any additional resources. Boost.Range concepts are wide-open to such classes. In fact, find_file_range depends on the fact that clients don't iterate twice, while boost::iterator_range depends on the fact that holding iterators are valid. You could easily make many classes conform to the concepts. I hope this article helps:

std::string inputs; {
  boost::copy(make_istream_range<char>(std::cin), std::back_inserter(inputs));
}
std::cout << inputs << std::endl;

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

mb2sync


I am worried about my poor English...
Location: Japan Japan

Other popular Files and Folders articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 6 of 6 (Total in Forum: 6) (Refresh)FirstPrevNext
Subject  Author Date 
Generalassertmembereugeneugene4:56 8 Nov '05  
GeneralRe: assertmembermb2sync12:50 8 Nov '05  
Generalboost::dir_itmemberTodd Smith10:25 4 Nov '05  
GeneralRe: boost::dir_itmembermb2sync13:56 4 Nov '05  
Generalgood exploration of boost conceptsmemberMartin.Holzherr3:22 4 Nov '05  
GeneralRe: good exploration of boost conceptsmembermb2sync5:53 4 Nov '05  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 3 Nov 2005
Editor: Deeksha Shenoy
Copyright 2005 by mb2sync
Everything else Copyright © CodeProject, 1999-2008
Web20 | Advertise on the Code Project