BOOST_FOREACH

[SVN r30683]
This commit is contained in:
Eric Niebler
2005-08-26 03:43:30 +00:00
commit 2258532c5e
20 changed files with 1866 additions and 0 deletions
+96
View File
@@ -0,0 +1,96 @@
* text=auto !eol svneol=native#text/plain
*.gitattributes text svneol=native#text/plain
# Scriptish formats
*.bat text svneol=native#text/plain
*.bsh text svneol=native#text/x-beanshell
*.cgi text svneol=native#text/plain
*.cmd text svneol=native#text/plain
*.js text svneol=native#text/javascript
*.php text svneol=native#text/x-php
*.pl text svneol=native#text/x-perl
*.pm text svneol=native#text/x-perl
*.py text svneol=native#text/x-python
*.sh eol=lf svneol=LF#text/x-sh
configure eol=lf svneol=LF#text/x-sh
# Image formats
*.bmp binary svneol=unset#image/bmp
*.gif binary svneol=unset#image/gif
*.ico binary svneol=unset#image/ico
*.jpeg binary svneol=unset#image/jpeg
*.jpg binary svneol=unset#image/jpeg
*.png binary svneol=unset#image/png
*.tif binary svneol=unset#image/tiff
*.tiff binary svneol=unset#image/tiff
*.svg text svneol=native#image/svg%2Bxml
# Data formats
*.pdf binary svneol=unset#application/pdf
*.avi binary svneol=unset#video/avi
*.doc binary svneol=unset#application/msword
*.dsp text svneol=crlf#text/plain
*.dsw text svneol=crlf#text/plain
*.eps binary svneol=unset#application/postscript
*.gz binary svneol=unset#application/gzip
*.mov binary svneol=unset#video/quicktime
*.mp3 binary svneol=unset#audio/mpeg
*.ppt binary svneol=unset#application/vnd.ms-powerpoint
*.ps binary svneol=unset#application/postscript
*.psd binary svneol=unset#application/photoshop
*.rdf binary svneol=unset#text/rdf
*.rss text svneol=unset#text/xml
*.rtf binary svneol=unset#text/rtf
*.sln text svneol=native#text/plain
*.swf binary svneol=unset#application/x-shockwave-flash
*.tgz binary svneol=unset#application/gzip
*.vcproj text svneol=native#text/xml
*.vcxproj text svneol=native#text/xml
*.vsprops text svneol=native#text/xml
*.wav binary svneol=unset#audio/wav
*.xls binary svneol=unset#application/vnd.ms-excel
*.zip binary svneol=unset#application/zip
# Text formats
.htaccess text svneol=native#text/plain
*.bbk text svneol=native#text/xml
*.cmake text svneol=native#text/plain
*.css text svneol=native#text/css
*.dtd text svneol=native#text/xml
*.htm text svneol=native#text/html
*.html text svneol=native#text/html
*.ini text svneol=native#text/plain
*.log text svneol=native#text/plain
*.mak text svneol=native#text/plain
*.qbk text svneol=native#text/plain
*.rst text svneol=native#text/plain
*.sql text svneol=native#text/x-sql
*.txt text svneol=native#text/plain
*.xhtml text svneol=native#text/xhtml%2Bxml
*.xml text svneol=native#text/xml
*.xsd text svneol=native#text/xml
*.xsl text svneol=native#text/xml
*.xslt text svneol=native#text/xml
*.xul text svneol=native#text/xul
*.yml text svneol=native#text/plain
boost-no-inspect text svneol=native#text/plain
CHANGES text svneol=native#text/plain
COPYING text svneol=native#text/plain
INSTALL text svneol=native#text/plain
Jamfile text svneol=native#text/plain
Jamroot text svneol=native#text/plain
Jamfile.v2 text svneol=native#text/plain
Jamrules text svneol=native#text/plain
Makefile* text svneol=native#text/plain
README text svneol=native#text/plain
TODO text svneol=native#text/plain
# Code formats
*.c text svneol=native#text/plain
*.cpp text svneol=native#text/plain
*.h text svneol=native#text/plain
*.hpp text svneol=native#text/plain
*.ipp text svneol=native#text/plain
*.tpp text svneol=native#text/plain
*.jam text svneol=native#text/plain
*.java text svneol=native#text/plain
Executable
+8
View File
@@ -0,0 +1,8 @@
# Copyright Eric Niebler 2005. Use, modification, and distribution are
# subject to the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
using quickbook ;
xml foreach : foreach.qbk ;
boostbook standalone : foreach ;
+386
View File
@@ -0,0 +1,386 @@
[library Boost.Foreach
[authors [Niebler, Eric]]
[copyright 2004 Eric Niebler]
[category algorithms]
[purpose
foreach looping construct, for writing simple loops over STL containers,
null-terminated strings, arrays, iterator pairs and user defined types.
]
[id foreach]
[dirname foreach]
[license
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
<ulink url="http://www.boost.org/LICENSE_1_0.txt">
http://www.boost.org/LICENSE_1_0.txt
</ulink>)
]
]
[/ QuickBook Document version 1.0 ]
[/ Images ]
[def _note_ [$images/note.png]]
[def _alert_ [$images/caution.png]]
[def _detail_ [$images/note.png]]
[def _tip_ [$images/tip.png]]
[/ Links ]
[def _iterator_ [@../../libs/iterator/doc/index.html Boost.Iterator]]
[def _range_ [@../../libs/range/index.html Boost.Range]]
[def _iterator_range_ [@../../libs/range/doc/utility_class.html#iter_range `boost::iterator_range<>`]]
[def _sub_range_ [@../../libs/range/doc/utility_class.html#sub_range `boost::sub_range<>`]]
[def _foreach_ `BOOST_FOREACH`]
[section Introduction]
[:"Make simple things easy."]
[:[*['-- Larry Wall]]]
[h2 What is _foreach_?]
In C++, writing a loop that iterates over a sequence is tedious. You can either
use iterators, which requires a considerable amount of boiler-plate, or you can
use the `std::for_each()` algorithm and move your loop body into a predicate, which
requires no less boiler-plate and forces you to move your logic far from where
it will be used. In contrast, some other languages, like Perl, provide a dedicated
"foreach" construct that automates this process. _foreach_ is just such a construct
for C++. It iterates over sequences for you, freeing you from having to deal directly
with iterators or write predicates.
_foreach_ is designed for ease-of-use and efficiency. It does no dynamic allocations,
makes no virtual function calls or calls through function pointers, and makes no calls
that are not transparent to the compiler's optimizer. This results in near-optimal code
generation; the performance of _foreach_ is usually within a few percent of the
equivalent hand-coded loop. And although _foreach_ is a macro, it is a remarkably
well-behaved one. On modern compilers, it evaluates its arguments exactly once, leading
to no nasty surprises.
[h2 Hello, world!]
Below is a sample program that uses _foreach_ to loop over the contents of
a null-terminated C-style string.
#include <iostream>
#include <boost/foreach.hpp>
int main()
{
BOOST_FOREACH( char ch, "Hello, world!" )
{
std::cout << ch;
}
return 0;
}
This program outputs the following:
[pre
Hello, world!
]
[h2 Supported Sequence Types]
_foreach_ iterates over sequences. But what qualifies as a sequence, exactly? Since
_foreach_ is built on top of _range_, it automatically supports those types which
_range_ recognizes as sequences. In particular, you can use _foreach_ with:
* STL containers
* arrays
* Null-terminated strings (`char` and `wchar_t`)
* std::pair of iterators
[blurb _note_ The support for STL containers is very general; anything that looks like
an STL container counts. If it has nested `iterator` and `const_iterator` types and `begin()`
and `end()` member functions, _foreach_ will automatically know how to iterate over
it. It is in this way that _iterator_range_ and _sub_range_ work with _foreach_.]
See the section on [link boost_foreach.extending_boost_foreach Extending _foreach_] to find
out how to make _foreach_ work with other types.
[h2 Examples]
Below are some examples that demonstrate all the different ways you can use _foreach_.
Iterate over an STL container:
std::list<int> list_int( /*...*/ );
BOOST_FOREACH( int i, list_int )
{
// do something with i
}
Iterate over an array, with covariance (i.e., the type of the iteration variable is
not exactly the same as the element type of the container):
short array_short[] = {1,2,3};
BOOST_FOREACH( int i, array_short )
{
// The short was implicitly converted to an int
}
Predeclare the loop variable, and use `break`, `continue`, and `return` in the loop body:
std::deque<int> deque_int( /*...*/ );
int i = 0;
BOOST_FOREACH( i, deque_int )
{
if(i==0) return;
if(i==1) continue;
if(i==2) break;
}
Iterate over a sequence by reference, and modify the underlying sequence:
short array_short[] = {1,2,3};
BOOST_FOREACH( short & i, array_short )
{
++i;
}
// array_short contains {2,3,4} here
Iterate over a vector of vectors with nested _foreach_ loops. In this
example, notice that braces around the loop body are not necessary:
std::vector<std::vector<int> > matrix_int;
BOOST_FOREACH( std::vector<int> & row, matrix_int )
BOOST_FOREACH( int & i, row )
++i;
Iterate over an expression that returns a sequence by value (i.e. an r-value):
extern std::vector<float> get_vector_float();
BOOST_FOREACH( float f, get_vector_float() )
{
// Note: get_vector_float() will be called exactly once
}
Iterating over r-values doesn't work on some older compilers. Check the
[link boost_foreach.portability Portability] section to see whether your
compiler supports this.
[h2 Making _foreach_ Prettier]
People have complained about the name _foreach_. It's too long. `ALL CAPS` can
get tiresome to look at. That may be true, but _foreach_ is merely following
the [@http://www.boost.org/more/lib_guide.htm Boost Naming Convention]. That
doesn't mean you're stuck with it, though. If you would like to use a different
identifier (`foreach`, perhaps), you can simply do:
#define foreach BOOST_FOREACH
Only do this if you are sure that the identifier you choose will not cause
name conflicts in your code.
[blurb _note_ Do not use `#define foreach(x,y) BOOST_FOREACH(x,y)`.
This can be problematic if the arguments are macros themselves. This would
result in an additional expansion of these macros. Instead, use the
form shown above.]
[endsect]
[section Extending BOOST_FOREACH]
If you want to use _foreach_ to iterate over some new collection type, you must
"teach" _foreach_ how to interact with your type. Since _foreach_ is built on top
of _range_, you must extend _range_ in order to extend _foreach_.
Below is an example for extending _foreach_ to iterate over a type which wraps a
`std::string`.
struct StringWrapper
{
std::string str;
};
namespace boost
{
// specialize rannge_iterator and range_const_iterator
template<>
struct range_iterator<StringWrapper>
{
typedef std::string::iterator type;
};
template<>
struct range_const_iterator<StringWrapper>
{
typedef std::string::const_iterator type;
};
// Overload begin() and end(), both const and non-const versions
std::string::iterator begin(StringWrapper & w) { return w.str.begin(); }
std::string::iterator end(StringWrapper & w) { return w.str.end(); }
std::string::const_iterator begin(StringWrapper const & w) { return w.str.begin(); }
std::string::const_iterator end(StringWrapper const & w) { return w.str.end(); }
}
Now that you have taught _range_ (and hence _foreach_) about your type, you
can now use _foreach_ to iterate over your type.
StringWrapper my_string_wrapper;
BOOST_FOREACH( char ch, my_string_wrapper )
{
// Woo-hoo!
}
There are some portability issues you should be aware of when extending _foreach_. Be sure
to check out the [link boost_foreach.portability Portability] section.
[endsect]
[section Pitfalls]
This section describes some common pitfalls with _foreach_.
[h2 Types With Commas]
Since _foreach_ is a macro, it must have exactly two arguments, with exactly one
comma separating them. That's not always convenient, especially when the type of the
loop variable is a template. Consider trying to iterate over a `std::map`:
std::map<int,int> m;
// ERROR! Too many arguments to BOOST_FOREACH macro.
BOOST_FOREACH(std::pair<int,int> p, m) // ...
One way to fix this is with a typedef.
std::map<int,int> m;
typedef std::pair<int,int> pair_t;
BOOST_FOREACH(pair_t p, m) // ...
Another way to fix it is to predeclare the loop variable:
std::map<int,int> m;
std::pair<int,int> p;
BOOST_FOREACH(p, m) // ...
[h2 Hoisting and Iterator Invalidation]
Under the covers, _foreach_ uses iterators to traverse the element
sequence. Before the loop is executed, the end iterator is cached
in a local variable. This is called ['hoisting], and it is an
important optimization. It assumes, however, that the end iterator
of the sequence is stable. It usually is, but if you modify the
sequence by adding or removing elements while you are iterating
over it, you may end up hoisting yourself on your on petard.
Consider the following code:
std::vector<int> vect(4, 4);
BOOST_FOREACH(int i, vect)
{
vect.push_back(i + 1);
}
This code will compile, but it has undefined behavior. That is because
it is logically equivalent to the following:
std::vector<int> vect(4, 4);
for(std::vector<int>::iterator i1 = vect.begin(), i2 = vect.end();
i1 != i2; ++i1)
{
int i = *i1;
vect.push_back(i + 1);
}
The call to `vect.push_back()` will cause all iterators into `vect` to
become invalid, including `i1` and `i2`. The next iteration through
the loop will cause the invalid iterators to be used -- Blam-o! Bad news.
The moral of the story is to think twice before adding and removing
elements from the sequence over which you are iterating. If doing
so could cause iterators to become invalid, don't do it. Use a regular
`for` loop instead.
[endsect]
[section Portability]
_foreach_ uses some fairly sophisticated techniques that not all compilers support. Depending
on how compliant your compiler is, you may not be able to use _foreach_ in some scenarios. Since
_foreach_ uses _range_, it inherits _range_'s portability issues. You can read about those
issues in that library's [@../../libs/range/doc/portability.html Portability]
section.
In addition to the demands placed on the compiler by _range_, _foreach_ places additional demands
in order to handle r-value sequences properly. (Recall that an r-value is an unnamed object, so
an example of an r-value sequence would be a function that returns a `std::vector<>` by value.) Compilers
vary in their handling of r-values and l-values. To cope with the situation _foreach_ defines three
levels of compliance, described below:
[table BOOST_FOREACH Compliance Levels
[[Level] [Meaning]]
[[*Level 0*] [['[_Highest level of compliance]]\n
_foreach_ works with l-values, r-values and const-qualified r-values.]]
[[*Level 1*] [['[_Moderate level of compliance]]\n
_foreach_ works with l-values and plain r-values, but not const-qualified r-values.\n
`BOOST_FOREACH_NO_CONST_RVALUE_DETECTION` is defined in this case.]]
[[*Level 2*] [['[_Lowest level of compliance]]\n
_foreach_ works with l-values only, not r-values.\n
`BOOST_FOREACH_NO_RVALUE_DETECTION` is defined in this case.]]
]
Below are the compilers _foreach_ has been tested with, and the compliance level you can expect
from each.
[table Compiler Compliance Level
[[Compiler] [Compliance Level]]
[[Visual C++ 7.1] [Level 1]]
[[Visual C++ Whidbey Beta] [Level 1]]
[[Visual C++ 7.0] [Level 2]]
[[Visual C++ 6.0] [Level 2]]
[[gcc 3.3.3] [Level 0]]
[[Intel for Windows 8.0] [Level 1]]
[[Intel for Windows 7.0] [Level 2]]
[[Comeau 4.3.3] [Level 0]]
[[Borland 5.6.4] [Level 2]]
]
Also, if your compiler is one for which the Boost config system defines `BOOST_NO_FUNCTION_TEMPLATE_ORDERING`,
then the compliance level for the _foreach_ macro is Level 2, the lowest.
[endsect]
[section History and Acknowledgements]
[h2 History]
The ideas for _foreach_ began life in the Visual C++ group at Microsoft during the early phases of
the design for C++/CLI. Whether to add a dedicated "foreach" looping construct to the language was
an open question at the time. As a mental exercise, Anson Tsao sent around some proof-of-concept
code which demonstrated that a pure library solution might be possible. The code was written in the
proposed C++/CLI dialect of the time, for which there was no compiler as of yet. I was intrigued by
the possibility, and I ported his code to Managed C++ and got it working. We worked together to
refine the idea and eventually published an article about it in the November 2003 issue of the
[@http://www.cuj.com CUJ].
After leaving Microsoft, I revisited the idea of a looping construct. I reimplemented the macro
from scratch in standard C++, corrected some shortcomings of the CUJ version and rechristened it
BOOST_FOREACH. In October of 2003 I began a discussion about it on the Boost developers list, where
it met with a luke-warm reception. I dropped the issue until December 2004, when I reimplemented
BOOST_FOREACH yet again. The new version only evaluated its sequence expression once and correctly
handled both l-value and r-value sequence expressions. It was built on top of the recently
accepted _range_ library, which increased its portability. This was the version that, on Dec. 12 2004,
I finally submitted to Boost for review. It was accepted into Boost on May 5, 2005.
[h2 Acknowledgements]
Thanks go out to Anson Tsao of Microsoft for coming up with the idea and demonstrating its feasibility.
I would also like to thank [@http://boost.org/people/thorsten_ottosen.html Thorsten Ottosen] for
the _range_ library, on which the current version of _foreach_ is built.
[h2 Further Reading]
If you would like more information about how _foreach_ works, you can read the article
[@http://www.artima.com/cppsource/foreach.html "Conditional Love"] at
[@http://www.artima.com/cppsource/ The C++ Source].
[endsect]
+702
View File
@@ -0,0 +1,702 @@
///////////////////////////////////////////////////////////////////////////////
// foreach.hpp header file
//
// Copyright 2004 Eric Niebler.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_FOREACH
// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
#include <cstddef>
#include <utility> // for std::pair
#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
// Some compilers allow temporaries to be bound to non-const references.
// These compilers make it impossible to for BOOST_FOREACH to detect
// temporaries and avoid reevaluation of the collection expression.
#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) \
|| BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) \
|| (BOOST_WORKAROUND(BOOST_INTEL_CXX_VERSION, <= 700) && defined(_MSC_VER))
# define BOOST_FOREACH_NO_RVALUE_DETECTION
#endif
// Some compilers do not correctly implement the L-value/R-value conversion
// rules of the ternary conditional operator.
#if defined(BOOST_FOREACH_NO_RVALUE_DETECTION) \
|| BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1400)) \
|| BOOST_WORKAROUND(BOOST_INTEL_WIN, BOOST_TESTED_AT(800)) \
|| BOOST_WORKAROUND(__GNUC__, < 3) \
|| (BOOST_WORKAROUND(__GNUC__, == 3) && (__GNUC_MINOR__ <= 2))
# define BOOST_FOREACH_NO_CONST_RVALUE_DETECTION
#endif
#include <boost/mpl/bool.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/range/end.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/result_iterator.hpp>
#include <boost/type_traits/is_const.hpp>
#include <boost/iterator/iterator_traits.hpp>
#include <boost/utility/addressof.hpp>
#ifndef BOOST_FOREACH_NO_CONST_RVALUE_DETECTION
# include <new>
# include <boost/aligned_storage.hpp>
# include <boost/utility/enable_if.hpp>
# include <boost/type_traits/is_array.hpp>
#endif
namespace boost
{
// forward declarations for iterator_range
template<typename T>
class iterator_range;
// forward declarations for sub_range
template<typename T>
class sub_range;
namespace foreach
{
///////////////////////////////////////////////////////////////////////////////
// in_range
//
template<typename T>
inline std::pair<T, T> in_range(T begin, T end)
{
return std::make_pair(begin, end);
}
} // namespace foreach
namespace foreach_detail_
{
///////////////////////////////////////////////////////////////////////////////
// adl_begin/adl_end
//
template<typename T>
inline BOOST_DEDUCED_TYPENAME range_result_iterator<T>::type adl_begin(T &t)
{
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) \
|| BOOST_WORKAROUND(__GNUC__, < 3)
return boost::begin(t);
#else
using boost::begin;
typedef BOOST_DEDUCED_TYPENAME range_result_iterator<T>::type type;
return type(begin(t));
#endif
}
template<typename T>
inline BOOST_DEDUCED_TYPENAME range_result_iterator<T>::type adl_end(T &t)
{
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) \
|| BOOST_WORKAROUND(__GNUC__, < 3)
return boost::end(t);
#else
using boost::end;
typedef BOOST_DEDUCED_TYPENAME range_result_iterator<T>::type type;
return type(end(t));
#endif
}
///////////////////////////////////////////////////////////////////////////////
// auto_any_t/auto_any
//
struct auto_any_base
{
// auto_any_base must evaluate to false in boolean context so that
// they can be declared in if() statements.
operator bool() const
{
return false;
}
};
template<typename T>
struct auto_any : auto_any_base
{
auto_any(T const &t)
: item(t)
{
}
// temporaries of type auto_any will be bound to const auto_any_base
// references, but we still want to be able to mutate the stored
// data, so declare it as mutable.
mutable T item;
};
typedef auto_any_base const &auto_any_t;
template<typename T, typename C>
inline BOOST_DEDUCED_TYPENAME boost::mpl::if_<C, T const, T>::type &auto_any_cast(auto_any_t a)
{
return static_cast<auto_any<T> const &>(a).item;
}
typedef boost::mpl::true_ const_;
///////////////////////////////////////////////////////////////////////////////
// type2type
//
template<typename T, typename C = boost::mpl::false_>
struct type2type
: boost::mpl::if_<C, T const, T>
{
};
template<typename T, typename C = boost::mpl::false_>
struct foreach_iterator
{
// If there is no function template ordering, then it may
// be impossible to strip cv-modifiers from T, so use
// range_result_iterator. Otherwise, use range_const_iterator
// and range_iterator.
#ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
typedef BOOST_DEDUCED_TYPENAME boost::mpl::eval_if<
C
, range_const_iterator<T>
, range_iterator<T>
>::type type;
#else
typedef BOOST_DEDUCED_TYPENAME boost::mpl::eval_if<
C
, range_result_iterator<T const>
, range_result_iterator<T>
>::type type;
#endif
};
template<typename T, typename C = boost::mpl::false_>
struct foreach_reference
: iterator_reference<BOOST_DEDUCED_TYPENAME foreach_iterator<T, C>::type>
{
};
///////////////////////////////////////////////////////////////////////////////
// encode_type
//
template<typename T>
inline type2type<T> *encode_type(T &)
{
return 0;
}
#ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
template<typename T>
inline type2type<T, const_> *encode_type(T const &)
{
return 0;
}
#endif
#ifndef BOOST_FOREACH_NO_CONST_RVALUE_DETECTION
///////////////////////////////////////////////////////////////////////////////
// rvalue_probe
//
struct rvalue_probe
{
template<typename T>
rvalue_probe(T const &t, bool &b)
: ptemp(const_cast<T *>(&t))
, rvalue(b)
{
}
template<typename U>
operator U()
{
rvalue = true;
return *static_cast<U *>(ptemp);
}
template<typename V>
operator V &() const
{
return *static_cast<V *>(ptemp);
}
void *ptemp;
bool &rvalue;
};
///////////////////////////////////////////////////////////////////////////////
// simple_variant
// holds either a T or a T*
template<typename T>
struct simple_variant
{
simple_variant(T *t)
: rvalue(false)
{
*static_cast<T **>(data.address()) = t;
}
simple_variant(T const &t)
: rvalue(true)
{
::new(data.address()) T(t);
}
simple_variant(simple_variant const &that)
: rvalue(that.rvalue)
{
if(rvalue)
::new(data.address()) T(*that.get());
else
*static_cast<T **>(data.address()) = that.get();
}
~simple_variant()
{
if(rvalue)
get()->~T();
}
T *get() const
{
if(rvalue)
return static_cast<T *>(data.address());
else
return *static_cast<T **>(data.address());
}
private:
enum { size = sizeof(T) > sizeof(T*) ? sizeof(T) : sizeof(T*) };
simple_variant &operator =(simple_variant const &);
bool const rvalue;
mutable aligned_storage<size> data;
};
#elif !defined(BOOST_FOREACH_NO_RVALUE_DETECTION)
///////////////////////////////////////////////////////////////////////////////
// is_rvalue
//
template<typename T>
inline mpl::false_ *is_rvalue(T &, int)
{
return 0;
}
template<typename T>
inline mpl::true_ *is_rvalue(T const &, ...)
{
return 0;
}
#endif // BOOST_FOREACH_NO_CONST_RVALUE_DETECTION
///////////////////////////////////////////////////////////////////////////////
// set_false
//
inline bool set_false(bool &b)
{
return b = false;
}
///////////////////////////////////////////////////////////////////////////////
// to_ptr
//
template<typename T>
inline T *to_ptr(T const &t) { return 0; }
// Borland needs a little extra help with arrays
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
template<typename T,std::size_t N>
inline T (*to_ptr(T (&t)[N]))[N] { return 0; }
#endif
///////////////////////////////////////////////////////////////////////////////
// cheap_copy
// Overload this for user-defined collection types if they are inexpensive to copy.
// This tells BOOST_FOREACH it can avoid the r-value/l-value detection stuff.
inline mpl::false_ *cheap_copy(...) { return 0; }
template<typename T>
inline mpl::true_ *cheap_copy(std::pair<T, T> *) { return 0; }
template<typename T>
inline mpl::true_ *cheap_copy(iterator_range<T> *) { return 0; }
template<typename T>
inline mpl::true_ *cheap_copy(sub_range<T> *) { return 0; }
template<typename T>
inline mpl::true_ *cheap_copy(T **) { return 0; }
template<typename T,std::size_t N>
inline mpl::false_ *cheap_copy(T (*)[N]) { return 0; }
///////////////////////////////////////////////////////////////////////////////
// derefof
//
template<typename T>
inline T &derefof(T *t)
{
// This is a work-around for a compiler bug in Borland. If T* is a pointer to array type U(*)[N],
// then dereferencing it results in a U* instead of U(&)[N]. The cast forces the issue.
return reinterpret_cast<T &>(
*const_cast<char *>(
reinterpret_cast<char const volatile *>(t)
)
);
}
///////////////////////////////////////////////////////////////////////////////
// contain
//
template<typename T>
inline auto_any<T> contain(T const &t, void *, boost::mpl::true_ *)
{
return t;
}
#ifndef BOOST_FOREACH_NO_CONST_RVALUE_DETECTION
template<typename T>
inline auto_any<T *> contain(T &t, bool *, boost::mpl::false_ *)
{
return boost::addressof(t);
}
template<typename T>
inline BOOST_DEDUCED_TYPENAME disable_if<
is_array<T>
, auto_any<simple_variant<T const> >
>::type
contain(T const &t, bool *rvalue, boost::mpl::false_ *)
{
return *rvalue ? simple_variant<T const>(t) : simple_variant<T const>(&t);
}
#else
template<typename T>
inline auto_any<T *> contain(T &t, boost::mpl::false_ *, boost::mpl::false_ *) // l-value
{
return boost::addressof(t);
}
template<typename T>
inline auto_any<T> contain(T const &t, boost::mpl::true_ *, boost::mpl::false_ *) // r-value
{
return t;
}
#endif
/////////////////////////////////////////////////////////////////////////////
// begin
//
template<typename T, typename C>
inline auto_any<BOOST_DEDUCED_TYPENAME foreach_iterator<T, C>::type>
begin(auto_any_t col, type2type<T, C> *, void *, boost::mpl::true_ *)
{
return foreach_detail_::adl_begin(auto_any_cast<T, C>(col));
}
#ifndef BOOST_FOREACH_NO_CONST_RVALUE_DETECTION
template<typename T, typename C>
inline auto_any<BOOST_DEDUCED_TYPENAME foreach_iterator<T, C>::type>
begin(auto_any_t col, type2type<T, C> *, bool *, boost::mpl::false_ *)
{
typedef BOOST_DEDUCED_TYPENAME type2type<T, C>::type type;
return foreach_detail_::adl_begin(derefof(auto_any_cast<type *, boost::mpl::false_>(col)));
}
template<typename T>
inline BOOST_DEDUCED_TYPENAME disable_if<
is_array<T>
, auto_any<BOOST_DEDUCED_TYPENAME foreach_iterator<T, boost::mpl::true_>::type>
>::type
begin(auto_any_t col, type2type<T, const_> *, bool *, boost::mpl::false_ *)
{
return foreach_detail_::adl_begin(*auto_any_cast<simple_variant<T const>, boost::mpl::false_>(col).get());
}
#else
template<typename T, typename C>
inline auto_any<BOOST_DEDUCED_TYPENAME foreach_iterator<T, C>::type>
begin(auto_any_t col, type2type<T, C> *, boost::mpl::false_ *, boost::mpl::false_ *) // l-value
{
typedef BOOST_DEDUCED_TYPENAME type2type<T, C>::type type;
typedef BOOST_DEDUCED_TYPENAME foreach_iterator<T, C>::type iterator;
return iterator(foreach_detail_::adl_begin(derefof(auto_any_cast<type *, boost::mpl::false_>(col))));
}
template<typename T>
inline auto_any<BOOST_DEDUCED_TYPENAME foreach_iterator<T, boost::mpl::true_>::type>
begin(auto_any_t col, type2type<T, const_> *, boost::mpl::true_ *, boost::mpl::false_ *) // r-value
{
return foreach_detail_::adl_begin(auto_any_cast<T, boost::mpl::true_>(col));
}
#endif
///////////////////////////////////////////////////////////////////////////////
// end
//
template<typename T, typename C>
inline auto_any<BOOST_DEDUCED_TYPENAME foreach_iterator<T, C>::type>
end(auto_any_t col, type2type<T, C> *, void *, boost::mpl::true_ *)
{
return foreach_detail_::adl_end(auto_any_cast<T, C>(col));
}
#ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
template<typename T, typename C>
inline auto_any<int>
end(auto_any_t col, type2type<T *, C> *, void *, boost::mpl::true_ *)
{
return 0; // not used
}
#endif
#ifndef BOOST_FOREACH_NO_CONST_RVALUE_DETECTION
template<typename T, typename C>
inline auto_any<BOOST_DEDUCED_TYPENAME foreach_iterator<T, C>::type>
end(auto_any_t col, type2type<T, C> *, bool *, boost::mpl::false_ *)
{
typedef BOOST_DEDUCED_TYPENAME type2type<T, C>::type type;
return foreach_detail_::adl_end(derefof(auto_any_cast<type *, boost::mpl::false_>(col)));
}
template<typename T>
inline BOOST_DEDUCED_TYPENAME disable_if<
is_array<T>
, auto_any<BOOST_DEDUCED_TYPENAME foreach_iterator<T, boost::mpl::true_>::type>
>::type
end(auto_any_t col, type2type<T, const_> *, bool *, boost::mpl::false_ *)
{
return foreach_detail_::adl_end(*auto_any_cast<simple_variant<T const>, boost::mpl::false_>(col).get());
}
#else
template<typename T, typename C>
inline auto_any<BOOST_DEDUCED_TYPENAME foreach_iterator<T, C>::type>
end(auto_any_t col, type2type<T, C> *, boost::mpl::false_ *, boost::mpl::false_ *) // l-value
{
typedef BOOST_DEDUCED_TYPENAME type2type<T, C>::type type;
typedef BOOST_DEDUCED_TYPENAME foreach_iterator<T, C>::type iterator;
return iterator(foreach_detail_::adl_end(derefof(auto_any_cast<type *, boost::mpl::false_>(col))));
}
template<typename T>
inline auto_any<BOOST_DEDUCED_TYPENAME foreach_iterator<T, boost::mpl::true_>::type>
end(auto_any_t col, type2type<T, const_> *, boost::mpl::true_ *, boost::mpl::false_ *) // r-value
{
return foreach_detail_::adl_end(auto_any_cast<T, boost::mpl::true_>(col));
}
#endif
///////////////////////////////////////////////////////////////////////////////
// done
//
template<typename T, typename C>
inline bool done(auto_any_t cur, auto_any_t end, type2type<T, C> *)
{
typedef BOOST_DEDUCED_TYPENAME foreach_iterator<T, C>::type iter_t;
return auto_any_cast<iter_t, boost::mpl::false_>(cur) == auto_any_cast<iter_t, boost::mpl::false_>(end);
}
#ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
template<typename T, typename C>
inline bool done(auto_any_t cur, auto_any_t, type2type<T *, C> *)
{
return ! *auto_any_cast<T *, boost::mpl::false_>(cur);
}
#endif
///////////////////////////////////////////////////////////////////////////////
// next
//
template<typename T, typename C>
inline void next(auto_any_t cur, type2type<T, C> *)
{
typedef BOOST_DEDUCED_TYPENAME foreach_iterator<T, C>::type iter_t;
++auto_any_cast<iter_t, boost::mpl::false_>(cur);
}
///////////////////////////////////////////////////////////////////////////////
// deref
//
template<typename T, typename C>
inline BOOST_DEDUCED_TYPENAME foreach_reference<T, C>::type
deref(auto_any_t cur, type2type<T, C> *)
{
typedef BOOST_DEDUCED_TYPENAME foreach_iterator<T, C>::type iter_t;
return *auto_any_cast<iter_t, boost::mpl::false_>(cur);
}
} // namespace foreach_detail_
} // namespace boost
#ifndef BOOST_FOREACH_NO_CONST_RVALUE_DETECTION
///////////////////////////////////////////////////////////////////////////////
// R-values and const R-values supported here
///////////////////////////////////////////////////////////////////////////////
// A sneaky way to get the type of the collection without evaluating the expression
# define BOOST_FOREACH_TYPEOF(COL) \
(true ? 0 : boost::foreach_detail_::encode_type(COL))
// Evaluate the collection expression, and detect if it is an l-value or and r-value
# define BOOST_FOREACH_EVAL(COL) \
(true ? boost::foreach_detail_::rvalue_probe((COL), _foreach_rvalue) : (COL))
// Declare a variable to track the rvalue-ness of the collection expression
# define BOOST_FOREACH_DEFINE_RVALUE() \
if (bool _foreach_rvalue = false) {} else
// The R-value/L-value-ness of the collection expression is determined dynamically
# define BOOST_FOREACH_RVALUE(COL) \
(&_foreach_rvalue)
# define BOOST_FOREACH_CHEAP_COPY(COL) \
(true ? 0 : boost::foreach_detail_::cheap_copy(boost::foreach_detail_::to_ptr(COL)))
# define BOOST_FOREACH_NOOP(COL) \
((void)0)
#elif !defined(BOOST_FOREACH_NO_RVALUE_DETECTION)
///////////////////////////////////////////////////////////////////////////////
// R-values supported here, const R-values NOT supported here
///////////////////////////////////////////////////////////////////////////////
// A sneaky way to get the type of the collection without evaluating the expression
# define BOOST_FOREACH_TYPEOF(COL) \
(true ? 0 : boost::foreach_detail_::encode_type(COL))
// Evaluate the collection expression
# define BOOST_FOREACH_EVAL(COL) \
(COL)
// No variable is needed to track the rvalue-ness of the collection expression
# define BOOST_FOREACH_DEFINE_RVALUE() \
/**/
// Determine whether the collection expression is an l-value or an r-value.
// NOTE: this gets the answer for const R-values wrong.
# define BOOST_FOREACH_RVALUE(COL) \
(true ? 0 : boost::foreach_detail_::is_rvalue((COL), 0))
# define BOOST_FOREACH_CHEAP_COPY(COL) \
(true ? 0 : boost::foreach_detail_::cheap_copy(boost::foreach_detail_::to_ptr(COL)))
# define BOOST_FOREACH_NOOP(COL) \
((void)0)
#else
///////////////////////////////////////////////////////////////////////////////
// R-values NOT supported here
///////////////////////////////////////////////////////////////////////////////
// A sneaky way to get the type of the collection without evaluating the expression
# define BOOST_FOREACH_TYPEOF(COL) \
(true ? 0 : boost::foreach_detail_::encode_type(COL))
// Evaluate the collection expression
# define BOOST_FOREACH_EVAL(COL) \
(COL)
// No variable is needed to track the rvalue-ness of the collection expression
# define BOOST_FOREACH_DEFINE_RVALUE() \
/**/
// Can't use R-values with BOOST_FOREACH
# define BOOST_FOREACH_RVALUE(COL) \
(static_cast<boost::mpl::false_ *>(0))
# define BOOST_FOREACH_CHEAP_COPY(COL) \
(true ? 0 : boost::foreach_detail_::cheap_copy(boost::foreach_detail_::to_ptr(COL)))
// Attempt to make uses of BOOST_FOREACH with non-lvalues fail to compile
// BUGBUG but cheap-to-copy containers *would* be handled correctly. Hrm.
# define BOOST_FOREACH_NOOP(COL) \
((void)&(COL))
#endif
#define BOOST_FOREACH_CONTAIN(COL) \
boost::foreach_detail_::contain( \
BOOST_FOREACH_EVAL(COL) \
, BOOST_FOREACH_RVALUE(COL) \
, BOOST_FOREACH_CHEAP_COPY(COL))
#define BOOST_FOREACH_BEGIN(COL) \
boost::foreach_detail_::begin( \
_foreach_col \
, BOOST_FOREACH_TYPEOF(COL) \
, BOOST_FOREACH_RVALUE(COL) \
, BOOST_FOREACH_CHEAP_COPY(COL))
#define BOOST_FOREACH_END(COL) \
boost::foreach_detail_::end( \
_foreach_col \
, BOOST_FOREACH_TYPEOF(COL) \
, BOOST_FOREACH_RVALUE(COL) \
, BOOST_FOREACH_CHEAP_COPY(COL))
#define BOOST_FOREACH_DONE(COL) \
boost::foreach_detail_::done( \
_foreach_cur \
, _foreach_end \
, BOOST_FOREACH_TYPEOF(COL))
#define BOOST_FOREACH_NEXT(COL) \
boost::foreach_detail_::next( \
_foreach_cur \
, BOOST_FOREACH_TYPEOF(COL))
#define BOOST_FOREACH_DEREF(COL) \
boost::foreach_detail_::deref( \
_foreach_cur \
, BOOST_FOREACH_TYPEOF(COL))
///////////////////////////////////////////////////////////////////////////////
// BOOST_FOREACH
//
// For iterating over collections. Collections can be
// arrays, null-terminated strings, or STL containers.
// The loop variable can be a value or reference. For
// example:
//
// std::list<int> int_list(/*stuff*/);
// BOOST_FOREACH(int &i, int_list)
// {
// /*
// * loop body goes here.
// * i is a reference to the int in int_list.
// */
// }
//
// Alternately, you can declare the loop variable first,
// so you can access it after the loop finishes. Obviously,
// if you do it this way, then the loop variable cannot be
// a reference.
//
// int i;
// BOOST_FOREACH(i, int_list)
// { ... }
//
#define BOOST_FOREACH(VAR, COL) \
BOOST_FOREACH_DEFINE_RVALUE() \
if (boost::foreach_detail_::auto_any_t _foreach_col = BOOST_FOREACH_CONTAIN(COL)) {} else \
if (boost::foreach_detail_::auto_any_t _foreach_cur = BOOST_FOREACH_BEGIN(COL)) {} else \
if (boost::foreach_detail_::auto_any_t _foreach_end = BOOST_FOREACH_END(COL)) {} else \
for (bool _foreach_continue = true; \
_foreach_continue && !BOOST_FOREACH_DONE(COL); \
_foreach_continue ? BOOST_FOREACH_NEXT(COL) : BOOST_FOREACH_NOOP(COL)) \
if (boost::foreach_detail_::set_false(_foreach_continue)) {} else \
for (VAR = BOOST_FOREACH_DEREF(COL); !_foreach_continue; _foreach_continue = true)
#endif
Executable
+9
View File
@@ -0,0 +1,9 @@
<html>
<head>
<meta http-equiv="refresh" content="0; URL=../../doc/html/foreach.html">
</head>
<body>
Automatic redirection failed, please go to
<a href="../../doc/html/foreach.html">../../doc/html/foreach.html</a>
</body>
</html>
Executable
+32
View File
@@ -0,0 +1,32 @@
# foreach library test Jamfile
# Copyright Eric Niebler 2004
# Use, modification, and distribution is subject to the Boost Software
# License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
subproject libs/foreach/test ;
# bring in rules for testing
import testing ;
# Make tests run by default.
DEPENDS all : foreach ;
{
test-suite "foreach"
: [ run stl_byval.cpp ]
[ run stl_byref.cpp ]
[ run array_byval.cpp ]
[ run array_byref.cpp ]
[ run cstr_byval.cpp ]
[ run cstr_byref.cpp ]
[ run pair_byval.cpp ]
[ run pair_byref.cpp ]
[ run user_defined.cpp ]
[ run call_once.cpp ]
[ run rvalue_const.cpp ]
[ run rvalue_nonconst.cpp ]
;
}
+21
View File
@@ -0,0 +1,21 @@
# (C) Copyright 2004: Eric Niebler
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
# bring in rules for testing
import testing ;
test-suite "foreach"
: [ run stl_byval.cpp ]
[ run stl_byref.cpp ]
[ run array_byval.cpp ]
[ run array_byref.cpp ]
[ run cstr_byval.cpp ]
[ run cstr_byref.cpp ]
[ run pair_byval.cpp ]
[ run pair_byref.cpp ]
[ run user_defined.cpp ]
[ run call_once.cpp ]
[ run rvalue_const.cpp ]
[ run rvalue_nonconst.cpp ]
;
+46
View File
@@ -0,0 +1,46 @@
// (C) Copyright Eric Niebler 2004.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/*
Revision history:
25 August 2005 : Initial version.
*/
#include <boost/test/minimal.hpp>
#include <boost/iterator/counting_iterator.hpp>
#include "../../../boost/foreach.hpp"
#include "./utility.hpp"
///////////////////////////////////////////////////////////////////////////////
// int_iterator
//
typedef boost::counting_iterator<int> int_iterator;
///////////////////////////////////////////////////////////////////////////////
// define come containers
//
int my_array[] = { 1,2,3,4,5 };
int const (&my_const_array)[5] = my_array;
///////////////////////////////////////////////////////////////////////////////
// test_main
//
int test_main( int, char*[] )
{
// non-const containers by reference
BOOST_CHECK(to_vector_foreach_byref(my_array) == to_vector_for(my_array));
// const containers by reference
BOOST_CHECK(to_vector_foreach_byref(my_const_array) == to_vector_for(my_const_array));
// mutate the mutable collections
mutate_foreach_byref(my_array);
// compare the mutated collections to the actual results
std::pair<int_iterator,int_iterator> results(int_iterator(2),int_iterator(7));
BOOST_CHECK(to_vector_foreach_byval(my_array) == to_vector_for(results));
return 0;
}
+33
View File
@@ -0,0 +1,33 @@
// (C) Copyright Eric Niebler 2004.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/*
Revision history:
25 August 2005 : Initial version.
*/
#include <boost/test/minimal.hpp>
#include "../../../boost/foreach.hpp"
#include "./utility.hpp"
///////////////////////////////////////////////////////////////////////////////
// define come containers
//
int my_array[] = { 1,2,3,4,5 };
int const (&my_const_array)[5] = my_array;
///////////////////////////////////////////////////////////////////////////////
// test_main
//
int test_main( int, char*[] )
{
// non-const containers by value
BOOST_CHECK(to_vector_foreach_byval(my_array) == to_vector_for(my_array));
// const containers by value
BOOST_CHECK(to_vector_foreach_byval(my_const_array) == to_vector_for(my_const_array));
return 0;
}
+40
View File
@@ -0,0 +1,40 @@
// (C) Copyright Eric Niebler 2005.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/*
Revision history:
25 August 2005 : Initial version.
*/
#include <vector>
#include <boost/test/minimal.hpp>
#include "../../../boost/foreach.hpp"
// counter
int counter = 0;
std::vector<int> my_vector(4,4);
std::vector<int> const &get_vector()
{
++counter;
return my_vector;
}
///////////////////////////////////////////////////////////////////////////////
// test_main
//
int test_main( int, char*[] )
{
BOOST_FOREACH(int i, get_vector())
{
((void)i); // no-op
}
BOOST_CHECK(1 == counter);
return 0;
}
+47
View File
@@ -0,0 +1,47 @@
// (C) Copyright Eric Niebler 2004.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/*
Revision history:
25 August 2005 : Initial version.
*/
#include <boost/test/minimal.hpp>
#include <boost/iterator/counting_iterator.hpp>
#include "../../../boost/foreach.hpp"
#include "./utility.hpp"
///////////////////////////////////////////////////////////////////////////////
// int_iterator
//
typedef boost::counting_iterator<int> int_iterator;
///////////////////////////////////////////////////////////////////////////////
// define come containers
//
char my_ntcs_buffer[] = "\1\2\3\4\5";
char *my_ntcs = my_ntcs_buffer;
char const *my_const_ntcs = my_ntcs;
///////////////////////////////////////////////////////////////////////////////
// test_main
//
int test_main( int, char*[] )
{
// non-const containers by reference
BOOST_CHECK(to_vector_foreach_byref(my_ntcs) == to_vector_for(my_ntcs));
// const containers by reference
BOOST_CHECK(to_vector_foreach_byref(my_const_ntcs) == to_vector_for(my_const_ntcs));
// mutate the mutable collections
mutate_foreach_byref(my_ntcs);
// compare the mutated collections to the actual results
std::pair<int_iterator,int_iterator> results(int_iterator(2),int_iterator(7));
BOOST_CHECK(to_vector_foreach_byval(my_ntcs) == to_vector_for(results));
return 0;
}
+34
View File
@@ -0,0 +1,34 @@
// (C) Copyright Eric Niebler 2004.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/*
Revision history:
25 August 2005 : Initial version.
*/
#include <boost/test/minimal.hpp>
#include "../../../boost/foreach.hpp"
#include "./utility.hpp"
///////////////////////////////////////////////////////////////////////////////
// define come containers
//
char my_ntcs_buffer[] = "\1\2\3\4\5";
char *my_ntcs = my_ntcs_buffer;
char const *my_const_ntcs = my_ntcs;
///////////////////////////////////////////////////////////////////////////////
// test_main
//
int test_main( int, char*[] )
{
// non-const containers by value
BOOST_CHECK(to_vector_foreach_byval(my_ntcs) == to_vector_for(my_ntcs));
// const containers by value
BOOST_CHECK(to_vector_foreach_byval(my_const_ntcs) == to_vector_for(my_const_ntcs));
return 0;
}
+51
View File
@@ -0,0 +1,51 @@
// (C) Copyright Eric Niebler 2004.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/*
Revision history:
13 December 2004 : Initial version.
25 August 2005 : Initial version.
*/
#include <list>
#include <vector>
#include <boost/test/minimal.hpp>
#include <boost/iterator/iterator_traits.hpp>
#include <boost/iterator/counting_iterator.hpp>
#include "../../../boost/foreach.hpp"
#include "./utility.hpp"
///////////////////////////////////////////////////////////////////////////////
// int_iterator
//
typedef boost::counting_iterator<int> int_iterator;
///////////////////////////////////////////////////////////////////////////////
// define come containers
//
int my_array[] = { 1,2,3,4,5 };
std::pair<int*,int*> my_pair(my_array,my_array+5);
std::pair<int const*,int const*> const my_const_pair(my_array,my_array+5);
///////////////////////////////////////////////////////////////////////////////
// test_main
//
int test_main( int, char*[] )
{
// non-const containers by reference
BOOST_CHECK(to_vector_foreach_byref(my_pair) == to_vector_for(my_pair));
// const containers by reference
BOOST_CHECK(to_vector_foreach_byref(my_const_pair) == to_vector_for(my_const_pair));
// mutate the mutable collections
mutate_foreach_byref(my_pair);
// compare the mutated collections to the actual results
std::pair<int_iterator,int_iterator> results(int_iterator(2),int_iterator(7));
BOOST_CHECK(to_vector_foreach_byval(my_pair) == to_vector_for(results));
return 0;
}
+34
View File
@@ -0,0 +1,34 @@
// (C) Copyright Eric Niebler 2004.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/*
Revision history:
25 August 2005 : Initial version.
*/
#include <boost/test/minimal.hpp>
#include "../../../boost/foreach.hpp"
#include "./utility.hpp"
///////////////////////////////////////////////////////////////////////////////
// define come containers
//
int my_array[] = { 1,2,3,4,5 };
std::pair<int*,int*> my_pair(my_array,my_array+5);
std::pair<int const*,int const*> const my_const_pair(my_array,my_array+5);
///////////////////////////////////////////////////////////////////////////////
// test_main
//
int test_main( int, char*[] )
{
// non-const containers by value
BOOST_CHECK(to_vector_foreach_byval(my_pair) == to_vector_for(my_pair));
// const containers by value
BOOST_CHECK(to_vector_foreach_byval(my_const_pair) == to_vector_for(my_const_pair));
return 0;
}
+41
View File
@@ -0,0 +1,41 @@
// (C) Copyright Eric Niebler 2005.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/*
Revision history:
25 August 2005 : Initial version.
*/
#include <vector>
#include <boost/test/minimal.hpp>
#include "../../../boost/foreach.hpp"
#ifdef BOOST_FOREACH_NO_CONST_RVALUE_DETECTION
# error Expected failure : const rvalues disallowed
#else
std::vector<int> const get_vector()
{
return std::vector<int>(4, 4);
}
///////////////////////////////////////////////////////////////////////////////
// test_main
//
int test_main( int, char*[] )
{
int counter = 0;
BOOST_FOREACH(int i, get_vector())
{
counter += i;
}
BOOST_CHECK(16 == counter);
return 0;
}
#endif
+41
View File
@@ -0,0 +1,41 @@
// (C) Copyright Eric Niebler 2005.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/*
Revision history:
25 August 2005 : Initial version.
*/
#include <vector>
#include <boost/test/minimal.hpp>
#include "../../../boost/foreach.hpp"
#ifdef BOOST_FOREACH_NO_RVALUE_DETECTION
# error Expected failure : rvalues disallowed
#else
std::vector<int> get_vector()
{
return std::vector<int>(4, 4);
}
///////////////////////////////////////////////////////////////////////////////
// test_main
//
int test_main( int, char*[] )
{
int counter = 0;
BOOST_FOREACH(int i, get_vector())
{
counter += i;
}
BOOST_CHECK(16 == counter);
return 0;
}
#endif
+60
View File
@@ -0,0 +1,60 @@
// (C) Copyright Eric Niebler 2004.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/*
Revision history:
25 August 2005: Initial version.
*/
#include <list>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/test/minimal.hpp>
#include "../../../boost/foreach.hpp"
#include "./utility.hpp"
///////////////////////////////////////////////////////////////////////////////
// int_iterator
//
typedef boost::counting_iterator<int> int_iterator;
///////////////////////////////////////////////////////////////////////////////
// initialize a std::list<int>
std::list<int> get_list()
{
std::list<int> l;
l.push_back(1);
l.push_back(2);
l.push_back(3);
l.push_back(4);
l.push_back(5);
return l;
}
///////////////////////////////////////////////////////////////////////////////
// define come containers
//
std::list<int> my_list(get_list());
std::list<int> const &my_const_list = my_list;
///////////////////////////////////////////////////////////////////////////////
// test_main
//
int test_main( int, char*[] )
{
// non-const containers by reference
BOOST_CHECK(to_vector_foreach_byref(my_list) == to_vector_for(my_list));
// const containers by reference
BOOST_CHECK(to_vector_foreach_byref(my_const_list) == to_vector_for(my_const_list));
// mutate the mutable collections
mutate_foreach_byref(my_list);
// compare the mutated collections to the actual results
std::pair<int_iterator,int_iterator> results(int_iterator(2),int_iterator(7));
BOOST_CHECK(to_vector_foreach_byval(my_list) == to_vector_for(results));
return 0;
}
+49
View File
@@ -0,0 +1,49 @@
// stl_byval.cpp
///
// (C) Copyright Eric Niebler 2004.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/*
Revision history:
25 August 2005 : Initial version.
*/
#include <list>
#include <boost/test/minimal.hpp>
#include "../../../boost/foreach.hpp"
#include "./utility.hpp"
///////////////////////////////////////////////////////////////////////////////
// initialize a std::list<int>
std::list<int> get_list()
{
std::list<int> l;
l.push_back(1);
l.push_back(2);
l.push_back(3);
l.push_back(4);
l.push_back(5);
return l;
}
///////////////////////////////////////////////////////////////////////////////
// define come containers
//
std::list<int> my_list(get_list());
std::list<int> const &my_const_list = my_list;
///////////////////////////////////////////////////////////////////////////////
// test_main
//
int test_main( int, char*[] )
{
// non-const containers by value
BOOST_CHECK(to_vector_foreach_byval(my_list) == to_vector_for(my_list));
// const containers by value
BOOST_CHECK(to_vector_foreach_byval(my_const_list) == to_vector_for(my_const_list));
return 0;
}
+53
View File
@@ -0,0 +1,53 @@
// (C) Copyright Eric Niebler 2005.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/*
Revision history:
25 August 2005 : Initial version.
*/
#include <boost/test/minimal.hpp>
#include "../../../boost/foreach.hpp"
///////////////////////////////////////////////////////////////////////////////
// define a user-defined collection type and teach BOOST_FOREACH how to enumerate it
//
namespace mine
{
struct dummy {};
}
namespace boost
{
template<>
struct range_iterator<mine::dummy>
{
typedef char * type;
};
template<>
struct range_const_iterator<mine::dummy>
{
typedef char const * type;
};
char * begin(mine::dummy&) {return 0;}
char const * begin(mine::dummy const&) {return 0;}
char * end(mine::dummy&) {return 0;}
char const * end(mine::dummy const&) {return 0;}
}
///////////////////////////////////////////////////////////////////////////////
// test_main
//
int test_main( int, char*[] )
{
// loop over a user-defined type (just make sure this compiles)
mine::dummy d;
BOOST_FOREACH( char c, d )
{
((void)c); // no-op
}
return 0;
}
+83
View File
@@ -0,0 +1,83 @@
///////////////////////////////////////////////////////////////////////////////
// utility.hpp header file
//
// Copyright 2005 Eric Niebler.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_FOREACH_TEST_UTILITY_HPP
#define BOOST_FOREACH_TEST_UTILITY_HPP
#include <vector>
#include <boost/config.hpp>
#include <boost/range/end.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/result_iterator.hpp>
#include <boost/iterator/iterator_traits.hpp>
#include "../../../boost/foreach.hpp"
///////////////////////////////////////////////////////////////////////////////
// to_vector_for
//
template<typename Range>
inline std::vector<int> to_vector_for( Range & rng )
{
std::vector<int> vect;
typedef BOOST_DEDUCED_TYPENAME boost::range_result_iterator<Range>::type iterator;
for(iterator begin = boost::begin(rng), end = boost::end(rng);
begin != end; ++begin)
{
vect.push_back(*begin);
}
return vect;
}
///////////////////////////////////////////////////////////////////////////////
// to_vector_foreach_byval
//
template<typename Range>
inline std::vector<int> to_vector_foreach_byval( Range & rng )
{
std::vector<int> vect;
typedef BOOST_DEDUCED_TYPENAME boost::range_result_iterator<Range>::type iterator;
typedef BOOST_DEDUCED_TYPENAME boost::iterator_value<iterator>::type value;
BOOST_FOREACH( value i, rng )
{
vect.push_back(i);
}
return vect;
}
///////////////////////////////////////////////////////////////////////////////
// to_vector_foreach_byref
//
template<typename Range>
inline std::vector<int> to_vector_foreach_byref( Range & rng )
{
std::vector<int> vect;
typedef BOOST_DEDUCED_TYPENAME boost::range_result_iterator<Range>::type iterator;
typedef BOOST_DEDUCED_TYPENAME boost::iterator_reference<iterator>::type reference;
BOOST_FOREACH( reference i, rng )
{
vect.push_back(i);
}
return vect;
}
///////////////////////////////////////////////////////////////////////////////
// mutate_foreach_byref
//
template<typename Range>
inline void mutate_foreach_byref( Range & rng )
{
typedef BOOST_DEDUCED_TYPENAME boost::range_result_iterator<Range>::type iterator;
typedef BOOST_DEDUCED_TYPENAME boost::iterator_reference<iterator>::type reference;
BOOST_FOREACH( reference i, rng )
{
++i;
}
}
#endif