2010-01-05 02:53:20 +01:00
/*
IterSource ( Test ) - how to build an opaque iterator - based data source
2010-12-17 23:28:49 +01:00
Copyright: clarify and simplify the file headers
* 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.
2024-11-17 23:42:55 +01:00
Copyright ( C )
2010 , Hermann Vosseler < Ichthyostega @ web . de >
2010-12-17 23:28:49 +01:00
Copyright: clarify and simplify the file headers
* 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.
2024-11-17 23:42:55 +01:00
* * 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 .
2010-12-17 23:28:49 +01:00
Copyright: clarify and simplify the file headers
* 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.
2024-11-17 23:42:55 +01:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-01-05 02:53:20 +01:00
2017-02-22 01:54:20 +01:00
/** @file iter-source-test.cpp
2017-02-22 03:17:18 +01:00
* * unit test \ ref IterSource_test
2016-11-03 18:20:10 +01:00
*/
2010-01-05 02:53:20 +01:00
# include "lib/test/run.hpp"
2010-01-05 05:21:13 +01:00
# include "lib/test/test-helper.hpp"
2016-01-07 03:58:29 +01:00
# include "lib/format-cout.hpp"
2018-03-24 05:35:13 +01:00
# include "lib/nocopy.hpp"
2010-01-05 02:53:20 +01:00
# include "lib/util.hpp"
# include "lib/iter-source.hpp"
# include <boost/lexical_cast.hpp>
2014-04-03 22:42:48 +02:00
# include <unordered_map>
2010-01-05 05:21:13 +01:00
# include <string>
2010-01-05 02:53:20 +01:00
# include <list>
2010-01-06 04:14:16 +01:00
# include <map>
2010-01-05 02:53:20 +01:00
namespace lib {
namespace test {
using : : Test ;
2024-11-13 02:23:23 +01:00
using util : : isnil ;
2010-01-05 02:53:20 +01:00
using boost : : lexical_cast ;
2011-05-16 08:38:27 +02:00
using lib : : time : : TimeVar ;
2010-01-05 05:21:13 +01:00
using lib : : test : : randStr ;
2010-01-06 04:14:16 +01:00
using lib : : test : : randTime ;
2010-01-06 06:53:29 +01:00
using std : : make_pair ;
2010-01-05 05:21:13 +01:00
using std : : string ;
2010-01-05 02:53:20 +01:00
using std : : list ;
2024-03-16 02:04:47 +01:00
using LERR_ ( ITER_EXHAUST ) ;
2017-10-29 15:31:34 +01:00
2017-12-07 05:48:36 +01:00
using iter_source : : eachEntry ;
using iter_source : : transform ;
using iter_source : : singleVal ;
using iter_source : : eachMapKey ;
using iter_source : : eachMapVal ;
using iter_source : : eachValForKey ;
using iter_source : : eachDistinctKey ;
2010-01-05 02:53:20 +01:00
namespace { // Subject of test
2010-01-05 05:21:13 +01:00
/**
2010-01-05 02:53:20 +01:00
* Explicit implementation of the IterSource interface ( test dummy )
2010-01-05 05:21:13 +01:00
* Creates a random string and chops off a character on each iteration
2010-01-05 02:53:20 +01:00
*/
class TestSource
2010-01-05 05:21:13 +01:00
: public IterSource < CStr >
2018-03-24 05:35:13 +01:00
, util : : NonCopyable
2010-01-05 02:53:20 +01:00
{
2010-01-05 04:10:23 +01:00
2010-01-05 05:21:13 +01:00
string buffer_ ;
CStr current_ ;
2017-12-09 05:08:24 +01:00
virtual Pos ////////////////////////////////////////////TICKET #1125 : this iteration control API should use three control functions, similar to IterStateWrapper
firstResult ( ) override
2010-01-05 05:21:13 +01:00
{
current_ = buffer_ . c_str ( ) ;
ENSURE ( current_ ) ;
return & current_ ;
}
virtual void
2017-12-09 05:08:24 +01:00
nextResult ( Pos & pos ) override
2010-01-05 05:21:13 +01:00
{
2025-06-07 23:59:57 +02:00
if ( pos and * pos and * * pos )
2010-01-05 05:21:13 +01:00
+ + ( * pos ) ;
2025-06-07 23:59:57 +02:00
if ( ! ( pos and * pos and * * pos ) )
2010-01-05 05:21:13 +01:00
pos = 0 ;
}
2010-01-05 04:10:23 +01:00
public :
TestSource ( uint num )
2010-01-05 05:21:13 +01:00
: buffer_ ( randStr ( num ) )
, current_ ( 0 )
2010-01-05 04:10:23 +01:00
{
2010-01-05 05:21:13 +01:00
INFO ( test , " created TestSource( \" %s \" ) " , cStr ( buffer_ ) ) ;
2010-01-05 04:10:23 +01:00
}
2010-01-05 02:53:20 +01:00
} ;
2010-01-05 05:21:13 +01:00
/** test dummy: simply wrapping an STL container
2010-01-05 02:53:20 +01:00
* and exposing a range as Lumiera Forward Iterator
*/
struct WrappedList
{
list < int > data_ ;
WrappedList ( uint num )
{
while ( num )
data_ . push_back ( num - - ) ;
}
typedef list < int > : : iterator sourceIter ;
typedef RangeIter < sourceIter > iterator ;
2010-01-05 05:21:13 +01:00
iterator begin ( ) { return iterator ( data_ . begin ( ) , data_ . end ( ) ) ; }
iterator end ( ) { return iterator ( ) ; }
2010-01-05 02:53:20 +01:00
} ;
2017-10-29 15:31:34 +01:00
/** diagnostics helper */
template < class IT >
inline void
pullOut ( IT & iter )
{
for ( ; iter ; + + iter )
cout < < " :: " < < * iter ;
cout < < endl ;
}
2010-01-05 02:53:20 +01:00
} // (END) impl test dummy containers
2013-10-24 23:06:36 +02:00
/**************************************************************/ /**
2010-01-05 02:53:20 +01:00
* @ test create some ( opaque ) data sources ,
* and then pull the data out by iteration .
2010-01-05 05:21:13 +01:00
* Demonstrates simple usage of the IterSource interface
2010-01-05 02:53:20 +01:00
*
2010-01-05 05:21:13 +01:00
* @ see IterSource
* @ see PlacementIndex : : Table # _eachEntry_4check real world usage example
2014-05-09 01:45:10 +02:00
* @ todo the output order of the values produced by this test
* is implementation dependent in for the hashmap case
2010-01-05 02:53:20 +01:00
*/
class IterSource_test : public Test
{
typedef IterSource < int > : : iterator IntIter ;
2010-01-05 05:21:13 +01:00
typedef IterSource < CStr > : : iterator StrIter ;
2010-01-06 06:53:29 +01:00
typedef IterSource < string > : : iterator StringIter ;
2011-05-16 08:38:27 +02:00
typedef IterSource < TimeVar > : : iterator TimeIter ;
2010-01-06 04:14:16 +01:00
2016-01-08 00:16:14 +01:00
typedef std : : map < string , TimeVar > TreeMap ;
2014-04-03 22:42:48 +02:00
typedef std : : unordered_map < string , TimeVar > HashMap ;
2010-01-05 05:21:13 +01:00
2016-01-08 00:16:14 +01:00
typedef std : : multimap < int , int > TreeMultimap ;
2014-04-03 22:42:48 +02:00
typedef std : : unordered_multimap < int , int > HashMultimap ;
2010-01-06 06:53:29 +01:00
2024-11-15 19:02:48 +01:00
uint NUM_ELMS { 0 } ;
2010-01-05 02:53:20 +01:00
virtual void
run ( Arg arg )
{
2024-11-13 02:23:23 +01:00
seedRand ( ) ;
2024-11-15 19:02:48 +01:00
NUM_ELMS = firstVal ( arg , 10 ) ;
2010-01-05 02:53:20 +01:00
2010-01-06 04:14:16 +01:00
verify_simpleIters ( ) ;
2011-06-26 03:59:03 +02:00
verify_transformIter ( ) ;
2010-01-06 04:14:16 +01:00
verify_MapWrappers < TreeMap > ( ) ;
verify_MapWrappers < HashMap > ( ) ;
2010-01-06 06:53:29 +01:00
2010-03-31 05:01:03 +02:00
verify_MultimapIters < TreeMultimap > ( ) ;
verify_MultimapIters < HashMultimap > ( ) ;
2010-01-06 04:14:16 +01:00
}
void
verify_simpleIters ( )
{
2010-01-05 02:53:20 +01:00
// build the test data sources
WrappedList customList ( NUM_ELMS ) ;
TestSource dedicatedSource ( NUM_ELMS ) ;
2010-10-05 01:40:50 +02:00
list < int > & rawList ( customList . data_ ) ;
2010-01-05 02:53:20 +01:00
IntIter iii ( eachEntry ( customList ) ) ;
2010-10-05 01:40:50 +02:00
IntIter isi ( eachEntry ( rawList . begin ( ) , rawList . end ( ) ) ) ;
2010-01-05 05:21:13 +01:00
StrIter cii ( IterSource < CStr > : : build ( dedicatedSource ) ) ;
2010-01-05 02:53:20 +01:00
2010-12-10 02:55:40 +01:00
CHECK ( ! isnil ( iii ) ) ;
CHECK ( ! isnil ( isi ) ) ;
CHECK ( ! isnil ( cii ) ) ;
2010-01-05 02:53:20 +01:00
pullOut ( iii ) ;
2010-10-05 01:40:50 +02:00
pullOut ( isi ) ;
2010-01-05 02:53:20 +01:00
pullOut ( cii ) ;
2010-12-10 02:55:40 +01:00
CHECK ( ! iii ) ;
CHECK ( ! isi ) ;
CHECK ( ! cii ) ;
2010-01-05 02:53:20 +01:00
}
2017-10-29 15:31:34 +01:00
/** @test verify transforming an embedded iterator
* This test not only wraps a source iterator and packages it behind the
* abstracting interface IterSource , but in addition also applies a function
* to each element yielded by the source iterator . As demo transformation
* we use the values from our custom container ( \ ref WrappedList ) to build
* a time value in quarter seconds
*
*/
2011-06-26 03:59:03 +02:00
void
verify_transformIter ( )
{
WrappedList customList ( NUM_ELMS ) ;
2017-10-29 15:31:34 +01:00
WrappedList : : iterator sourceValues = customList . begin ( ) ;
// transformation function
auto makeTime = [ ] ( int input_sec ) - > TimeVar
{
return time : : Time ( time : : FSecs ( input_sec , 4 ) ) ;
} ;
2011-06-26 03:59:03 +02:00
TimeIter tIt ( transform ( sourceValues , makeTime ) ) ;
CHECK ( ! isnil ( tIt ) ) ;
pullOut ( tIt ) ;
CHECK ( ! tIt ) ;
}
2017-10-29 15:31:34 +01:00
/** @test an IterSouce which returns just a single value once */
2010-01-05 02:53:20 +01:00
void
2017-10-29 15:31:34 +01:00
verify_singleValIter ( )
2010-01-05 02:53:20 +01:00
{
2017-10-29 15:31:34 +01:00
int i { - 9 } ;
IntIter ii = singleVal ( 12 ) ;
CHECK ( not isnil ( ii ) ) ;
CHECK ( 12 = = * ii ) ;
+ + ii ;
CHECK ( isnil ( ii ) ) ;
VERIFY_ERROR ( ITER_EXHAUST , * ii ) ;
// IterSource is an abstracting interface,
// thus we're able to reassign an embedded iterator
// with a different value type (int& instead of int)
ii = singleVal ( i ) ;
CHECK ( not isnil ( ii ) ) ;
CHECK ( - 9 = = * ii ) ;
// NOTE: since we passed a reference, a reference got wrapped
i = 23 ;
CHECK ( 23 = = * ii ) ;
+ + ii ;
CHECK ( isnil ( ii ) ) ;
2010-01-05 02:53:20 +01:00
}
2010-01-06 04:14:16 +01:00
2017-10-29 15:31:34 +01:00
2010-01-06 04:14:16 +01:00
template < class MAP >
void
verify_MapWrappers ( )
{
MAP testMap ;
for ( uint i = 0 ; i < NUM_ELMS ; + + i )
testMap [ ' X ' + randStr ( 11 ) ] = randTime ( ) ;
StringIter sIter = eachMapKey ( testMap ) ;
TimeIter tIter = eachMapVal ( testMap ) ;
2025-06-07 23:59:57 +02:00
CHECK ( sIter and tIter ) ;
2010-01-06 04:14:16 +01:00
pullOut ( sIter ) ;
pullOut ( tIter ) ;
2025-06-07 23:59:57 +02:00
CHECK ( not sIter and not tIter ) ;
2010-03-31 05:01:03 +02:00
// The each-value-for-given-key-Iterator can be used for a map or multimap.
// In case of a map, it should yield exactly one result for existing values
// and zero results for non-existing mappings
StringIter justSomeKey = eachMapKey ( testMap ) ;
TimeIter correspondingVal = eachMapVal ( testMap ) ;
+ + justSomeKey ;
+ + correspondingVal ;
2010-12-10 02:55:40 +01:00
CHECK ( justSomeKey ) ;
2010-03-31 05:01:03 +02:00
TimeIter value4key = eachValForKey ( testMap , " nonexistent key " ) ;
2010-12-10 02:55:40 +01:00
CHECK ( ! value4key ) ;
2010-03-31 05:01:03 +02:00
value4key = eachValForKey ( testMap , * justSomeKey ) ;
2010-12-10 02:55:40 +01:00
CHECK ( value4key ) ;
CHECK ( * value4key = = * correspondingVal ) ;
2010-03-31 05:01:03 +02:00
+ + value4key ;
2010-12-10 02:55:40 +01:00
CHECK ( ! value4key ) ;
2010-01-06 04:14:16 +01:00
}
2010-01-06 06:53:29 +01:00
template < class MAP >
void
2010-03-31 05:01:03 +02:00
verify_MultimapIters ( ) ///< @see IterTools_test#verify_filterRepetitions
2010-01-06 06:53:29 +01:00
{
MAP testMap ;
for ( uint i = 0 ; i < NUM_ELMS ; + + i )
{
2024-11-13 02:23:23 +01:00
uint n = 1 + rani ( 100 ) ;
2010-01-06 06:53:29 +01:00
do testMap . insert ( make_pair ( i , n ) ) ;
while ( - - n ) ;
}
2010-12-10 02:55:40 +01:00
CHECK ( NUM_ELMS < testMap . size ( ) , " no repetition in test data?? " ) ;
2010-01-06 06:53:29 +01:00
IntIter keys = eachDistinctKey ( testMap ) ;
cout < < " distinct_keys " ;
2010-12-10 02:55:40 +01:00
CHECK ( keys ) ;
2010-01-06 06:53:29 +01:00
pullOut ( keys ) ;
2010-12-10 02:55:40 +01:00
CHECK ( ! keys ) ;
2010-03-31 05:01:03 +02:00
cout < < " values_4_key " ;
IntIter vals = eachValForKey ( testMap , NUM_ELMS ) ; // non-existent key
2010-12-10 02:55:40 +01:00
CHECK ( ! vals ) ;
2010-03-31 05:01:03 +02:00
vals = eachValForKey ( testMap , 0 ) ;
2010-12-10 02:55:40 +01:00
CHECK ( vals ) ;
2010-03-31 05:01:03 +02:00
pullOut ( vals ) ; // should produce anything between 1 and 100 entries
2010-12-10 02:55:40 +01:00
CHECK ( ! vals ) ;
2010-01-06 06:53:29 +01:00
}
2010-01-05 02:53:20 +01:00
} ;
2010-01-06 06:53:29 +01:00
2010-01-05 02:53:20 +01:00
LAUNCHER ( IterSource_test , " unit common " ) ;
} } // namespace lib::test