diff --git a/doc/boost_range.html b/doc/boost_range.html index 41f4e81..ec65bdc 100644 --- a/doc/boost_range.html +++ b/doc/boost_range.html @@ -3,6 +3,7 @@
std::pair<iterator,iterator>
char[]
,wchar_t[]
,
char*
, and wchar_t*
)
std::pair<iterator,iterator>
- boost::array<>
anyway). Also note
that arrays and pointers of char
or whar_t
are
treated special because of their use in string algorithms.
-
-The concept is defined by the type-generators and the functions below. Even
+The concept is defined by the metafunction and the functions below. Even
though these functions are defined in namespace boost
, there is no
such general requirement, that is, if one wants to extend the list of supported
types, it can be done in any namespace.
+
- namespace boost - { - // - // type generators - // - - template< typename EC > - struct value_type_of - { - typedef ... type; // type of stored objects - }; - - template< typename EC > - struct iterator_of - { - typedef ... type; // iterator over stored objects - }; - - template< typename EC > - struct const_iterator_of - { - typedef ... type; // iterator over immutable stored objects - }; - - template< typename EC > - struct difference_type_of - { - typedef ... type; - BOOST_STATIC_ASSERT( boost::is_signed< type >::value ); - // - // remark: if std::iterator_traits<> works for the type, this assertion must - hold - // - BOOST_STATIC_ASSERT( boost::is_same< type, std::iterator_traits< typename - iterator_of< EC >::type >::difference_type>::value ); - }; - - template< typename EC > - struct size_type_of - { - typedef ... type; - BOOST_STATIC_ASSERT( boost::is_unsigned< type >::value ); - BOOST_STATIC_ASSERT( sizeof( type ) >= sizeof( - difference_type_of< EC >::type ) ); - }; - - template< typename EC > - struct result_iterator_of - { - typedef ... type; - // iterator_of< EC >::type if EC is non-const, - const_iterator_of< EC >::type otherwise - }; - - // - // funtions - // - - template< typename EC > - inline typename iterator_of+ template< class T > + inline typename iterator_of< T >::type + end( T& c ); + + template< class T > + inline typename const_iterator_of< T >::type + end( const T& c ); + + template< class T > + inline bool + empty( const T& c ); + + template< class T > + inline typename size_type_of< T >::type + size( const T& c ); + +} // namespace 'boost' diff --git a/doc/external_concepts.html b/doc/external_concepts.html index 98ccf90..f04671d 100644 --- a/doc/external_concepts.html +++ b/doc/external_concepts.html @@ -1,38 +1,123 @@ -::type - begin( EC& c ); +namespace boost +{ + // + // Range metafunctions + // - template< typename EC > - inline typename const_iterator_of< EC >::type - begin( const EC& c ); - - template< typename EC > - inline typename iterator_of< EC >::type - end( EC& c ); - - template< typename EC > - inline typename const_iterator_of< EC >::type - end( const EC& c ); + template< class T > + struct value_type_of + { + typedef ... type; // type of stored objTts + }; + + template< class T > + struct iterator_of + { + typedef ... type; // iterator over stored objects + }; + + template< class T > + struct const_iterator_of + { + typedef ... type; // iterator over immutable stored objects + }; + + template< class T > + struct difference_type_of + { + typedef ... type; + BOOST_STATIC_ASSERT( boost::is_signed< type >::value ); + // + // remark: if std::iterator_traits<> works for the type, this assertion must + hold + // + BOOST_STATIC_ASSERT( boost::is_same< type, std::iterator_traits< typename + iterator_of< T >::type >::difference_type>::value ); + }; + + template< class T > + struct size_type_of + { + typedef ... type; + BOOST_STATIC_ASSERT( boost::is_unsigned< type >::value ); + BOOST_STATIC_ASSERT( sizeof( type ) >= sizeof( + difference_type_of< T >::type ) ); + }; + + template< class T > + struct result_iterator_of + { + typedef ... type; + // iterator_of< T >::type if T is non-const, + const_iterator_of< T >::type otherwise + }; + + // + // funtions + // + + template< class T > + inline typename iterator_of ::type + begin( T& c ); + + template< class T > + inline typename const_iterator_of< T >::type + begin( const T& c ); - template< typename EC > - inline bool - empty( const EC& c ); - - template< typename EC > - inline typename size_type_of< EC >::type - size( const EC& c ); - - } // namespace 'boost'
![]() | Concepts and External Concepts |
Generic programming in C++ is characterized by the use of function and class templates where - the template parameter(s) must satisfy certain requirements.Often these - requirements are so important that we give them a name: we call - such a set of type requirements a concept. We say that a type - conforms to a concept or that it is a model of a concept if it - satisfies all of those requirements. The concept can be specified as a set - of member functions with well-defined semantics - and a set of nested typedefs with well-defined properties.
Often it much more flexible to provide free-standing functions and typedefs - which provides the exact same semantics (but a different syntax) as - specified - by the concept. This allows generic code to treat different types as if - they fulfilled the concept. In this case we say that the concept has - been externalized or that the new requirements constitutes an external - concept . We say that a type conforms to an external concept - or that it is a model of an external concept . A concept may exist - without a corresponding external concept and conversely.
Whenever a concept specifies a member function, the corresponding external
- concept
- must specify a free-standing function of the same name, same return type and
- the same argument list except there is an extra first argument which must
- be of the type (or a reference to that type) that is to fulfill the external
- concept. If the corresonding member function has any cv-qulifiers, the
- first argument must have the same cv-qualifiers. Whenever a concept
- specifies a nested typedef, the corresponding external concept
- specifies a type-generator, that is, a type with a nested typedef
- named type
. The type-generator has the name as the nested typedef with
- _of
appended.
- The converse relationship of an external concept and its corresponding concept
- also holds.
Example:
A type T
fulfills the FooConcept if it
- has the follwing public members:
void T::foo( int ) const;
- int T::bar();
- typedef implementation defined foo_type;
The corresponding external concept is the ExternalFooConcept.
A type T
fullfills the ExternalFooConcept if these
- free-standing functions and type-generators exists:
void foo( const T&, int );
- int bar( T& );
- foo_type_of< T >::type;
© Thorsten Ottosen 2003-2004 (nesotto_AT_cs.auc.dk). - Permission to copy, use, modify, sell and distribute this software is granted provided this copyright notice appears - in all copies. This software is provided "as is" without express or implied warranty, and with no - claim as to its suitability for any purpose.
![]() |
+ Concepts and External Concepts |
+
+Generic programming in C++ is characterized by the use of function and class +templates where the template parameter(s) must satisfy certain requirements.Often +these requirements are so important that we give them a name: we call such a set +of type requirements a concept. We say that a type conforms to a +concept or that it is a model of a concept if it satisfies all of +those requirements. The concept can be specified as a set of member functions +with well-defined semantics and a set of nested typedefs with well-defined +properties. +
++Often it much more flexible to provide free-standing functions and typedefs +which provides the exact same semantics (but a different syntax) as specified by +the concept. This allows generic code to treat different types as if they +fulfilled the concept. In this case we say that the concept has been externalized + or that the new requirements constitutes an external concept . We +say that a type conforms to an external concept or that it is a model +of an external concept . A concept may exist without a corresponding +external concept and conversely. +
+
+Whenever a concept specifies a member function, the corresponding external
+concept must specify a free-standing function of the same name, same return type
+and the same argument list except there is an extra first argument which must be
+of the type (or a reference to that type) that is to fulfill the external
+concept. If the corresonding member function has any cv-qulifiers, the first
+argument must have the same cv-qualifiers. Whenever a concept specifies a nested
+typedef, the corresponding external concept specifies a metafunction,
+that is, a type with a nested typedef named type
. The metafunction
+has the name as the nested typedef with _of
appended. The converse
+relationship of an external concept and its corresponding concept also holds.
+
+Example: +
+
+A type T
fulfills the FooConcept if it has the follwing public
+members:
+
void T::foo( int ) const;
+int T::bar();
+typedef implementation defined foo_type;
++The corresponding external concept is the ExternalFooConcept. +
+
+A type T
fullfills the ExternalFooConcept if these free-standing
+functions and metafunctions exists:
+
void foo( const T&, int );
+int bar( T& );
+foo_type_of< T >::type;
+© Thorsten Ottosen 2003-2004 (nesotto_AT_cs.auc.dk). Permission to copy, +use, modify, sell and distribute this software is granted provided this +copyright notice appears in all copies. This software is provided "as is" +without express or implied warranty, and with no claim as to its suitability for +any purpose. +
+-
iterator_of<C>::type
and const_iterator_of<C>::type
- for std::pair<iterator, iterator>
.
+ Why is there no difference between iterator_of<C>::type
+ and const_iterator_of<C>::type
for std::pair<iterator,
+ iterator>
.
In general it is not possible nor desirable to find a corresponding const_iterator
.
@@ -30,24 +30,71 @@
object.
- The library have been kept small because its current interface will serve - most purposes. If and when a genuine need arises for more functionality, it can - be implemented. + The library have been kept small because its current interface will serve most + purposes. If and when a genuine need arises for more functionality, it can be + implemented.
- One should always start with a generic algorithm that takes two - iterators (or more) as - input. Then use Boost.Range to build handier versions on top of the - iterator based algorithm. Please notice that once the range version - of the algorithm is done, it makes sense not to expose the - iterator version in the public interface. + One should always start with a generic algorithm that takes two iterators (or + more) as input. Then use Boost.Range to build handier versions on top of the + iterator based algorithm. Please notice that once the range version of the + algorithm is done, it makes sense not to expose the iterator version in + the public interface.
+ Even though we speak of incrementable iterators, it would not make + much sense for ranges; for example, we cannot determine the size and + emptiness of a range since we cannot even compare + its iterators. +
++ instead of +boost::begin( r );
++ when calling functions in this library? If so, can I still rely on argument + dependent lookup (ADL) to kick in? +using namespace boost; +begin( r )
+ The answer to the first question is that "it's up to you". The + answer to the second question is Yes. Normally qualified syntax + disables ADL, but the functions are implemented in a special + manner that preserves ADL properties. The trick was explained by + Daniel Frey on comp.lang.std.c++ in the thread "Whence Swap" and + it is best explained by some code:
++ ++namespace boost +{ + namespace range_detail + { + template< class T > + typename iterator_of<T>:type begin( T& r ) + { /* normal implementation */ } + } + + template< class T > + typename iterator_of<T>::type begin( T& r ) + { + // + // Create ADL hook + // + using range_detail::begin; + return begin( r ); + } +}+
<boost/range.hpp>
<boost/range/types.hpp>
<boost/range/metafunctions.hpp>
<boost/range/functions.hpp>
<boost/range/value_type.hpp>
<boost/range/iterator.hpp>
<boost/range/const_iterator.hpp>
<boost/range/difference_type.hpp>
<boost/range/size_type.hpp>
<boost/range/result_iterator.hpp>
<boost/range/reverse_iterator.hpp>
<boost/range/const_reverse_iterator.hpp>
<boost/range/reverse_result_iterator.hpp>
<boost/range/begin.hpp>
<boost/range/end.hpp>
<boost/range/empty.hpp>
<boost/range/size.hpp>
<boost/range/rbegin.hpp>
<boost/range/rend.hpp>
<boost/range/iterator_range.hpp>
<boost/range/sub_range.hpp>
- Meanwhile work on container algorithms in various context showed the + Meanwhile work on algorithms for containers in various contexts showed the need for handling pairs of iterators, and string libraries needed special - treatment of character arrays. -
+ treatment of character arrays. In the end it made sense to formalize the + minimal requirements of these similar concepts. And the results are the + Range concepts found in this library. + +
+ The term Range was adopted because of paragraph 24.1/7
from the
+C++ standard:
+ Most of the library's algorithmic templates that operate on data + structures have interfaces that use ranges. A range is a pair of + iterators that designate the beginning and end of the computation. A + range [i, i) is an empty range; in general, a range [i, j) refers to + the elements in the data structure starting with the one pointed to + by i and up to but not including the one pointed to by j. Range [i, + j) is valid if and only if j is reachable from i. The result of the + application of functions in the library to invalid ranges is + undefined. +
Special thanks goes to diff --git a/doc/intro.html b/doc/intro.html index eadca07..e65c7d1 100755 --- a/doc/intro.html +++ b/doc/intro.html @@ -18,22 +18,32 @@
+ When writing generic code that works with Standard Library containers, one often
+ finds it desirable to extend that code to work with other types that offer
+ enough functionality to satisfy the needs of the generic code, but in an altered
+ form. For example, raw arrays are often suitable for use with generic code that
+ works with containers, provided a suitable adapter is used. Likewise, null
+ terminated strings can be treated as containers of characters, if suitably
+ adapted. This library provides the means to adapt Standard Library containers,
+ null terminated strings, std::pairs
of iterators, and raw
+arrays, such that the same generic code can work with them all.
+
The main advantages are
Below are given a small example (the complete example can be found here ): -
++ + + By using the free-standing functions and metafunctions, the code automatically works for all the types supported by this library. Notice that we have to provide two version of++ // + // example: extracting bounds in a generic algorithm + // + template< typename ForwardRange, typename T > + inline typename boost::iterator_of< ForwardRange >::type + find( ForwardRange& c, const T& value ) + { + return std::find( boost::begin( c ), boost::end( c ), value ); + } + + template< typename ForwardRange, typename T > + inline typename boost::const_iterator_of< ForwardRange >::type + find( const ForwardRange& c, const T& value ) + { + return std::find( boost::begin( c ), boost::end( c ), value ); + } + + // + // replace first value and return its index + // + template< class ForwardRange, class T > + inline typename boost::size_type_of< ForwardRange >::type + my_generic_replace( ForwardRange& c, const T& value, const T& replacement ) + { + typename boost::iterator_of< ForwardRange >::type found = find( c, value ); - // - // Example: extracting bounds in generic algorithms - // - - template< typename XRange, typename T > - inline typename boost::iterator_of<XRange>::type - find( XRange& c, const T& value ) - { - return std::find( boost::begin( c ), boost::end( c ), value ); - } - - template< typename XRange, typename T > - inline typename boost::const_iterator_of<XRange>::type - find( const XRange& c, const T& value ) - { - return std::find( boost::begin( c ), boost::end( c ), value ); - } - - // - // replace first value and return its index - // - template< typename EC, typename T > - inline typename boost::size_type_of< EC >::type - my_generic_replace( EC& c, const T& value, const T& replacement ) - { - typename boost::const_iterator_of<EC>::type found = find( c, value ); + if( found != boost::end( c ) ) *found = replacement; - return std::distance( boost::begin( c ), found ); - } - - // - // usage - // - std::vector<int> my_vector; - typedef vector<int>::iterator iterator; - std::pair<iterator,iterator> my_view( my_vector.begin(), my_vector.begin( - ) + N ); - char str[] = "a string"; - // ... - std::cout << my_generic_replace( my_vector, 4, 2 ) - << my_generic_replace( my_view, 4, 2 ) - << my_generic_replace( str, 'a', 'b' ); -+ return std::distance( boost::begin( c ), found ); + } - By using the free-standing functions and type-generators, the code automatically + // + // usage + // + const int N = 5; + std::vectormy_vector; + int values[] = { 1,2,3,4,5,6,7,8,9 }; + my_vector.assign( values, values + 9 ); + typedef std::vector ::iterator iterator; + std::pair my_view( boost::begin( my_vector ), + boost::begin( my_vector ) + N ); + char str_val[] = "a string"; + char* str = str_val; + + std::cout << my_generic_replace( my_vector, 4, 2 ) + << my_generic_replace( my_view, 4, 2 ) + << my_generic_replace( str, 'a', 'b' ); + +
find()
since we cannot forward a non-const
rvalue with reference arguments (see this article about The
diff --git a/doc/portability.html b/doc/portability.html
index 92ee98a..2d61ffd 100755
--- a/doc/portability.html
+++ b/doc/portability.html
@@ -20,7 +20,7 @@
Full support for built-in arrays require that the compiler supports class template partial specialization. For non-conforming compilers there might - be a change that it works anyway thanks to workarounds in the type traits + be a chance that it works anyway thanks to workarounds in the type traits library.
Notice that some compilers cannot do function template ordering properly. In diff --git a/doc/range.htm b/doc/range.htm index c4308ed..42c5864 100755 --- a/doc/range.htm +++ b/doc/range.htm @@ -16,318 +16,454 @@ -
![]() |
- Boost.Range |
-
![]() |
+ Boost.Range |
+
+ A Range is a concept similar to the STL Container concept. A
+ Range provides iterators for accessing a closed-open range
+[first,one_past_last)
of elements and provides
+ information about the number of elements in the Range. However, a Range has
+ fewer requirements than a Container.
+
+ The motivation for the Range concept is + that there are many useful Container-like types that do not meet the full + requirements of Container, and many algorithms that can be written with this + reduced set of requirements. In particular, a Range does not necessarily -A Range is a concept similar to the STL Container concept. A -Range provides iterators for accessing a range of elements and provides -information about the number of elements in the Range. However, a Range has -fewer requirements than a Container. The motivation for the Range concept is -that there are many useful Container-like types that do not meet the full -requirements of Container, and many algorithms that can be written with this -reduced set of requirements. In particular, a Range does not necessarily +
+ The operations that can be performed on a Range is dependent on the + traversal +category of the underlying iterator type. Therefore + the range concepts are named to reflect which traversal category its + iterators support. See also terminology and style guidelines. + for more information about naming of ranges.
+ +-
+
-X | -A type that is a model of Range. | -
a, b | -Object of type X. | -
T | -The value type of X. | -
Value type | -value_type_of<X>::type | -The type of the object stored in a Range. - |
Iterator type | -iterator_of<X>::type | -The type of iterator used to iterate through a Range's elements. - The iterator's value type is expected to be the Range's value type. A - conversion from the iterator type to the const iterator type must exist. The - iterator type must at least be an InputIterator. | -
Const iterator type | -const_iterator_of<X>::type | -A type of iterator that may be used to examine, but not to - modify, a Range's elements. | -
Reference type | -reference_of<X>::type | -A type that behaves like a reference to the Range's value type. [1] | -
Distance type | -difference_type_of<>::type | -A signed integral type used to represent the distance between - two of the Range's iterators. This type must be the same as the iterator's - distance type. | -
Size type | -size_type_of<X>::type | -An unsigned integral type that can represent any nonnegative - value of the Range's distance type. | -
- -
Name | -Expression | -Return type | -
---|---|---|
Beginning of range | -begin(a) | -iterator if a is mutable, const_iterator - otherwise | -
End of range | -end(a) | -iterator if a is mutable, const_iterator - otherwise | -
Size of range | -size(a) | -size_type | -Is range empty? | -empty(a) | -Convertible to bool | - -
Expression | -Semantics | -Postcondition | -
+ Notation+
Description+
+ A range X where Associated types+ +
Valid expressions+ + The following expressions must be valid. ++ +
Expression semantics+ +
Complexity guarantees+ + All three functions are at most amortized linear time. For most practical + purposes, one can expectbegin(a) , end(a) and empty(a)
+ to be amortized constant time.
+
+ Invariants+
See also++ Container + + ++ Forward Range+ +Notation+
| ||
---|---|---|---|---|---|
a |
+ Object of type X . |
+
+ A range X
where iterator_of<X>::type
is a model
+of Forward Traversal Iterator
+
Valid range | -For any Range a, [begin(a),end(a)) is a
- valid range, that is, end(a) is reachable from begin(a)
- in a finite number of increments. |
-
Range size | -size(a) is equal to the distance from -begin(a) to end(a). | -
Completeness | -An algorithm that iterates through the range -[begin(a),end(a)) will pass through every element of a. | -
Distance type | +difference_type_of<X>::type |
+ A signed integral type used to represent the distance between + two of the Range's iterators. This type must be the same as the iterator's + distance type. | +
Size type | +size_type_of<X>::type |
+ An unsigned integral type that can represent any nonnegative + value of the Range's distance type. | +
Name | +Expression | +Return type | +
---|---|---|
Size of range | +size(a) |
+ size_type |
+
Expression | +Semantics | +Postcondition | +
---|---|---|
size(a) |
+ Returns the size of the Range, that is, its number
+of elements. Note size(a) == 0u is equivalent to
+empty(a). |
+ size(a) >= 0 |
+
size(a)
is at most amortized linear time.
+
Range size | +size(a) is equal to the distance from begin(a)
+ to end(a) . |
X |
+ A type that is a model of Bidirectional Range. | +
a |
+ Object of type X . |
+
iterator_of<X>::type
iterator must meet all of the requirements
+of Bidirectional Traversal Iterator.
+
+ Reverse Iterator type | +reverse_iterator_of<X>::type |
+ The type of iterator used to iterate through a Range's elements + in reverse order. The iterator's value type is expected to be the Range's value + type. A conversion from the reverse iterator type to the const reverse iterator + type must exist. | +
Const reverse iterator type | +const_reverse_iterator_of<X>::type |
+ A type of reverse iterator that may be used to examine, but not + to modify, a Range's elements. | +
All models of Container
- Name | +Expression | +Return type | +Semantics | +
---|---|---|---|
Beginning of range | +rbegin(a) |
+ reverse_iterator_of<X>::type if
+a is mutable, const_reverse_iterator_of<X>::type
+otherwise. |
+ Equivalent to
+reverse_iterator_of<X>::type(end(a)) . |
End of range | +rend(a) |
+ reverse_iterator_of<X>::type if
+a is mutable, const_reverse_iterator_of<X>::type
+otherwise. |
+ Equivalent to
+reverse_iterator_of<X>::type(begin(a)) . |
rbegin(a)
has the same complexity as end(a)
and rend(a)
+ has the same complexity as begin(a)
from Forward Range.
+
+ +
Valid reverse range | +For any Bidirectional Range a , [rbegin(a),rend(a))
+ is a valid range, that is, rend(a) is reachable from rbegin(a)
+ in a finite number of increments. |
+
Completeness | +An algorithm that iterates through the range [rbegin(a),rend(a))
+ will pass through every element of a . |
+
+ A range X
where iterator_of<X>::type
is a model
+of Random Access Traversal Iterator
+
Copyright © 2000 | +Jeremy Siek + |
Copyright © 2004 | +Thorsten Ottosen. + |
Name | -Expression | -Return type | -Semantics | -
---|---|---|---|
Beginning of range | -rbegin(a) | -reverse_iterator if a is mutable, const_reverse_iterator - otherwise. | -Equivalent to X::reverse_iterator(end(a)). |
End of range | -rend(a) | -reverse_iterator if a is mutable, const_reverse_iterator - otherwise. | -Equivalent to -X::reverse_iterator(begin(a)). |
-[1]
-
-The reference type does not have to be a real C++ reference. The requirements of
-the reference type is that it behaves like a real reference. Hence the
-reference type must be convertible to the value_type and assignment through
-
-
-
-
Copyright © 2000 | -Jeremy Siek - |
Copyright © 2004 | -Thorsten Ottosen. - |