mirror of
https://github.com/boostorg/foreach.git
synced 2026-07-21 13:23:39 +00:00
BOOST_FOREACH
[SVN r30683]
This commit is contained in:
@@ -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
@@ -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 ;
|
||||
Executable
+386
@@ -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]
|
||||
Executable
+702
@@ -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
@@ -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
@@ -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 ]
|
||||
;
|
||||
}
|
||||
Executable
+21
@@ -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 ]
|
||||
;
|
||||
Executable
+46
@@ -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;
|
||||
}
|
||||
Executable
+33
@@ -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;
|
||||
}
|
||||
Executable
+40
@@ -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;
|
||||
}
|
||||
Executable
+47
@@ -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;
|
||||
}
|
||||
Executable
+34
@@ -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;
|
||||
}
|
||||
Executable
+51
@@ -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;
|
||||
}
|
||||
Executable
+34
@@ -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;
|
||||
}
|
||||
Executable
+41
@@ -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
|
||||
Executable
+41
@@ -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
|
||||
Executable
+60
@@ -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;
|
||||
}
|
||||
Executable
+49
@@ -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;
|
||||
}
|
||||
Executable
+53
@@ -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;
|
||||
}
|
||||
Executable
+83
@@ -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
|
||||
Reference in New Issue
Block a user