Trouble grokking iterator adaptors
Hi there, I could really use the features provided by iterator adaptors part of the library, but I'm having a lot of trouble getting a nested set of adaptors to compile. In one case, I'd like to return an iterator into std::map< std::string, boost::shared_ptr< ApiOption > >, and have it return references to options in which option->isTemplate( ) is false. Conceptually, I'd like a filter_iterator->indirect_iterator-
projection_iterator chain.
I've been using this typedef to project onto the second member of the pair: typedef boost::projection_iterator_pair_generator< select_second< std::string, boost::shared_ptr< ApiOption > >, OptionMap::iterator, OptionMap::const_iterator > OptionMapIterators; but I've been at a loss to add indirect_iterator and filter_iterator into the mix. Can anyone help me get unstuck? Thank you in advance, Kris
The following is a part of the directory_iterator documentation: "A path returned by dereferencing a directory_iterator is, if representing a directory, suitable for.... If not representing a directory, the dereferenced path is suitable for..." So I would assume that dereferencing a directory_iterator and using is_directory() should always be possible. This is not the case for a dangling link. In the example below is_directory() throws an exception when a dangling link is encountered. boost::filesystem::directory_iterator itDirEnd; for (boost::filesystem::directory_iterator itDir("/tmp");itDir!=itDirEnd;++itDir) { if (boost::filesystem::is_directory(*itDir)) // throws an exception for dangling links ; } Should the use of directory_iterator under certain circumstances force the user to use the native operating system API? Wouldn't it be more consistent to skip links altogether when iterating? Best regards, Peter.
At 04:45 PM 4/14/2003, Peter Klotz wrote:
The following is a part of the directory_iterator documentation:
"A path returned by dereferencing a directory_iterator is, if representing a directory, suitable for.... If not representing a directory, the dereferenced path is suitable for..."
So I would assume that dereferencing a directory_iterator and using is_directory() should always be possible.
For some operating systems, that isn't correct. For example, on Windows 2K (and presumably other Windows variants), certain files like the pagefile can't even be queried by is_directory() without an exception being thrown.
This is not the case for a dangling link.
In the example below is_directory() throws an exception when a dangling link is encountered.
boost::filesystem::directory_iterator itDirEnd; for (boost::filesystem::directory_iterator itDir("/tmp");itDir!=itDirEnd;++itDir) { if (boost::filesystem::is_directory(*itDir)) // throws an exception for dangling links ; }
Should the use of directory_iterator under certain circumstances force
Could you give a bit of background on the above? What operating system? Exactly what do you mean by "dangling link"? If your operating system has several kinds of links, which kind are you talking about? the
user to use the native operating system API?
Yes - in cases where there doesn't seem to be any way to abstract the operation into a portable function it is better to leave it for an operating system specific function.
Wouldn't it be more consistent to skip links altogether when iterating?
I'm not sure. Non-pathological links seem to work as expected, and operating systems often detect and report pathological cases as errors, which seems to me to be reasonable behavior. OTOH, links aren't an area that has received a lot of scrutiny, so it may be that some change is needed. --Beman
Hi Beman
Could you give a bit of background on the above? What operating system? Exactly what do you mean by "dangling link"? If your operating system has several kinds of links, which kind are you talking about?
Sorry that I did not explain my environment. The operating system is Linux. I am talking about symbolic links whose target was removed. Something like: touch xyz ln -s xyz dangling_link rm -f xyz
For example, on Windows 2K (and presumably other Windows variants), certain files like the pagefile can't even be queried by is_directory() without an exception being thrown.
Should the use of directory_iterator under certain circumstances force
Here I see a difference. One obtains a security_error when accessing the pagefile under Windows. This seems reasonable since users have no access rights for the pagefile. In the case of dangling links I obtain a not_found_error. This seems to be a contradiction. First I find something (and obtain an iterator) and without any interference from outside is_directory() tells me it cannot find the object. The problem is that directory_iterator refers to the link whereas is_directory() and the following exception refer to the target (which is missing). So by catching the not_found_error I am unable to distinguish these two cases: 1. Found a link but its target is missing 2. Found a file/directory but someone deleted it before is_directory() was called the
user to use the native operating system API?
Yes - in cases where there doesn't seem to be any way to abstract the operation into a portable function it is better to leave it for an operating system specific function.
I agree. What about adding a "non portable" error code for filesystem_error, something like missing_target_error? Okay, this would be an implicit is_link() function :-)
Wouldn't it be more consistent to skip links altogether when iterating?
I'm not sure. I am not sure as well.
Non-pathological links seem to work as expected, and operating systems often detect and report pathological cases as errors, which seems to me to be reasonable behavior. OTOH, links aren't an area that has received a lot of scrutiny, so it may be that some change is needed.
Dangling links may be pathological but they are perfectly legal as far as the OS and the filesystem is concerned (and they are always present when nobody expects it). So the only solution seems to be to add an is_link() function myself and check for the presence of the link target. Best regards, Peter.
Peter Klotz wrote:
Yes - in cases where there doesn't seem to be any way to abstract the operation into a portable function it is better to leave it for an operating system specific function.
I agree. What about adding a "non portable" error code for filesystem_error, something like missing_target_error? Okay, this would be an implicit is_link() function :-)
Both missing_target_error and is_link() look entirely reasonable to me. I see nothing non-portable here.
At 06:55 AM 4/22/2003, Peter Dimov wrote:
Peter Klotz wrote:
Yes - in cases where there doesn't seem to be any way to abstract the operation into a portable function it is better to leave it for an operating system specific function.
I agree. What about adding a "non portable" error code for filesystem_error, something like missing_target_error? Okay, this would be an implicit is_link() function :-)
Both missing_target_error and is_link() look entirely reasonable to me.
The portable error_code is just not_found_error, because some operating systems may not distinguish a broken link from other not found conditions. is_link() sounds promising, but we would have to survey more operating systems first to be sure. --Beman
Beman Dawes wrote:
At 06:55 AM 4/22/2003, Peter Dimov wrote:
Both missing_target_error and is_link() look entirely reasonable to me.
The portable error_code is just not_found_error, because some operating systems may not distinguish a broken link from other not found conditions.
Were missing_target_error and not_found_error exception _types_, you could derive one from the other. :-)
"Kris Braun"
Hi there,
I could really use the features provided by iterator adaptors part of the library, but I'm having a lot of trouble getting a nested set of adaptors to compile. In one case, I'd like to return an iterator into std::map< std::string, boost::shared_ptr< ApiOption > >, and have it return references to options in which option->isTemplate( ) is false. Conceptually, I'd like a filter_iterator->indirect_iterator-
projection_iterator chain.
I've been using this typedef to project onto the second member of the pair: typedef boost::projection_iterator_pair_generator< select_second< std::string, boost::shared_ptr< ApiOption > >, ^^^^^^^^^^^^^ Where is select_second defined with two template parameters?
OptionMap::iterator, OptionMap::const_iterator > OptionMapIterators;
Do you need both const and non-const iterators? If not, the pair_generator is probably overkill.
but I've been at a loss to add indirect_iterator and filter_iterator into the mix. Can anyone help me get unstuck?
I can't really tell what's going on here, but it looks like you
haven't got step 1 right. Maybe you should try to compile a test
program that just uses the projection you want.
Also, I don't think the existing iterator adaptor fulfills its promise
to work properly with smart pointers. I am sure that you can do it
(and more easily too) using the sandbox iterator adaptors if that's
an option for you.
// untested
filter_iterator<
std::logical_not<
boost::mem_fun_ref_t
, indirect_iterator<
transform_iterator<
select_second
HTH, -- Dave Abrahams Boost Consulting www.boost-consulting.com
participants (5)
-
Beman Dawes
-
David Abrahams
-
Kris Braun
-
Peter Dimov
-
Peter Klotz