2009-12-29 03:42:33 +01:00
|
|
|
/*
|
|
|
|
|
UtilForeach(Test) - helpers for doing something for each element
|
|
|
|
|
|
|
|
|
|
Copyright (C) Lumiera.org
|
|
|
|
|
2009, Hermann Vosseler <Ichthyostega@web.de>
|
|
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU General Public License as
|
|
|
|
|
published by the Free Software Foundation; either version 2 of the
|
|
|
|
|
License, or (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
|
|
|
|
|
* *****************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "lib/test/run.hpp"
|
2009-12-29 04:39:27 +01:00
|
|
|
#include "lib/util-foreach.hpp"
|
2009-12-29 03:42:33 +01:00
|
|
|
#include "lib/iter-adapter.hpp"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <boost/lexical_cast.hpp>
|
|
|
|
|
#include <boost/lambda/lambda.hpp>
|
|
|
|
|
#include <tr1/functional>
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
using ::Test;
|
|
|
|
|
|
|
|
|
|
using util::for_each;
|
|
|
|
|
using util::has_any;
|
|
|
|
|
using util::and_all;
|
|
|
|
|
|
|
|
|
|
using boost::lexical_cast;
|
|
|
|
|
using std::tr1::function;
|
|
|
|
|
using std::tr1::ref;
|
|
|
|
|
using std::cout;
|
|
|
|
|
using std::endl;
|
|
|
|
|
|
|
|
|
|
using namespace boost::lambda;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace util {
|
|
|
|
|
namespace test {
|
|
|
|
|
|
|
|
|
|
typedef std::vector<int> VecI;
|
|
|
|
|
typedef lib::RangeIter<VecI::iterator> RangeI;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace{ // Test data and operations
|
|
|
|
|
|
|
|
|
|
uint NUM_ELMS = 10;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// need explicit definitions here, because we use
|
|
|
|
|
// tr1/functional and boost::lambda at the same time
|
|
|
|
|
std::tr1::_Placeholder<1> _1;
|
|
|
|
|
boost::lambda::placeholder1_type _1_;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VecI
|
|
|
|
|
buildTestNumberz (uint count)
|
|
|
|
|
{
|
|
|
|
|
VecI numbers;
|
|
|
|
|
numbers.reserve(count);
|
|
|
|
|
while (count)
|
|
|
|
|
numbers.push_back(count--);
|
|
|
|
|
|
|
|
|
|
return numbers;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* == functions to bind and invoke == */
|
|
|
|
|
bool
|
|
|
|
|
plainFunc (int i)
|
|
|
|
|
{
|
|
|
|
|
cout <<':'<< i;
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
function1 (int i, int j)
|
|
|
|
|
{
|
|
|
|
|
return plainFunc(i+j);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
function2 (int i, int j, int& k)
|
|
|
|
|
{
|
2010-01-04 13:34:51 +01:00
|
|
|
k += i + j;
|
2009-12-29 03:42:33 +01:00
|
|
|
return plainFunc(k);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define _NL_ cout << endl;
|
2009-12-31 03:25:25 +01:00
|
|
|
#define ANNOUNCE(_LABEL_) cout << "---:" << STRINGIFY(_LABEL_) << endl;
|
2009-12-29 03:42:33 +01:00
|
|
|
|
|
|
|
|
} // (End) test data and operations
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*********************************************************************
|
|
|
|
|
* @test Invoking an operation for each element of a collection.
|
|
|
|
|
* Covers the various flavours of these convenience helpers:
|
|
|
|
|
* They might operate either on a STL container (providing
|
|
|
|
|
* \c begin() and \c end() functions), or at a "Lumiera
|
|
|
|
|
* Forward Iterator", which is incremented and dereferenced
|
|
|
|
|
* for each value it yields, until exhaustion.
|
|
|
|
|
*
|
|
|
|
|
* Moreover for each of these cases, there are additional
|
|
|
|
|
* overloads allowing to create a bind-expression on-the fly.
|
|
|
|
|
* As a further variation of this scheme, an predicate can be
|
|
|
|
|
* evaluated for each element, either with universal quantisation
|
|
|
|
|
* (results are && combined), or with existential quantisation.
|
|
|
|
|
*/
|
|
|
|
|
class UtilForeach_test : public Test
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
run (Arg arg)
|
|
|
|
|
{
|
|
|
|
|
if (0 < arg.size()) NUM_ELMS = lexical_cast<uint> (arg[0]);
|
|
|
|
|
|
|
|
|
|
VecI container = buildTestNumberz (NUM_ELMS);
|
|
|
|
|
RangeI iterator(container.begin(), container.end());
|
|
|
|
|
|
|
|
|
|
check_foreach_plain (container);
|
2010-01-04 14:23:15 +01:00
|
|
|
check_foreach_plain (iterator);
|
2009-12-29 03:42:33 +01:00
|
|
|
|
|
|
|
|
check_foreach_bind (container);
|
2010-01-04 14:23:15 +01:00
|
|
|
check_foreach_bind (iterator);
|
2009-12-29 03:42:33 +01:00
|
|
|
|
2009-12-31 03:25:25 +01:00
|
|
|
check_foreach_bind_const (container);
|
|
|
|
|
|
2009-12-29 03:42:33 +01:00
|
|
|
check_foreach_memFun (container);
|
2010-01-04 14:23:15 +01:00
|
|
|
check_foreach_memFun (iterator);
|
2009-12-29 03:42:33 +01:00
|
|
|
|
|
|
|
|
check_foreach_lambda (container);
|
2010-01-04 14:23:15 +01:00
|
|
|
check_foreach_lambda (iterator);
|
2009-12-29 03:42:33 +01:00
|
|
|
|
|
|
|
|
check_existence_quant (container);
|
2010-01-04 14:23:15 +01:00
|
|
|
check_existence_quant (iterator);
|
|
|
|
|
|
|
|
|
|
ASSERT (int(NUM_ELMS) ==container[0]);
|
|
|
|
|
|
|
|
|
|
check_ref_argument_bind (container);
|
|
|
|
|
ASSERT (int(NUM_ELMS) ==container[0]);
|
|
|
|
|
|
|
|
|
|
check_ref_argument_bind (iterator);
|
|
|
|
|
ASSERT (60+int(NUM_ELMS) ==container[0]);
|
|
|
|
|
// changes got propagated through the iterator
|
2009-12-29 03:42:33 +01:00
|
|
|
|
2009-12-29 04:30:11 +01:00
|
|
|
check_invoke_on_each ();
|
2009-12-29 03:42:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @test invoke a simple free function, given
|
|
|
|
|
* as reference, function pointer or functor.
|
|
|
|
|
* The invoked test function will print its argument
|
|
|
|
|
*/
|
|
|
|
|
template<typename CO>
|
|
|
|
|
void
|
|
|
|
|
check_foreach_plain (CO coll)
|
|
|
|
|
{
|
2009-12-31 03:25:25 +01:00
|
|
|
ANNOUNCE (check_foreach_plain);
|
2009-12-29 03:42:33 +01:00
|
|
|
function<bool(int)> func(plainFunc);
|
|
|
|
|
|
|
|
|
|
for_each (coll, plainFunc); _NL_
|
|
|
|
|
for_each (coll, &plainFunc); _NL_
|
|
|
|
|
for_each (coll, func); _NL_
|
|
|
|
|
|
|
|
|
|
and_all (coll, plainFunc); _NL_
|
|
|
|
|
and_all (coll, &plainFunc); _NL_
|
|
|
|
|
and_all (coll, func); _NL_
|
|
|
|
|
|
|
|
|
|
has_any (coll, plainFunc); _NL_
|
|
|
|
|
has_any (coll, &plainFunc); _NL_
|
|
|
|
|
has_any (coll, func); _NL_
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @test bind additional parameters on-the-fly,
|
|
|
|
|
* including the possibility to use a placeholder
|
|
|
|
|
* to denote the position of the variable parameter */
|
|
|
|
|
template<typename CO>
|
|
|
|
|
void
|
|
|
|
|
check_foreach_bind (CO coll)
|
|
|
|
|
{
|
2009-12-31 03:25:25 +01:00
|
|
|
ANNOUNCE (check_foreach_bind);
|
2009-12-29 03:42:33 +01:00
|
|
|
function<bool(int,int)> fun1(function1);
|
|
|
|
|
|
|
|
|
|
for_each (coll, function1, 10, _1 ); _NL_
|
|
|
|
|
for_each (coll, &function1,10, _1 ); _NL_
|
|
|
|
|
for_each (coll, fun1, 10, _1 ); _NL_
|
|
|
|
|
|
|
|
|
|
and_all (coll, function1, 10, _1 ); _NL_
|
|
|
|
|
and_all (coll, &function1, 10, _1 ); _NL_
|
|
|
|
|
and_all (coll, fun1, 10, _1 ); _NL_
|
|
|
|
|
|
|
|
|
|
has_any (coll, function1, 10, _1 ); _NL_
|
|
|
|
|
has_any (coll, &function1, 10, _1 ); _NL_
|
|
|
|
|
has_any (coll, fun1, 10, _1 ); _NL_
|
|
|
|
|
|
|
|
|
|
for_each (coll, function1, _1, _1 ); _NL_
|
|
|
|
|
for_each (coll, &function1,_1, _1 ); _NL_
|
|
|
|
|
for_each (coll, fun1, _1, _1 ); _NL_
|
|
|
|
|
|
|
|
|
|
and_all (coll, function1, _1, _1 ); _NL_
|
|
|
|
|
and_all (coll, &function1, _1, _1 ); _NL_
|
|
|
|
|
and_all (coll, fun1, _1, _1 ); _NL_
|
|
|
|
|
|
|
|
|
|
has_any (coll, function1, _1, _1 ); _NL_
|
|
|
|
|
has_any (coll, &function1, _1, _1 ); _NL_
|
|
|
|
|
has_any (coll, fun1, _1, _1 ); _NL_
|
|
|
|
|
|
2009-12-31 03:25:25 +01:00
|
|
|
//does not compile.....
|
|
|
|
|
// for_each (coll, function1, 10, 20, _1 );
|
|
|
|
|
// for_each (coll, function1, _1, _2 );
|
|
|
|
|
// for_each (coll, function1, 10 );
|
2010-01-04 14:23:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @test under some circumstances, it is even possible
|
|
|
|
|
* to take a ref to the data in the input sequence,
|
|
|
|
|
* or to a summation variable.
|
|
|
|
|
* @note in case of invoking this test with a Lumiera Forward Iterator,
|
|
|
|
|
* the changes go through to the original container, in spite of
|
|
|
|
|
* passing the iterator by value. This behaviour is correct, as
|
|
|
|
|
* an iterator is an reference-like object
|
|
|
|
|
*
|
|
|
|
|
* */
|
|
|
|
|
template<typename CO>
|
|
|
|
|
void
|
|
|
|
|
check_ref_argument_bind (CO coll)
|
|
|
|
|
{
|
2009-12-31 03:25:25 +01:00
|
|
|
ANNOUNCE (assign_to_input);
|
2010-01-04 14:23:15 +01:00
|
|
|
function<bool(int,int,int)> fun2(function2);
|
|
|
|
|
|
2010-01-04 13:34:51 +01:00
|
|
|
for_each (coll, function2, 5, 5, _1 ); _NL_
|
|
|
|
|
for_each (coll, &function2,5, 5, _1 ); _NL_
|
2009-12-29 03:42:33 +01:00
|
|
|
|
2010-01-04 13:34:51 +01:00
|
|
|
and_all (coll, function2, 5, 5, _1 ); _NL_
|
|
|
|
|
and_all (coll, &function2, 5, 5, _1 ); _NL_
|
2009-12-29 03:42:33 +01:00
|
|
|
|
2010-01-04 13:34:51 +01:00
|
|
|
has_any (coll, function2, 5, 5, _1 ); _NL_
|
|
|
|
|
has_any (coll, &function2, 5, 5, _1 ); _NL_
|
2010-01-04 14:23:15 +01:00
|
|
|
|
|
|
|
|
// note: when using a function object,
|
|
|
|
|
// instead of directly using a binder,
|
|
|
|
|
// the pass-by reference doesn't work
|
|
|
|
|
for_each (coll,fun2, 5, 5, _1 ); _NL_
|
|
|
|
|
and_all (coll, fun2, 5, 5, _1 ); _NL_
|
2010-01-04 13:34:51 +01:00
|
|
|
has_any (coll, fun2, 5, 5, _1 ); _NL_
|
2009-12-29 03:42:33 +01:00
|
|
|
|
|
|
|
|
int sum=0;
|
2009-12-31 03:25:25 +01:00
|
|
|
ANNOUNCE (assign_to_var);
|
2010-01-04 13:34:51 +01:00
|
|
|
for_each (coll, function2, -10, _1, ref(sum) ); _NL_
|
|
|
|
|
for_each (coll, &function2,-10, _1, ref(sum) ); _NL_
|
|
|
|
|
for_each (coll, fun2, -10, _1, ref(sum) ); _NL_
|
2009-12-31 03:25:25 +01:00
|
|
|
cout << "sum=" << sum << endl;
|
|
|
|
|
|
2010-01-04 13:34:51 +01:00
|
|
|
sum=0;
|
|
|
|
|
and_all (coll, function2, -10, _1, ref(sum) ); _NL_
|
|
|
|
|
and_all (coll, &function2, -10, _1, ref(sum) ); _NL_
|
|
|
|
|
and_all (coll, fun2, -10, _1, ref(sum) ); _NL_
|
2009-12-31 03:25:25 +01:00
|
|
|
cout << "sum=" << sum << endl;
|
|
|
|
|
|
2010-01-04 13:34:51 +01:00
|
|
|
sum=0;
|
|
|
|
|
has_any (coll, function2, -10, _1, ref(sum) ); _NL_
|
|
|
|
|
has_any (coll, &function2, -10, _1, ref(sum) ); _NL_
|
|
|
|
|
has_any (coll, fun2, -10, _1, ref(sum) ); _NL_
|
2009-12-31 03:25:25 +01:00
|
|
|
cout << "sum=" << sum << endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @test the input sequence can be also taken
|
|
|
|
|
* from a const container (for iterators this
|
|
|
|
|
* obviously doesn't make sense */
|
|
|
|
|
template<typename CO>
|
|
|
|
|
void
|
|
|
|
|
check_foreach_bind_const (CO const& coll)
|
|
|
|
|
{
|
|
|
|
|
ANNOUNCE (check_foreach_bind_const);
|
|
|
|
|
|
|
|
|
|
for_each (coll,function1, 10, _1 ); _NL_
|
|
|
|
|
and_all (coll, function1, 10, _1 ); _NL_
|
|
|
|
|
has_any (coll, function1, 10, _1 ); _NL_
|
|
|
|
|
|
|
|
|
|
for_each (coll,function1, _1, _1 ); _NL_
|
|
|
|
|
and_all (coll, function1, _1, _1 ); _NL_
|
|
|
|
|
has_any (coll, function1, _1, _1 ); _NL_
|
|
|
|
|
|
|
|
|
|
int sum=0;
|
|
|
|
|
|
|
|
|
|
for_each (coll,function2, _1, _1, ref(sum) ); _NL_
|
|
|
|
|
and_all (coll, function2, _1, _1, ref(sum) ); _NL_
|
|
|
|
|
has_any (coll, function2, _1, _1, ref(sum) ); _NL_
|
2009-12-29 03:42:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct Dummy
|
|
|
|
|
{
|
|
|
|
|
int sum_;
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
fun (int i)
|
|
|
|
|
{
|
|
|
|
|
sum_ += i;
|
|
|
|
|
return plainFunc (sum_);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** @test bind a member function to be invoked for each element */
|
|
|
|
|
template<typename CO>
|
|
|
|
|
void
|
|
|
|
|
check_foreach_memFun (CO coll)
|
|
|
|
|
{
|
2009-12-31 03:25:25 +01:00
|
|
|
ANNOUNCE (check_foreach_memFun);
|
|
|
|
|
|
2009-12-29 03:42:33 +01:00
|
|
|
Dummy dummy;
|
2009-12-31 03:25:25 +01:00
|
|
|
dummy.sum_ = 0;
|
2009-12-29 03:42:33 +01:00
|
|
|
|
2009-12-31 03:25:25 +01:00
|
|
|
for_each (coll, &Dummy::fun, dummy, _1 ); _NL_
|
|
|
|
|
and_all (coll, &Dummy::fun, dummy, _1 ); _NL_
|
|
|
|
|
has_any (coll, &Dummy::fun, dummy, _1 ); _NL_
|
2009-12-29 03:42:33 +01:00
|
|
|
|
2009-12-31 03:25:25 +01:00
|
|
|
for_each (coll, &Dummy::fun, &dummy, _1 ); _NL_
|
|
|
|
|
and_all (coll, &Dummy::fun, &dummy, _1 ); _NL_
|
|
|
|
|
has_any (coll, &Dummy::fun, &dummy, _1 ); _NL_
|
2009-12-29 03:42:33 +01:00
|
|
|
|
2009-12-31 03:25:25 +01:00
|
|
|
cout << "sum=" << dummy.sum_ << endl;
|
2009-12-29 03:42:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @test use a lambda-expression, to be invoked for each element */
|
|
|
|
|
template<typename CO>
|
|
|
|
|
void
|
|
|
|
|
check_foreach_lambda (CO coll)
|
|
|
|
|
{
|
2009-12-31 03:25:25 +01:00
|
|
|
ANNOUNCE (check_foreach_lambda);
|
|
|
|
|
uint sum(0);
|
|
|
|
|
|
|
|
|
|
for_each (coll, var(sum) += _1_ );
|
2009-12-29 03:42:33 +01:00
|
|
|
|
2010-01-04 14:23:15 +01:00
|
|
|
ASSERT (sum == (NUM_ELMS+1) * NUM_ELMS/2);
|
2009-12-29 03:42:33 +01:00
|
|
|
|
|
|
|
|
ASSERT (!and_all (coll, _1_ - 1 ));
|
|
|
|
|
ASSERT ( has_any (coll, _1_ + 1 ));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @test verify the logic of universal and existential quantisation.
|
|
|
|
|
* We use a predicate generated on-the-fly as lambda expression */
|
|
|
|
|
template<typename CO>
|
|
|
|
|
void
|
|
|
|
|
check_existence_quant (CO coll)
|
|
|
|
|
{
|
2009-12-31 03:25:25 +01:00
|
|
|
ANNOUNCE (check_existence_quant);
|
|
|
|
|
|
2009-12-29 03:42:33 +01:00
|
|
|
ASSERT ( and_all (coll, 0 < _1_ ));
|
|
|
|
|
ASSERT (!and_all (coll, 1 < _1_ ));
|
|
|
|
|
|
|
|
|
|
ASSERT ( has_any (coll, 0 < _1_ ));
|
|
|
|
|
ASSERT ( has_any (coll, _1_ >= NUM_ELMS ));
|
|
|
|
|
ASSERT (!has_any (coll, _1_ > NUM_ELMS ));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct TestElm
|
|
|
|
|
{
|
|
|
|
|
uint n_;
|
|
|
|
|
TestElm(uint i) : n_(i) {}
|
|
|
|
|
|
2009-12-31 03:25:25 +01:00
|
|
|
bool operation() { return plainFunc (n_); }
|
2009-12-29 03:42:33 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @test the binding can also be used to \em dispatch an operation
|
|
|
|
|
* on each element within a object collection: here the parameter
|
|
|
|
|
* is used as \c this pointer to specify the object instance */
|
|
|
|
|
void
|
2009-12-29 04:30:11 +01:00
|
|
|
check_invoke_on_each ()
|
2009-12-29 03:42:33 +01:00
|
|
|
{
|
2009-12-31 03:25:25 +01:00
|
|
|
ANNOUNCE (check_invoke_on_each);
|
|
|
|
|
|
2009-12-29 04:30:11 +01:00
|
|
|
std::vector<TestElm> elms;
|
2009-12-29 03:42:33 +01:00
|
|
|
for (uint i=0; i<6; ++i)
|
|
|
|
|
elms.push_back (TestElm(i));
|
|
|
|
|
|
2009-12-29 04:30:11 +01:00
|
|
|
std::vector<TestElm*> elmPtrs;
|
2009-12-29 03:42:33 +01:00
|
|
|
for (uint i=0; i<6; ++i)
|
2009-12-29 04:30:11 +01:00
|
|
|
elmPtrs.push_back (& elms[i]);
|
2009-12-29 03:42:33 +01:00
|
|
|
|
|
|
|
|
// fed the element pointer as "this" pointer of the member function
|
|
|
|
|
for_each (elmPtrs, &TestElm::operation, _1 ); _NL_
|
|
|
|
|
and_all (elmPtrs, &TestElm::operation, _1 ); _NL_
|
|
|
|
|
has_any (elmPtrs, &TestElm::operation, _1 ); _NL_
|
|
|
|
|
|
2010-01-04 13:34:51 +01:00
|
|
|
// the same works with copies of the elements as well...
|
2009-12-29 03:42:33 +01:00
|
|
|
for_each (elms, &TestElm::operation, _1 ); _NL_
|
|
|
|
|
and_all (elms, &TestElm::operation, _1 ); _NL_
|
|
|
|
|
has_any (elms, &TestElm::operation, _1 ); _NL_
|
2010-01-04 13:34:51 +01:00
|
|
|
|
|
|
|
|
// note: it seems not to be possible to create a binder, which takes the "*this"-Argument by ref
|
2009-12-29 03:42:33 +01:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LAUNCHER (UtilForeach_test, "unit common");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}} // namespace util::test
|
|
|
|
|
|