65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Range Adaptors 的函数式 STL

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.75/5 (20投票s)

Aug 27, 2006

23分钟阅读

viewsIcon

38891

downloadIcon

255

Introduction to Functional STL Library using Boost.Range Adaptors.

1 引言

Oven provides an experimental Range Adaptor implementation of Range Library Proposal

typedef
    any_range<int, boost::single_pass_traversal_tag>
range;

range sieve(range rng)
{
    return rng|dropped(1)|filtered(regular(lambda::_1 % front(rng) != 0));
}

range primes
    = iteration(range(counting_from(2)), &::sieve)|transformed(front);

int main()
{
    std::cout << (primes|taken(200));
}

All the types and functions are defined innamespace pstade::ovenat<pstade/oven.hpp>unless otherwise specified.

2 Requirements

3 Tested Under

  • Microsoft Visual C++ 2005 Express Edition SP1
  • Microsoft Visual C++ .NET Version 7.1 SP1
  • GCC 3.4.4

4 Specification

This document is based on the following specifications.

std::string src("hello, specification");

boost::result_of<op_make_filtered(std::string&, bool(*)(char))>::type
    result = make_filtered(src, &is_upper);
BOOST_CHECK( equals(result, src|filtered(&is_upper)) );

All the ranges Oven defines areInputStreamableOutputStreamableif<pstade/oven/io.hpp>is included.

[1] The function type is not supported asrfun. Instead, add&to make a function pointer.

5 Range Algorithms

Oven provides some range-based algorithms.<pstade/oven/functions.hpp>includes all the following functions unless otherwise specified.

5.1 STL Algorithms

Oven has all the range-based STL algorithms, which are ported from Boost.RangeEx with some compiler workarounds

std::string str;

// iterator-based
str = "gfedcba";
std::sort(str.begin(), str.end());
BOOST_CHECK( str == "abcdefg" );

// Oven range-based
str = "gfedcba";
oven::sort(str);
BOOST_CHECK( str == "abcdefg" );
  • 标题<pstade/oven/algorithm.hpp><pstade/oven/numeric.hpp>
  • Valid expressionalgo(rng,a0,a1,..,aN), wherealgois a Function Object.
  • Preconditionstd::algo(boost::begin(rng),boost::end(rng),a0,a1,..,aN)is a valid expression, wherealgois one of the STL algorithms.
  • Returnsstd::algo(boost::begin(rng),boost::end(rng),a0,a1,..,aN)

5.2 adapted_to/to_base

adapted_togets thebase_typeiterator of adapted iterators

std::string src("cjaigvwzenqhe");
std::string::iterator it = oven::adapted_to<std::string::iterator>(
    oven::max_element(
        src
            | filtered(regular(lambda::_1 != 'z'))
            | filtered(regular(lambda::_1 != 'w'))
    )
);

BOOST_CHECK( *it == 'v' );
  • 标题<pstade/oven/adapted_to_base.hpp>
  • Valid expressionBaseIter base = oven::adapted_to<BaseIter>(it);BaseIter base = it|to_base; [2]
  • Precondition: The type ofbaseisBaseIter, anditis an adapted iterator.
[2] to_baseadds the automatic type deduction toadapted_to.

5.3 begin/end

begin/endis a pipable version ofboost::begin/end:

std::string src("abcDefg");   
oven::copy(src|reversed|transformed(to_upper), src|reversed|begin);
BOOST_CHECK( oven::equals(src, std::string("ABCDEFG")) );
  • 标题<pstade/oven/begin_end.hpp>
  • Valid expressionrng|beginrng|end
  • Preconditionboost::begin(rng)boost::end(rng)is a valid expression.
  • Returnsboost::begin(rng)boost::end(rng)respectively.

5.4 compile

Pending...

compileintroduces the syntax sugar forjointedetc

std::string       rng1("12");
std::list<char>   rng2 = std::string("34")|copied;
std::vector<char> rng3 = std::string("56")|copied;

BOOST_CHECK( equals(
    compile( +(rng1 >> (rng2|as_term) >> rng3) ) | taken(17),
    std::string("12345612345612345")
) );
  • 标题<pstade/oven/compile.hpp>
  • Valid expressioncompile(rngExpr)

5.5 copied

copiedadds the automatic type deduction to copy_range which calls the range constructor of the STL Sequences

std::vector<int> vec = oven::counting(3, 9)|copied;
vec.push_back(9);
BOOST_CHECK( oven::equals(vec, oven::counting(3, 10)) );
  • 标题<pstade/oven/copy_range.hpp>
  • Valid expressionSeq seq = rng|copied; [3]
  • PreconditionSeq seq = boost::copy_range<Seq>(rng);is a valid expression.
  • EffectSeq seq = boost::copy_range<Seq>(rng);
[3] Seq seq(rng|copied);is not a valid expression.

5.6 distance

The upcoming Boost.Range will replaceboost::sizebyboost::distance. oven::distancethat is the same asboost::distancemakes your code portable

std::string str("012345");
BOOST_CHECK( oven::distance(str) == 6 );
  • 标题<pstade/oven/distance.hpp>
  • Valid expressiondistance(rng)
  • Preconditionstd::distance(boost::begin(rng),boost::end(rng))is a valid expression.
  • Returnsstd::distance(boost::begin(rng),boost::end(rng))

5.7 equals

equalsis the range-basedstd::equalthat takes two ranges as the arguments

std::string str("hello, equals");
std::vector<char> vec = str|copied;
BOOST_CHECK( oven::equals(str, vec) );
  • 标题<pstade/oven/equals.hpp>
  • Valid expressionequals(rng1,rng2)
  • Preconditionequal(rng1,boost::begin(rng2))is a valid expression.
  • Returnstrueif and only if theoven::equal(rng1,boost::begin(rng2))boost::size(rng1) == boost::size(rng2)returnstrue. [4]
[4] The size of two ranges too is checked.

5.8 front/back

  • 标题<pstade/oven/front_back.hpp>
  • Valid expressionfront(rng)back(biRng).
  • Preconditionboost::range_valueofrngisCopyConstructible.
  • ReturnsV(*boost::begin(rng))V(*--boost::end(biRng))respectively, whereVisboost::range_valueofrng. [5]
[5] They don't return references because of 24.1/9.

6 Utilities

Some helper function objects are given to fill the gap between Oven and other libraries.

6.1 innumerable

As discribed below, the function object generation needs is slightly different from the Generator concept defined by the Standard.innumerableturns the Generator function object into the Standard conforming one, which creates an infinite range, working with generation.

  • 标题<pstade/oven/generation.hpp>
  • Valid expressioninnumerable(rfun)
  • Returns: A generation conforming function object.

6.2 regular

Boost.Lambda functors are neitherDefaultConstructiblenorCopyAssignable. An iterator holding such a functor cannot conform to evenInputIterator. So that,regularconverts it to comfortable one for iterators. [6]

  • 标题<pstade/oven/regular.hpp>
  • Valid expressionregular(lambdaFunctor)
  • Returns: Arfunwhich isDefaultConstructibleCopyAssignable.

In principle, callregularbefore a lambda functor is passed to Range Adaptors.

[6] regularincidentally converts the functor into the one which can take non-const rvalues.

6.3 shared_regular

shared_regularconverts a noncopyable function object type to copyable one.

  • 标题<pstade/oven/regular.hpp>
  • Valid expressionshared_regular(p).
  • Preconditionboost::shared_ptris constructible fromp.
  • Returns: Arfunwhich isDefaultConstructibleCopyAssignable.

7 Ranges

Oven provides some predefined range types.<pstade/oven/ranges.hpp>includes every range header unless otherwise specified.

7.1 any_range

Oven supportsboost::result_of, but it is sometimes cumbersome to get the type of the adapted range.any_rangebehaves as the type erasure of ranges

any_range<int, boost::single_pass_traversal_tag> factorials =
    counting_from(1) |
        scanned(1, regular(lambda::_1 * lambda::_2));
  • 标题<pstade/oven/any_range.hpp>
  • Valid expressionany_range<R,T> any_;, any_range<R,T> any_(rng);any_range<R,T> any_ = rng;, where the iterators ofany_areInteroperatableif and only ifrngs are the same type.
  • Preconditionboost::range_referenceofrngis convertible toRwithout creating rvalue.Tis aTraversalTag.
  • Returns: A range whose iterators behave as if they were the original iterators wrapped in any_iterator

7.2 array_range

array_rangeis a non-Copyable Random Access Range which delivers a range presentation of dynamically allocated arrays

std::string str("hello, array_range!");
boost::array<char, 19> sarr;
oven::copy(str, sarr|begin);
oven::array_range<char> darr(19);
oven::copy(str, darr|begin);

BOOST_CHECK( oven::equals(sarr, darr) );
  • 标题<pstade/oven/array_range.hpp>
  • Valid expressionarray_range<T> rng(sz);
  • Preconditionnew T[sz];is a valid expression.

7.3 directory_range

directory_rangeis a Single Pass Range which accesses the contents of a directory

BOOST_FOREACH (
    filesystem::path const& pt,
    directory_range(filesystem::current_path()))
{
    std::cout << pt.leaf() << std::endl;
}
  • 标题<pstade/oven/directory_range.hpp>; not included by<pstade/oven/ranges.hpp>
  • Valid expressiondirectory_range rng(p);wdirectory_range wrng(wp);
  • Precondition: The type ofpisboost::filesystem::pathand the type ofwpisboost::filesystem::wpath.
  • Returns: A range whose iterators behave as if they were the original iterators wrapped in directory_iterator

7.4 empty_range

empty_rangeis a Random Access Range which is always empty

BOOST_CHECK( boost::empty(empty_range<int>()) );
  • 标题<pstade/oven/empty_range.hpp>
  • Valid expressionempty_range<T> rng;

7.5 file_range

file_rangeis a constant Random Access Range for files

std::vector<char> vec;
oven::copy(file_range<char>("data.txt"), std::back_inserter(vec));
  • 标题<pstade/oven/file_range.hpp>
  • Valid expressionfile_range<C> rng;rng.is_open();
  • Preconditionboost::spirit::file_iterator<C>is a valid expression.
  • Returns: A range whose iterators behave as if they were the original iterators wrapped in file_iterator

The memberis_open()returnstrueif and only if the file opening is succeeded. Ifis_open()is nottrue, the range is empty.

8 Range Makers

Oven provides some predefined functions which produce a range. All the range returned from the following makers areCopyConstructibleInheritable. <pstade/oven/functions.hpp>includes every maker header unless otherwise specified.

8.1 as_array

The current Boost.Range regards char array as literal, whichas_arrayworks around.

  • 标题<pstade/oven/as_array.hpp>
  • Valid expressionas_array(arr)arr|as_array
  • Effect: same as TR2 as_array

8.2 as_c_str

as_c_strmakes a Random Access Range from null-terminated c-style string

{
    wchar_t const *psz = L"hello range";
    BOOST_CHECK( oven::equals(psz|as_c_str, std::wstring(L"hello range")) );
}
{
    std::string src("hello range");
    BOOST_CHECK( oven::equals(src.c_str()|as_c_str, src) );
}
  • 标题<pstade/oven/as_c_str.hpp>
  • Valid expression2as_c_str(x)x|as_c_str.
  • Returns: Ifxis convertible to a char pointer,[x,x+strlen(psz)); otherwise,[boost::begin(x),oven::find(x,0)).

8.3 as_literal

as_literalmakes a Random Access Range from character array.as_literaldoesn't support any pointer type but array type. So it is safe and fast. Compare it withas_c_str:

{
    BOOST_CHECK( oven::equals("hello range"|as_literal, std::string("hello range")) );
}
{
    BOOST_CHECK( oven::equals(
        "hello\0range"|as_c_str,
        std::string("hello")
    ) );
    BOOST_CHECK( oven::equals(
        "hello\0range"|as_literal,
        std::string("hello")|jointed('\0'|as_single)|jointed(std::string("range"))
    ) );
}
  • 标题<pstade/oven/as_literal.hpp>
  • Valid expression1as_literal(x)x|as_literal
  • Returns:Ifxis an array,[&x[0],&x[0]+sz-1)其中szis the size ofarr; otherwise,xas is. [7]
[7] as_literaldoesn't usestrlen. TR2 as_literal does.

8.4 as_single

as_singlemakes a Random Access Range which delivers a range presentation of one object

BOOST_CHECK( oven::equals('a'|as_single, std::string("a")) );
  • 标题<pstade/oven/as_single.hpp>
  • Valid expressionas_single(v)v|as_single
  • Returns: A range which behaves as if it were[&v,&v+1).

8.5 as_shared_single

  • 标题<pstade/oven/as_single.hpp>
  • Valid expressionas_shared_single(p)p|as_shared_single
  • Preconditionboost::shared_ptris constructible fromp.
  • Returns: A range which behaves as if it were[&*p,&*p+1).

8.6 counting

countingintroduces the replacement offorloop

int ans[] = { 2, 3, 4, 5, 6 };
BOOST_CHECK( oven::equal(counting(2, 7), ans) );

std::vector<int> vec;
BOOST_FOREACH (int i, counting(0, 5)) {
    vec.push_back(i);
}
  • 标题<pstade/oven/counting.hpp>
  • Valid expressioncounting(n, m), wherenmisIncrementable.
  • Returns: A range whose iterators behave as if they were the original iterators wrapped in counting_iterator

8.7 counting_from

  • 标题<pstade/oven/counting.hpp>
  • Valid expressioncounting_from(n), wherenisIncrementable.
  • Returns: A range which behaves as ifcounting(n,std::numeric_limits<N>::max()), whereNis the type ofn.

8.8 generation

generationreturns a range whose iterators were originally written as generator_iterator

struct rand_generator
{
    typedef boost::optional<long> result_type;

    result_type operator()()
    {
        long result = std::rand();
        if (result % 3 == 0)
            return result_type(); // range is end.

        return result;
    }
};

void test()
{
    rand_generator X;
    BOOST_FOREACH (long x, oven::generation(X)) {
        std::cout << x << std::endl;
    }
}
  • 标题<pstade/oven/generation.hpp>
  • Valid expressiongeneration(rfun)
  • Preconditionrfuncall returns initializedboost::optionalif range is not end; Otherwise, returns uninitialized one.
  • Returns: A Single Pass Range whose values are the results of invokingrfun.

If you have a Standard conforming Generator, you can convert it togenerationconforming one by using innumerable.

8.9 indexing

Pending...

8.10 iteration

iterationmakes an infinite range where the first item is calculated by applying the function on the first argument, the second item by applying the function on the previous result and so on

int answer[] = { 1,2,4,8,16 };
BOOST_CHECK( oven::equals(answer,
    oven::iteration(1, regular(lambda::_1 * 2))|oven::taken(5)
) );
  • 标题<pstade/oven/iteration.hpp>
  • Valid expressioniteration(x,fun)
  • Returns: An infinite [8] Single Pass Range of repeated applications offuntox.
[8] Strictly speaking, the Single Pass Range concept doesn't allow an infinite range. So assume here the end iterator is reachable from the begin iterator in the googolplex number of increments.

8.11 recursion

recursion, collaborating with any_range, creates a recursive [9] range

typedef any_range<int const&, boost::forward_traversal_tag> range_t;
range_t fibs;
memo_table tb;
int const start[] = { 1, 1 };
fibs =
    start
        | transformed(pstade::as_value)
        | jointed(
            boost::make_tuple(recursion(fibs), recursion(fibs)|dropped(1))
                | zipped_with(regular(lambda::_1 + lambda::_2))
            )
        | memoized(tb)
;

std::cout << (fibs|taken(howMany));
  • 标题<pstade/oven/recursion.hpp>
  • Valid expressionrecursion(fwdRng), wherefwdRngis anany_rangeobject.
  • Returns: An infinite range up to Bidirectional Range.
[9] In a recursive range,memoizedmust take a namedmemo_tableobject. A recursive range tends to be inefficient without memoization.

8.12 repeated

repeatedmakes a Random Access Range where all values are the first argument

BOOST_CHECK( oven::equals(
    'A'|repeated(6),
    std::string("AAAAAA")
) );
  • 标题<pstade/oven/repeated.hpp>
  • Valid expressionv|repeated(c)make_repeated(v,c)
  • Returns: A range which behaves as if it wereas_single(v)|cycled(c).

8.13 stream_input

stream_inputmakes a Single Pass Range fromstd::coutetc

std::string src("hello,stream_input!");

std::stringstream ss;
ss << src;

std::string result;
oven::copy(oven::stream_input<char>(ss), std::back_inserter(result));

BOOST_CHECK( oven::equals(result, src) );
  • Valid expressionoven::stream_input<V>(stm)
  • Returns: A range whose iterators behave as if they were the original iterators wrapped in istream_iterator

8.14 streambuf_input

  • 标题<pstade/oven/stream_input.hpp>
  • Valid expressionoven::streambuf_input(stm)
  • Returns: A range whose iterators behave as if they were the original iterators wrapped inistreambuf_iterator

9 Range Adaptors

A Range Adaptor delivers an altered presentation of one or more underlying ranges. Range Adaptors are lazy, meaning that their elements are only computed on demand. The underlying ranges are not modified. Additional information is available at Range Library Proposal.<pstade/oven/adaptors.hpp>includes all the following Range Adaptors unless otherwise specified.

Note that all the range returned from the following adaptors areCopyConstructibleInheritable. Also, ifa0|xxx(a1,..,aN)is a valid expression, thenmake_xxx(a0,..,aN)too is a valid expression which has the same effect.

9.1 adjacent_filtered

9.2 adjacent_transformed

  • 标题<pstade/oven/adjacent_transformed.hpp>
  • Valid expressionfwdRng|adjacent_transformed(rfun)
  • Preconditionboost::empty(fwdRng) == false
  • Returns: A range where adjacent pairs offwdRngare transformed by usingrfun.

9.3 advanced

  • 标题<pstade/oven/advanced.hpp>
  • Valid expressionfwdRng|advanced(d1,d2)
  • PreconditionfwdRngmust be a Bidirectional Range if eitherd1d2is negative.
  • Returns[boost::next(boost::begin(fwdRng),d1),boost::next(boost::end(fwdRng),d2)).

9.4 always

alwaysreturns a range which does not change as the base range vary

BOOST_CHECK( oven::equals(
    std::string("labor")
        | jointed(std::string("will be"))
        | always("lost"),
    std::string("lost")
) );
  • 标题<pstade/oven/always.hpp>
  • Valid expressionunusedRng|always(rng)
  • Returns[boost::begin(rng),boost::end(rng)).

9.5 appended

appendedreturns a range which is appended with its argument

std::string const str("hello, appen");

BOOST_CHECK( oven::equals(
    str|appended('d')|appended('e')|appended('d')|appended('!'),
    std::string("hello, appended!")
) );
  • 标题<pstade/oven/appended.hpp>
  • Valid expressionrng|appended(v)
  • Returns: A range which behaves as if it wererng|jointed(as_single(v)).

9.6 applied

applied, taking a Function Object which represents an algorithm, creates the range adaptor

namespace lambda = boost::lambda;
std::string src("abcdefghijk");
std::string s1("efg");
BOOST_CHECK((
    oven::equals(
        std::string("efghijk"),
        src|applied(lambda::bind(oven::search, lambda::_1, s1), oven::end)
    )
));
  • 标题<pstade/oven/applied.hpp>
  • Valid expression1rng|applied(f1,f2), wheref1(rng)f2(rng)must return iterators that are convertible torng's.
  • Valid expression2rng|applied(f), wheref(rng)must return a range whose iterators are convertible torng's.
  • Returns[f1(rng),f2(rng)), or[boost::begin(r),boost::end(r))其中r = f(rng), respectively.

9.7 broken_into

broken_intois the adaptor version ofboost::tokenizer:

int const offsets[] = { 2,2,4 };
std::string src("12252001");
std::vector<std::string> ans; {
    ans.push_back("12");
    ans.push_back("25");
    ans.push_back("2001");
}

BOOST_CHECK( oven::equals(
    ans,
    src|broken_into<std::string>(boost::offset_separator(offsets, offsets+3))
) );
  • 标题<pstade/oven/broken_into.hpp>
  • Valid expressionrng|broken_into<t>(f), wherefis aTokenizerFunction.
  • Returns: A range whose iterators behave as if they were the original iterators wrapped inboost::token_iterator.

9.8 checked

checkedadds the bounds checking ability to the base range

std::string in("012345");
std::string out("01234");

try {
    oven::copy(in, boost::begin(out|checked));
}
catch (check_error const& ) {
    return;
}

BOOST_CHECK(false);
  • 标题<pstade/oven/checked.hpp>
  • Valid expressionrng|checked
  • Effect: Throwscheck_errorderived fromstd::range_errorif iterators go out ofrng.
  • Returns[boost::begin(rng),boost::end(rng))

9.9 cleared

clearedreturns a range which is always empty

BOOST_CHECK( boost::empty(
    std::string("labor")
        | jointed(std::string("lost"))
        | cleared
) );
  • 标题<pstade/oven/cleared.hpp>
  • Valid expressionrng|cleared
  • Returns[boost::end(rng),boost::end(rng)).

9.10 concatenated

concatenatedaccepts a range whosevalue_typeis a range and concatenates them

std::string input("This is his face");
boost::regex re("\\w+");
BOOST_CHECK( oven::equals(
    input|tokenized(re)|concatenated,
    std::string("Thisishisface")
) );
  • 标题<pstade/oven/concatenated.hpp>
  • Valid expressionrngs|concatenated
  • SpecificationSegmentIteratoris an iterator ofrngs, andLocalIteratoris an iterator of the range which the dereference ofSegmentIteratorreturns.
  • Precondition: TheLocalIteratormust be valid after copying ofSegmentIterator.

9.11 constants

  • 标题<pstade/oven/constants.hpp>
  • Valid expressionrng|constants
  • Returns[boost::end(rng),boost::end(rng))whose iterators are constant.

9.12 const_lvalues

const_lvaluesturns the associatedreferencetype of the base range into reference type, which makes iterators of Forward Range conform toForwardIterator. Thus, STL that doesn't know traversal concepts can choose effective algorithms.

  • 标题<pstade/oven/const_lvalues.hpp>
  • Valid expressionrng|const_lvalues
  • Preconditionvalue_typeofrngisCopyConstructible, AssignableDefaultConstructible.
  • Returns[boost::begin(rng),boost::end(rng))whose iterators are constant.

9.13 copied_out

copied_outmakes a side-effect that copies the base range to its argument

std::string src("axaxaxbxbxbx");
std::string snapshot;
std::string answer("bbb");

BOOST_CHECK( oven::equals(
    src
        | filtered(regular(lambda::_1 != 'x'))
        | copied_out(std::back_inserter(snapshot))
        | filtered(regular(lambda::_1 != 'a')),
    answer
) );

BOOST_CHECK( snapshot == "aaabbb" );
  • 标题<pstade/oven/copied_out.hpp>
  • Valid expressionrng|copied_out(it)
  • Preconditionoven::copy(rng,it)is a valid expression.
  • Effectoven::copy(rng,it)
  • Returnsrng.

9.14 cycled

cycledcreates a circular range from the base range

BOOST_CHECK( oven::equals(
    std::string("xyz")|cycled(3),
    std::string("xyzxyzxyz")
) );
  • 标题<pstade/oven/cycled.hpp>
  • Valid expressionrng|cycled(n)
  • Returns: A constant range that repeats[boost::begin(rng),boost::end(rng)) ntimes.

9.15 delimited

delimitedadds a delimiter to the base range

BOOST_CHECK( equals(
    std::string("abcde")|transformed(as_single)|
        delimited("--"|as_literal)|dropped(2),
    std::string("a--b--c--d--e")
) );
  • 标题<pstade/oven/delimited.hpp>
  • Valid expressionrngs|delimited(delim), wheredelimis a Range to specify the delimiter.
  • Returns: A range which behaves as if it wererngs|transformed(with)|concatenated, whereis a Function Object which callsmake_jointedto jointdelim. [10]
[10] delimitedprepends the delimiter.droppedis useful to remove it.

9.16 directed

directedreturns a range whose values are iterators of the base range

std::string const str("gefadcb");
std::string const answer("abcdefg");

std::vector<std::string::const_iterator> iters;
oven::copy(str|directed, std::back_inserter(iters));
oven::sort( iters, boost::make_indirect_fun(::less_than()) );

BOOST_CHECK( oven::equals(iters|indirected, answer) );
  • 标题<pstade/oven/directed.hpp>
  • Valid expressionrng|directed
  • Returns: A range which behaves as if it werecounting(boost::begin(rng),boost::end(rng)).

9.17 dropped

droppedreturns the suffix of the base range after the firstnelements

BOOST_CHECK( oven::equals(
    std::string("hello, dropped!")|dropped(7),
    std::string("dropped!")
) );
  • 标题<pstade/oven/dropped.hpp>
  • Valid expressionrng|dropped(n)
  • Precondition0 <= n
  • Returns[boost::next(boost::begin(rng),std::min(n,distance(rng))),boost::end(rng))

9.18 dropped_while

dropped_whilereturns the remaining suffix of the base range of elements that satisfy Predicate

std::string src("11111234516313!");

BOOST_CHECK( oven::equals(
    src|dropped_while(lambda::_1 == '1'),
    std::string("234516313!")
) );
  • 标题<pstade/oven/dropped_while.hpp>
  • Valid expressionrng|dropped_while(pred)
  • Returns[oven::find_if(rng, not_(pred)),boost::end(rng))

9.19 filtered

filteredreturns a range which is filtered by using a Predicate [11]

int src[]    = { 2,5,2,6,1,3,2 };
int answer[] = { 0,5,0,6,1,3,0 };

BOOST_FOREACH (int& i, src|filtered(regular(lambda::_1 == 2))) {
    i = 0;
}

BOOST_CHECK( oven::equals(answer, src) );
[11] A non-assignable lambda functor makesfilterednon-conforming, so it needs regular to be applied before it is passed.

9.20 firsts

  • 标题<pstade/oven/firsts.hpp>
  • Valid expressionrng|firsts
  • Returns: A range which behaves as if it wererng|map_keys.

9.21 got_at

Pending...

  • 标题<pstade/oven/got_at.hpp>
  • Valid expressionrng|got_at<N>()rng|got_at_c<N>(), wherevalue_typeofrngis a Fusion Sequence.

9.22 identities

identitiesreturns a range which is identical to the base range

BOOST_CHECK( oven::equals(
    std::string("hello, identities!")|identities,
    std::string("hello, identities!")
) );
  • 标题<pstade/oven/identities.hpp>
  • Valid expressionrng|identitiesrng|identities(trv), wheretrvis a traversal tag object.
  • Preconditionrng's traversal tag is convertible totrv.
  • Returns[boost::begin(rng),boost::end(rng)).

9.23 indirected

indirectedadapts the base range by applying an extra dereference inside ofoperator*():

int src[]    = { 1,2,0,4,5 };
int answer[] = { 1,2,3,4,5 };
int *ptrs[]  = {&src[0],&src[1],&src[2],&src[3],&src[4]};

BOOST_FOREACH (int& i, ptrs|indirected) {
    if (i == 0)
        i = 3;
}

BOOST_CHECK( oven::equals(src, answer) );

9.24 jointed

jointedreturns a range which is jointed with its argument

std::string str0("every range");
std::vector<char> str1 = std::string(" is")|copied;
std::list<char> str2 = std::string(" string!?")|copied;

BOOST_CHECK( oven::equals(
    str0|jointed(str1)|jointed(str2),
    std::string("every range is string!?")
) );
  • 标题<pstade/oven/jointed.hpp>
  • Valid expressionrng1|jointed(rng2)
  • Precondition: Theboost::range_referenceofrng2is convertible torng1's without creating a rvalue.
  • Returns: A range that joints[boost::begin(rng1),boost::end(rng1))[boost::begin(rng2),boost::end(rng2)).

9.25 map_keys

map_keysreturns a range whose values are the keys of the base associative container

std::map<int, std::string> m;
m[12] = "hello";
m[4]  = "map";
m[99] = "keys";

BOOST_FOREACH (int k, m|map_keys) {
    BOOST_CHECK( k != 12 || m[k] == "hello" );
    BOOST_CHECK( k != 4  || m[k] == "map" );
    BOOST_CHECK( k != 99 || m[k] == "keys" );
}

9.26 map_values

map_valuesreturns a range whose values are the mapped values of the base associative container

std::map<int, std::string> m;
m[12] = "hello";
m[4]  = "map";
m[99] = "keys";

BOOST_FOREACH (std::string& v, m|map_values) {
    if (v == "keys")
        v = "values";
}

BOOST_CHECK( m[12] == "hello" );
BOOST_CHECK( m[4]  == "map" );
BOOST_CHECK( m[99] == "values" );

9.27 matches

  • 标题<pstade/oven/matches.hpp>; not included by<pstade/oven/ranges.hpp>
  • Valid expressionbiRng|matches(re)biRng|matches(re,flag)
  • Returns: A range whose iterators behave as if they were the original iterators wrapped inboost::regex_iterator.

9.28 memoized

memoizedreturns a range whose values are cached for speed, preparing for repeated dereferences

std::stringstream ss;
ss << "hello, memoized!";

::very_complicated_algorithm(
    oven::stream_input<char>(ss)
        | memoized
        | directed
        | indirected
        | sorted
        | memoized
);
  • 标题<pstade/oven/memoized.hpp>
  • Valid expressionrng|memoizedrng|memoized(tb), wheretbis a namedmemo_tableobject.
  • Preconditionboost::range_valueofrngisCopyConstructible. tbhas longer lifetime than the use of returned range.
  • Returns: A Forward Range whose values are memoized. [12]
[12] memoizedcan return a Forward Range even if the base range is a Single Pass Range.

9.29 merged

mergedcombines two sorted ranges into a single sorted range

std::string A1("abbbfH");
std::string A2("ABbCDFFhh");
std::string AA("aAbbbBbCDfFFHhh");
BOOST_CHECK( oven::equals(A1|merged(A2, &::lt_nocase), AA) );
  • 标题<pstade/oven/merged.hpp>
  • Valid expressionrng1|merged(rng2)rng1|merged(rng2,pred)
  • Preconditionrng1rng2are sorted.
  • Returns: A constant range up to Forward Range which behaves as if they were made bystd::merge.

9.30 permuted

  • 标题<pstade/oven/permuted.hpp>
  • Valid expressionrndRng|permuted(rng)
  • Preconditionrngis a range of the indices ofrndRng.
  • Returns: A range whose iterators behave as if they were the original iterators wrapped inboost::permutation_iterator.

9.31 pointed

pointedprovides an interface to have a conversation with legacy APIs

std::string const src("hello, pointed");
std::vector<char> vec;
vec.resize(oven::distance(src) + 1);
std::strcpy(boost::begin(vec|pointed), src.c_str());
BOOST_CHECK(( oven::equals(vec|null_terminated, src) ));
  • 标题<pstade/oven/pointed.hpp>
  • Valid expressionvec|pointed
  • Preconditionvecis a template instantiation ofstd::vector.
  • Returns[&*boost::begin(vec),&*boost::begin(vec)+oven::distance(vec))ifvecis not empty; otherwise,[0,0).

9.32 popped

  • 标题<pstade/oven/popped.hpp>
  • Valid expressionfwdRng|popped
  • Preconditionboost::empty(fwdRng) == false
  • Returns[boost::begin(fwdRng),boost::next(boost::begin(fwdRng),oven::distance(fwdRng)-1))

9.33 prepended

  • 标题<pstade/oven/prepended.hpp>
  • Valid expressionrng|prepended(v)
  • Returns: A range which behaves as if it wereas_single(v)|jointed(rng).

9.34 reversed

9.35 rotated

  • 标题<pstade/oven/rotated.hpp>
  • Valid expressionfwdRng|rotated(fun)
  • Returns[fun(fwdRng),boost::end(fwdRng))|jointed([boost::begin(fwdRng),fun(fwdRng)))

9.36 scanned

scannedis similar tooven::accumulate, but returns a range of successive reduced values from the base range

int const src[] = { 1,2,3,4,5 };
std::string null;

BOOST_FOREACH (std::string str, src|scanned(null, &::stringize)) {
    std::cout << "\"" << str << "\" ";
}
// outputs: "" "1" "12" "123" "1234" "12345"
  • 标题<pstade/oven/scanned.hpp>
  • Valid expressionrng|scanned(init,fun), where the type ofinitisDefaultConstructible, CopyConstructibleCopyAssignable.
  • Preconditionfun(s,r)is a valid expression, where the type ofsis the same asinitris the iterator dereference ofrng.
  • Returns: A range up to Forward Range which behaves as if it were made bystd::partial_sum.

9.37 seconds

  • 标题<pstade/oven/seconds.hpp>
  • Valid expressionrng|seconds
  • Returns: A range which behave as if it wererng|map_values.

9.38 set_cap

  • 标题<pstade/oven/set_cap.hpp>
  • Valid expressionrng1|set_cap(rng2)rng1|set_cap(rng2,pred)
  • Preconditionrng1rng2are sorted.
  • Returns: A constant range up to Forward Range which behaves as if they were made bystd::set_intersection.

9.39 set_cup

  • 标题<pstade/oven/set_cup.hpp>
  • Valid expressionrng1|set_cup(rng2)rng1|set_cup(rng2,pred)
  • Preconditionrng1rng2are sorted.
  • Returns: A constant range up to Forward Range which behaves as if they were made bystd::set_union.

9.40 set_delta

  • 标题<pstade/oven/set_delta.hpp>
  • Valid expressionrng1|set_delta(rng2)rng1|set_delta(rng2,pred)
  • Preconditionrng1rng2are sorted.
  • Returns: A constant range up to Forward Range which behaves as if they were made bystd::set_symmetric_difference.

9.41 set_minus

  • 标题<pstade/oven/set_minus.hpp>
  • Valid expressionrng1|set_minus(rng2)rng1|set_minus(rng2,pred)
  • Preconditionrng1rng2are sorted.
  • Returns: A constant range up to Forward Range which behaves as if they were made bystd::set_difference.

9.42 shared

shared, taking a pointer to heap-allocated range, makes a range whose iterators manage its lifetime

BOOST_FOREACH (char ch, std::string("dangling")|identities) {
    // will crash; 'std::string' object doesn't exist anymore. 
    std::cout << ch;
}

BOOST_FOREACH (char ch, new std::string("ok")|shared|identities) {
    // works fine.
    std::cout << ch;
}
  • 标题<pstade/oven/shared.hpp>
  • Valid expressionp|shared
  • Preconditionboost::shared_ptris constructible fromp.
  • Returns: A range whose iterators behave as if they were the original iterators wrapped in shared_container_iterator.

You can find a more elaborate example at<pstade/oven/sorted.hpp>.

9.43 sliced

sliced[13] provides the column view of the base range

int const answer[] = { 2,6,10,14 };
BOOST_CHECK( oven::equals(answer,
    counting(0, 16)|sliced(2, 4)
) );
  • 标题<pstade/oven/sliced.hpp>
  • Valid expressionrndRng|sliced(start,stride)
  • Preconditiond == 0 || d % stride == 00 <= start && start < stride, whered = oven::distance(rndRng);
[13] This name is different from Range Library Proposal's, which is the role of advanced or window.

9.44 string_found

  • 标题<pstade/oven/string_found.hpp>
  • Valid expressionrng|string_found(finder)
  • Returns: A range whose iterators behave as if they were the original iterators wrapped inboost::algorithm::find_iterator.

9.45 string_split

  • 标题<pstade/oven/string_split.hpp>
  • Valid expressionrng|string_split(finder)
  • Returns: A range whose iterators behave as if they were the original iterators wrapped inboost::algorithm::split_iterator.

9.46 taken

taken, applied to the base range, returns the prefix of the range of lengthn:

std::string src("hello, taken!");
std::string ans("hello");
BOOST_CHECK( oven::equals(src|taken(7)|taken(5), ans) );
  • 标题<pstade/oven/taken.hpp>
  • Valid expressionrng|taken(n)
  • Precondition0 <= n
  • Returns: A range up to Forward Range which behaves as if it were[boost::begin(rng),boost::next(boost::begin(rng),std::min(n, distance(rng)))).

9.47 taken_while

taken_while, applied to a Predicate and the base range, returns the longest prefix (possibly empty) of the range of elements that satisfy Predicate

std::string src("11111234516313!");

BOOST_CHECK( oven::equals(
    src|taken_while(lambda::_1 == '1'),
    std::string("11111")
) );
  • 标题<pstade/oven/taken_while.hpp>
  • Valid expressionrng|taken_while(pred)
  • Returns: A range up to Forward Range which behaves as if it were[boost::begin(rng),oven::find_if(rng,not_(pred)))

9.48 tokenized

9.49 transformed

9.50 uniqued

9.51 unzipped

unzippedreverseszipped:

std::cout <<
    (
        assign::list_of
            (boost::make_tuple(1,2))
            (boost::make_tuple(2,3))
            (boost::make_tuple(3,4))
            | unzipped
    );

// output> ({1,2,3} {2,3,4})
  • 标题<pstade/oven/unzipped.hpp>
  • Valid expressiontuples|unzipped, wheretuplesis a range whose value_type isboost::tuple.
  • Returns: Aboost::tuplewhose elements are unzipped ranges.

9.52 utf8_decoded

  • 标题<pstade/oven/utf8_decoded.hpp>
  • Valid expressionbiRng|utf8_decoded
  • Returns: A Bidirectional Range whose iterators behave as if they were the original iterators wrapped inboost::u8_to_u32_iterator.

9.53 window

  • 标题<pstade/oven/window.hpp>
  • Valid expressionfwdRng|window(n,m)
  • Returns[boost::next(boost::begin(rng),n),boost::next(boost::begin(rng),m)).

9.54 with_position

  • 标题<pstade/oven/with_position.hpp>
  • Valid expressionrng|with_position
  • Returns: A range whose iterators behave as if they were the original iterators wrapped inboost::spirit::position_iterator.

9.55 xpressive_matches

  • 标题<pstade/oven/xpressive_matches.hpp>; not included by<pstade/oven/ranges.hpp>
  • Valid expressionbiRng|xpressive_matches(re)biRng|xpressive_matches(re,flag)
  • Returns: A range whose iterators behave as if they were the original iterators wrapped inboost::xpressive::regex_iterator.

9.56 xpressive_tokenized

  • 标题<pstade/oven/xpressive_tokenized.hpp>; not included by<pstade/oven/ranges.hpp>
  • Valid expressionbiRng|xpressive_tokenized(re)biRng|xpressive_tokenized(re,subMatches,flag)
  • Returns: A range whose iterators behave as if they were the original iterators wrapped inboost::xpressive::regex_token_iterator.

9.57 zipped

zippedtakes a tuple of ranges and returns a range of corresponding tuples. If one input range is short, excess elements of the longer range are discarded

std::cout <<
    (
        boost::make_tuple(
            assign::list_of(1)(2)(3),
            assign::list_of(2)(3)(4)
        )
            | zipped
    );

// output> {(1 2),(2 3),(3 4)}
  • 标题<pstade/oven/zipped.hpp>
  • Valid expressionrngs|zipped, whererngsis aboost::tupleof ranges.
  • Returns: A range whose iterators behave as if they were the original iterators wrapped inboost::zip_iterator.

9.58 zipped_with

zipped_withgeneraliseszippedby zipping with the Function Object, given as the first argument, instead of a tupling

int xs[]  = { 0, 1, 2, 3, 4, 5, 6 };
int ys[]  = { 1, 6, 1, 2, 7, 8, 3 };
int ans[] = { 1, 7, 3, 5,11,13, 9 };

BOOST_CHECK( oven::equals(
    boost::tie(xs, ys)|zipped_with(::plus()),
    ans
) );
  • 标题<pstade/oven/zipped_with.hpp>
  • Valid expressionrngs|zipped_with(rfun), whererngsis aboost::tupleof ranges.
  • Precondition1: The arity ofrfunis the length ofrngs.
  • Returns: A range whose values are zipped by usingrfun.

10 Output Iterator Adaptors

10.1 to_counter

to_countertakes an initial count and increments it every output. adapted_to/to_base can extract the result of the counting

int const rng[] = { 0,0,1,1,2,3,3,3,4,4,4,4,4,5,5 };
int i = oven::copy(rng|uniqued, oven::to_counter(0))|to_base;
BOOST_CHECK( i == 6 );

BOOST_CHECK( 7 == oven::adapted_to<int>(oven::unique_copy(rng, oven::to_counter(1))) );
  • 标题<pstade/oven/to_counter.hpp>
  • Valid expressionto_counter(i), whereiis anIncrementable.
  • Returns: AnOutputIteratorwhich counts the output.

10.2 to_function

to_functionreturns anOutputIteratorwhich is a port of boost::function_output_iterator with some workarounds.

  • 标题<pstade/oven/to_function.hpp>
  • Valid expressionto_function(fun)
  • Returns: AnOutputIteratorwhich behaves as if it wereboost::function_output_iterator.

10.3 to_stream

to_streamreturns anOutputItertorwhich is a shorthand version ofstd::ostream_iterator. It needs no an explicit template parameter to specify thevalue_typeto output, but one precondition below must be kept. Generally, theboost::iterator_referenceofInputIteratormust be the same asvalue_typeof it except for reference qualifier.

  • 标题<pstade/oven/to_stream.hpp>
  • Valid expressionto_stream(os)
  • Precondition: The type to be assigned to dereference of an iterator whichto_streamreturns must be anOutputStreamable.
  • Returns: AnOutputIteratorwhich behave as if it werestd::ostream_iterator.

10.4 to_utf8_encoder

  • 标题<pstade/oven/to_utf8_encoder.hpp>
  • Valid expressionto_utf8_encoder(oit), whereoitis anOutputIterator.
  • Returns: AnOutputIteratorwhich behave as if it wereboost::utf8_output_iterator.

11 Extending Boost.Range

The extension way of Boost.Range seems to assume the future C++ abilitydecltype. For now, it is not practical to apply the way to a large library something like MFC. Oven provides yet another extension way, which is similar to Conceptualizing the Range-Based for Loop proposal to simplify the Boost.Range one

namespace Foo {

    template< class T >
    struct Pair
    {
        T first, last;
    };

} // namespace Foo

namespace pstade_oven_extension {

    template< class T >
    struct Range< Foo::Pair<T> >
    {
        // X == Foo::Pair<T>
        template< class X >
        struct associate
        {
            typedef T mutable_iterator;
            typedef T constant_iterator;
        };

        // if X is not const, Iterator == mutable_iterator;
        // otherwise, Iterator == constant_iterator.
        template< class Iterator, class X >
        Iterator begin(X& x)
        {
            return x.first;
        }

        template< class Iterator, class X >
        Iterator end(X& x)
        {
            return x.last;
        }
    };

} // namespace pstade_oven_extension

PSTADE_OVEN_EXTENSION_OF_TEMPLATE((Foo)(Pair), (class))
// PSTADE_OVEN_EXTENSION_OF_TEMPLATE((Foo)(Pair), 1) // also ok.
  1. Specialize::pstade_oven_extension::Range.
  2. Define templateassociate, beginend.
  3. Call the macro, in global namespace, to act as a bridge between Oven and Boost.Range.

Note that the const overloads can be sometimes omitted like above. Also,Rangehas the second template parameter forpstade::enable_if. boost::sizeis automatically extended by Oven.

  • 标题<pstade/oven/extension.hpp>
  • Valid expression1PSTADE_OVEN_EXTENSION_OF_TYPE(X)
  • Valid expression2PSTADE_OVEN_EXTENSION_OF_TEMPLATE(X,N), whereNis the number of template arguments. Only valid if all template arguments are typenames.
  • Valid expression3PSTADE_OVEN_EXTENSION_OF_TEMPLATE(X,S), whereSis a sequence of template arguments. Must be used when integral or template template parameters are present.
  • PreconditionXis a Boost.Preprocessor Sequence of type name.

12 MFC/ATL Extension

Oven provides Boost.Range support for MFC/ATL collection and string types. See Oven Range MFC/ATL Extension.

14 Release Notes

14.1 Version 0.90.0

  • Released initial version.

14.2 Version 0.90.1 - 0.90.6

  • Updated this document.
  • Implemented Range Algorithms.
  • Added some Ranges and Range Adaptors.
  • Added some Range Adaptors.
  • Changed the header of permuted.
  • Changed the header ofpointed.
  • Changed a valid expression of zipped.
  • Changed checked to throw exception.
  • Renamedfoundto string_found.
  • Changed the header of Range Algorithms.
  • Addedbase_iterator.
  • Added some Range Adaptors.
  • Renamedaccumulatedto scanned.
  • Added workaround for Standard Library Defect #198.
  • Changed constants semantics, and added always instead.
  • Changed utf8_decoded valid expression.
  • shared acceptsauto_ptr.

14.3 Version 0.90.7 - 0.90.9

  • Addedmatched, xpressive_matchedxpressive_tokenized.
  • Renamedbase_iteratortoto_base.
  • Renamedcopiedadaptor tocopied_to.
  • Added concatenated.
  • Renamedcopied_totocopied_out.
  • Fixed a bug oftransformedconcatenated.
  • Addedgenerated.
  • No longer supports function types asrfun.
  • Changed utf8_decoded valid expression.

14.4 Version 0.91.0 - 0.91.3

  • Added Output Iterator Adaptors.
  • Renamedgeneratedtogeneration.
  • Renamedpositionedtowith_position.
  • Renamedmatchedtomatches.
  • Renamedxpressive_matchedtoxpressive_matches.
  • Added Extending Boost.Range.
  • 已拒绝out_placedsorted.
  • Addedliteral_rangec_str_range.
  • null_terminatedno longer supports c-string.
  • Addedas_singletosingle_range's valid expressions.
  • Addedbegins/ends.
  • Addedmerged, set_cup, set_cap, set_minusset_delta.
  • Addedrotated.
  • Removedstriddenand changed effects ofsliced.
  • Addedthrough_window.
  • Addedpopped.
  • Changed the valid expression ofarray_protect_rangeliteral_range.
  • Addedto_function.
  • Renamedshiftedtoadvanced.

14.5 Version 0.91.4 - 0.91.9

  • Addedany_range.
  • Removedpoppedand changed the valid expression ofadvanced.
  • Removedgenerationas adaptor and added it as range.
  • takentaken_whilesupports Single Pass Range.
  • Addediterate_range.
  • Addedadjacent_transformed.
  • Addedpopped_back.
  • Changedcounting_rangevalid expressions.
  • Renamedrepeatedtocycled.
  • Addedrepeat_range.
  • Renamedpopped_backtopopped.
  • Changed the valid expressions ofzippedzipped_with.
  • Ported to VC++7.1 SP1.
  • Added MFC/ATL support.

14.6 Version 0.92.0 - 0.92.3

  • Renamedcounting_rangetocount_range, and added a valid expression.
  • Removed the valid expressionadvanced(d).
  • Renamedtietopack.
  • Addedboost::result_ofsupport to range-based algorithms.
  • Renamed Extending Boost.Range macros.
  • Renamedadaptor_totoadapted_to.

14.7 Version 0.93.0

  • Changed the names of some functions and headers.
  • Addeddelimited.

14.8 Version 0.93.1

  • Renamedbegins/endstobegin/end.
  • adjacent_transformedrejects empty range.
  • Changed template parameter ofany_range.
  • Replacedregularizedregular.
  • Removedto_regularized_function.
  • scannedrange contains theinitas the first element.

14.9 Version 0.93.2

  • takentaken_whilebehave lazily.
  • takentaken_whilenow return only up to ForwardRange.
  • droppedtakenacceptnwhich is larger than the distance.
  • Removednull_terminated.
  • as_c_straccepts a range.
  • zippedzipped_withaccept any tuple.
  • Removedgeneration_copied.
  • Addedshared_regularinnumerable.

14.10 Version 0.93.3

  • Fixed a bug ofgeneration.
  • Addedfrontback.
  • Addedrecursion.
© . All rights reserved.