* Lumiera source code always was copyrighted by individual contributors * there is no entity "Lumiera.org" which holds any copyrights * Lumiera source code is provided under the GPL Version 2+ == Explanations == Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above. For this to become legally effective, the ''File COPYING in the root directory is sufficient.'' The licensing header in each file is not strictly necessary, yet considered good practice; attaching a licence notice increases the likeliness that this information is retained in case someone extracts individual code files. However, it is not by the presence of some text, that legally binding licensing terms become effective; rather the fact matters that a given piece of code was provably copyrighted and published under a license. Even reformatting the code, renaming some variables or deleting parts of the code will not alter this legal situation, but rather creates a derivative work, which is likewise covered by the GPL! The most relevant information in the file header is the notice regarding the time of the first individual copyright claim. By virtue of this initial copyright, the first author is entitled to choose the terms of licensing. All further modifications are permitted and covered by the License. The specific wording or format of the copyright header is not legally relevant, as long as the intention to publish under the GPL remains clear. The extended wording was based on a recommendation by the FSF. It can be shortened, because the full terms of the license are provided alongside the distribution, in the file COPYING.
235 lines
7.4 KiB
C++
235 lines
7.4 KiB
C++
/*
|
||
IterAdapterSTL(Test) - building various custom iterators for a given container
|
||
|
||
Copyright (C)
|
||
2010, Hermann Vosseler <Ichthyostega@web.de>
|
||
|
||
**Lumiera** 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. See the file COPYING for further details.
|
||
|
||
* *****************************************************************/
|
||
|
||
/** @file iter-adapter-stl-test.cpp
|
||
** unit test \ref IterAdapterSTL_test
|
||
*/
|
||
|
||
|
||
|
||
#include "lib/test/run.hpp"
|
||
#include "lib/test/test-coll.hpp"
|
||
#include "lib/format-cout.hpp"
|
||
#include "lib/util.hpp"
|
||
|
||
#include "lib/iter-adapter-stl.hpp"
|
||
|
||
#include <boost/lexical_cast.hpp>
|
||
#include <vector>
|
||
|
||
|
||
|
||
namespace lib {
|
||
namespace test{
|
||
|
||
using ::Test;
|
||
using boost::lexical_cast;
|
||
using util::isnil;
|
||
|
||
namespace iter = lib::iter_stl;
|
||
|
||
|
||
/** test an iterator: create it by calling a constructor function
|
||
* and then pull out all contents and print them to STDOUT */
|
||
#define TEST_ITER(_CTOR_, _ARG_) \
|
||
cout << STRINGIFY(_CTOR_) ;\
|
||
pullOut (_CTOR_ _ARG_) ;\
|
||
cout << endl;
|
||
|
||
/** print descriptive separator to STDOUT */
|
||
#define PRINT_FUNC(_F_NAME_, _F_TYPE_) \
|
||
cout << "-----"<<STRINGIFY(_F_NAME_)<<"---" << util::typeStr<_F_TYPE_>() << endl;
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
/********************************************************************//**
|
||
* @test verify some of the adapters to expose typical container
|
||
* usage patterns as Lumiera Forward Iterators.
|
||
* - distinct values from a sequence
|
||
* - keys and values of a map / multimap
|
||
* - distinct keys from a multimap
|
||
* - multimap values associated with a given key
|
||
* - snapshot of an iterator, to be retrieved as iterator
|
||
*
|
||
* @see RangeIter
|
||
* @see iter-adapter.hpp
|
||
* @see iter-adapter-stl.hpp
|
||
* @todo this test just pulls all the values from the iterator
|
||
* and the testsuite verifies the retrieved values.
|
||
* But for the hash-map, the order of the results
|
||
* is not guaranteed, and implementation dependent.
|
||
*/
|
||
class IterAdapterSTL_test : public Test
|
||
{
|
||
uint NUM_ELMS{0};
|
||
|
||
virtual void
|
||
run (Arg arg)
|
||
{
|
||
NUM_ELMS = firstVal (arg, 10);
|
||
|
||
checkDistinctValIter();
|
||
|
||
iterateMapKeyVal (getTestMap_int<MapII> (NUM_ELMS));
|
||
iterateMapKeyVal (getTestMap_int<HMapII> (NUM_ELMS));
|
||
|
||
iterateMapKeyVal (getTestMultiMap_int<MMapII> (NUM_ELMS));
|
||
iterateMapKeyVal (getTestMultiMap_int<HMMapII> (NUM_ELMS));
|
||
|
||
iterateValues4Key (getTestMultiMap_int<MMapII> (NUM_ELMS));
|
||
iterateValues4Key (getTestMultiMap_int<HMMapII> (NUM_ELMS));
|
||
|
||
checkIteratorSnapshot();
|
||
}
|
||
|
||
|
||
template<class MAP>
|
||
void
|
||
iterateMapKeyVal (MAP const& map)
|
||
{
|
||
PRINT_FUNC (iterateMapKeyVal, MAP);
|
||
|
||
TEST_ITER (iter::eachKey, (map));
|
||
TEST_ITER (iter::eachKey, (map.begin(), map.end()));
|
||
TEST_ITER (iter::eachVal, (map));
|
||
TEST_ITER (iter::eachVal, (map.begin(), map.end()));
|
||
TEST_ITER (iter::eachDistinctKey, (map));
|
||
}
|
||
|
||
|
||
template<class MMAP>
|
||
void
|
||
iterateValues4Key (MMAP const& mumap)
|
||
{
|
||
PRINT_FUNC (iterateValues4Key, MMAP);
|
||
|
||
TEST_ITER (iter::eachValForKey, (mumap, 0));
|
||
|
||
// non-existing key should yield empty iterator
|
||
CHECK (! iter::eachValForKey (mumap, NUM_ELMS));
|
||
}
|
||
|
||
|
||
void
|
||
checkDistinctValIter()
|
||
{
|
||
PRINT_FUNC (filter-distinct-values, VecI);
|
||
|
||
VecI vec;
|
||
TEST_ITER(iter::eachDistinct, (vec));
|
||
|
||
vec.push_back (1);
|
||
vec.push_back (1);
|
||
vec.push_back (1);
|
||
TEST_ITER(iter::eachDistinct, (vec));
|
||
|
||
vec.push_back (2);
|
||
vec.push_back (3);
|
||
vec.push_back (3);
|
||
vec.push_back (1);
|
||
TEST_ITER(iter::eachDistinct, (vec));
|
||
|
||
vec.push_back (1);
|
||
vec.push_back (1);
|
||
vec.push_back (1);
|
||
vec.push_back (1);
|
||
vec.push_back (1);
|
||
TEST_ITER(iter::eachDistinct, (vec));
|
||
}
|
||
|
||
|
||
void
|
||
checkIteratorSnapshot()
|
||
{
|
||
typedef VecI::iterator Iter;
|
||
typedef RangeIter<Iter> Range;
|
||
typedef iter::IterSnapshot<int> Snapshot;
|
||
|
||
VecI vec = getTestSeq_int<VecI> (NUM_ELMS);
|
||
Snapshot capture1 (vec.begin(), vec.end());
|
||
|
||
Range range_of_all (vec.begin(), vec.end());
|
||
Snapshot capture2 = iter::snapshot(range_of_all); // NOTE: when specifically taken this way,
|
||
CHECK (range_of_all); // snapshot doesn't affect given source iterator pos
|
||
CHECK (capture2); // (but WARNING, the IterSnapshot ctor itself is destructive)
|
||
|
||
CHECK (vec.begin() == range_of_all.getPos());
|
||
CHECK (vec.end() == range_of_all.getEnd());
|
||
CHECK (!isnil (vec));
|
||
|
||
// concurrent or intermittent modification
|
||
vec.clear();
|
||
CHECK (isnil (vec));
|
||
CHECK (vec.end() != range_of_all.getEnd()); // range_of_all is now corrupted
|
||
|
||
CHECK (capture1); // ...but the snapshots remain unaffected
|
||
CHECK (capture2);
|
||
CHECK (capture1 == capture2); // can compare snapshots, based on actual contents
|
||
|
||
vec.push_back(22);
|
||
vec.push_back(44);
|
||
Snapshot capture3 (vec.begin(), vec.end()); // take another snapshot from current contents
|
||
CHECK (capture3);
|
||
CHECK (capture3 != capture1);
|
||
CHECK (capture3 != capture2);
|
||
|
||
|
||
uint sum_should_be = (NUM_ELMS-1)*NUM_ELMS/2;
|
||
|
||
CHECK (sum_should_be == sumAll (capture1));
|
||
CHECK (!capture1); // this one is exhausted now
|
||
CHECK ( capture2); // ...but the others are really independent
|
||
CHECK ( capture3);
|
||
CHECK (capture1 != capture2); // comparison includes the current position
|
||
|
||
CHECK (sum_should_be == sumAll (capture2));
|
||
CHECK (!capture1);
|
||
CHECK (!capture2);
|
||
CHECK ( capture3);
|
||
CHECK (capture1 == capture2); // now again equal (both exhausted and equal contents)
|
||
|
||
CHECK (22+44 == sumAll (capture3));
|
||
CHECK (!capture1);
|
||
CHECK (!capture2);
|
||
CHECK (!capture3);
|
||
CHECK (capture1 == capture2); // all exhausted iterators count as "equal"
|
||
CHECK (capture3 == capture1); // this ensures the idiom while(pos != end) works
|
||
CHECK (capture3 == capture2);
|
||
}
|
||
|
||
template<class IT>
|
||
uint
|
||
sumAll (IT& it)
|
||
{
|
||
uint sum(0);
|
||
cout << "snapshot";
|
||
while (it)
|
||
{
|
||
cout << "-" << *it;
|
||
sum += *it;
|
||
++it;
|
||
}
|
||
cout << endl;
|
||
return sum;
|
||
}
|
||
};
|
||
|
||
LAUNCHER (IterAdapterSTL_test, "unit common");
|
||
|
||
|
||
}} // namespace lib::test
|