Boost logo

Boost :

Subject: [boost] [range] strings
From: Domagoj Saric (domagoj.saric_at_[hidden])
Date: 2010-03-08 06:36:41


Currently, the following assertion:
    char const test_string[] = "a test string";
    assert( test_string == boost::as_literal( test_string ) );
fails while the following one:
    assert( test_string == boost::as_literal( test_string ).advance_end( 1 ) );
passes because the left-hand side parameter of operator== is implicitly
converted to a boost::iterator_range<> object which _includes_ the trailing zero
(because it is treated as any other array) while the boost::iterator_range<>
returned by boost::as_literal<>() _excludes_ the trailing zero...

I 'know' that there is no 'happy' solution for this because the status quo is
'consistent' across all types but it, on the other hand, creates problems (or
unexpected results), like the one outlined above, when strings, char pointers
and literals are used...For this reason I would prefer more the other 'less than
happy' solution that would treat strings in a special way (by never including
the trailing zero)...

Another problem is that the conversion, implict or otherwise, from a char
container/range whose iterators are not plain char pointers (e.g. std::strings
in 'secure STL' implementations) does not work (does not compile). My last post
in the [program_options] thread offers a 'fix'.

Yet another problem is that the as_literal<>() template function does not use
the fact that it was passed an array to implicitly/directly deduce the length
but it still calls std::strlen(). The make_range() function it calls for that:
make_range( T* const r, bool )
{
    return iterator_range<T*>( r, r + length(r) );
}
is also duplicated by:
inline const char* str_end( const char* s, const char* )
{
    return s + strlen( s );
}
...

Yes, some will object that the 'desired' direct deduction of length would be
broken for 'typical' local buffers that are not completely filled (if there is
no clear way of distinguishing them from literals):
void foo()
{
    char buf[ 256 ] = "a small string";
    as_literal( buf ).size() == std::strlen( buf ); // in status quo
    as_literal( buf ).size() == _countof( buf ) - 1; // as proposed
}
but that could then also be said for the current implict conversion from such a
"char buf[ 256 ]" into a boost::iterator_range<char const*>...
I'd vote that this be handled with a runtime assertion that if a plain char
array is passed it must be 'completely filled' (i.e. strlen( buf ) ==
_countof( buf ) ) otherwise the range must be explicitly constructed
(iterator_range<char const *>( buf, buf + actual length )...

Additionaly the above mentioned implementations of make_range() and str_end()
add two extra instructions (substraction and addition) because they use strlen()
that works with 'indexes'/size which then have to be converted to pointers...

Additionaly#2 the boost::range_detail::is_char_ptr() function in as_literal.hpp
is a runtime function when it seems it could be a metafunction...

--
"What Huxley teaches is that in the age of advanced technology, spiritual
devastation is more likely to come from an enemy with a smiling face than from
one whose countenance exudes suspicion and hate."
Neil Postman 

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk