├── .gitignore ├── .gitmodules ├── README.md ├── doc ├── aggregate.md ├── anyall.md ├── groupby.md ├── range.md ├── range_and_elevation.lyx ├── range_and_elevation.txt ├── select.md ├── setops.md ├── skiptake.md └── sorting.md └── src ├── clang.mak ├── exp ├── iterable_range.h ├── makefile ├── test.cpp ├── tests.sln └── tests.vcxproj ├── makefile ├── makefile_speed ├── narl.sln ├── narl.vcxproj ├── narl.vcxproj.filters ├── narl ├── concatenating_range.h ├── cycling_range.h ├── diffing_range.h ├── distinct_range.h ├── filtering_range.h ├── grouping_range.h ├── intersecting_range.h ├── iterable_range.h ├── joined_range.h ├── merging_range.h ├── narl.h ├── partial_range.h ├── range.h ├── range_accumulate.h ├── range_factory.h ├── range_generator.h ├── range_input_iterator.h ├── range_predicate.h ├── range_tocontainer.h ├── reversed_range.h ├── selectmany_range.h ├── sorted_range.h ├── transforming_range.h ├── unioning_range.h ├── zipping_range.h ├── zipping_range_non_variadic.h └── zipping_range_variadic.h ├── narl_speed.vcxproj ├── narl_speed.vcxproj.filters └── tests ├── perf ├── narl_speed.cpp ├── selectwhere.cpp └── selectwhere.h └── testnarl ├── narl_stl.cpp ├── test_concatenating_range.cpp ├── test_cycling_range.cpp ├── test_diffing_range.cpp ├── test_distinct_range.cpp ├── test_filtering_range.cpp ├── test_grouping_range.cpp ├── test_intersecting_range.cpp ├── test_iterable_range.cpp ├── test_joined_range.cpp ├── test_merging_range.cpp ├── test_partial_range.cpp ├── test_range_accumulate.cpp ├── test_range_factory.cpp ├── test_range_generator.cpp ├── test_range_predicate.cpp ├── test_reversed_range.cpp ├── test_selectmany_range.cpp ├── test_sorted_range.cpp ├── test_tocontainer_range.cpp ├── test_transforming_range.cpp ├── test_unioning_range.cpp ├── test_zipped_range.cpp ├── testnarl.cpp ├── testnarl.h ├── testnarlspeed.cpp └── throwing_range.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.out 3 | *.exe 4 | *.sdf 5 | *.opensdf 6 | *.suo 7 | *.user 8 | Debug/ 9 | tmp/ 10 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "externals/catch"] 2 | path = externals/catch 3 | url = https://github.com/philsquared/Catch.git 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # narl 2 | 3 | Not Another Range Library - Overload at [ACCU](http://accu.org): an article introducing the library - [Range and Elevation](http://accu.org/var/uploads/journals/Overload117.pdf) 4 | 5 | #Get started 6 | 7 | Narl is a header-only library for C++. You'll need gcc 4.8 or better, or MS Visual Studio 2013. Not all the features are available in Visual Studio. The code also compiles with Clang 3.2, with some warnings. 8 | 9 | Add the ```src/narl``` folder to you search path and include ``````. 10 | 11 | The library is based around the idea of Ranges, but for the most part, these aren't directly used. Instead, you compose expressions from Narl, and let the compiler figure out what the result is. 12 | 13 | There are lots of expressions which you can compose together, using the | operator. Here is a simple filtering expression: 14 | 15 | For example: 16 | 17 | ```c++ 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | using namespace narl; 25 | 26 | int main( int argc, char *const argv[] ) 27 | { 28 | std::vector< std::string > src { argv, argv + argc }; 29 | 30 | auto r = from( src ) | where( []( const item & i ) { return i.size() > 0; } ); 31 | 32 | for( auto const & arg : r ) 33 | { 34 | std::cout << arg; 35 | } 36 | } 37 | ``` 38 | 39 | You can use initializer lists to initialize a range too: ```from( { 1, 2, 3 } )```. 40 | 41 | Expressions can be arbitrarily complex, and are lazily evaluated left-to-right: 42 | 43 | ```c++ 44 | auto r = from( src ) 45 | | where( []( const item & i ) { return i.size() > 0; } ) 46 | | select( []( const item & i ) { return i.name(); } ); 47 | ``` 48 | 49 | Lastly, you can "re-hydrate" a range back into a standard container with ```to```: 50 | 51 | ```c++ 52 | auto r = from( { 1, 2, 3 } ) 53 | | select( []( int i ) { return std::to_string( i ); } ) 54 | | to< std::list >(); 55 | 56 | // or to< std::vector >() for example 57 | ``` 58 | 59 | ## Usage 60 | 61 | The full list of implemented expressions is: 62 | 63 | [from](doc/range.md#from) [to](doc/range.md#to) [make_range](doc/range.md#make_range) [fill_range](doc/range.md#fill_range) [range](doc/range.md#range) 64 | 65 | [aggregate](doc/aggregate.md#aggregate) [all](doc/anyall.md#all) [any](doc/anyall.md#any) [concat](doc/select.md#concat) [count](doc/aggregate.md#count) [cycle](doc/range.md#cycle) [distinct](doc/setops.md#distinct) [except](doc/setops.md#except) [groupby](doc/groupby.md#groupby) [join](doc/groupby.md#join)* [intersect_with](doc/setops.md#intersect_with) [merge_with](doc/sorting.md#merge_with) [reverse](doc/sorting.md#reverse) [select](doc/select.md#select) [selectmany](doc/select.md#selectmany) [sequenceequal](doc/aggregate.md#sequenceequal) [skip](doc/skiptake.md#skip) [skip_while](doc/skiptake.md#skip_while) [sorted](doc/sorting.md#sorted) [take](doc/skiptake.md#take) [take_while](doc/skiptake.md#take_while) [union_with](doc/setops.md#union_with) [where](doc/select.md#where) [zipwith](doc/select.md#zipwith) 66 | 67 | (*join does not work in VS2013) 68 | 69 | For some example code, see [narl_stl.cpp](https://github.com/essennell/narl/tree/master/src/tests/testnarl/narl_stl.cpp) which has some narl expressions showing implementations of C++ standard algorithms. 70 | 71 | ## Building the tests 72 | 73 | Narl uses [Catch](https://github.com/philsquared/Catch) which is referenced as an external git project in externals/catch 74 | 75 | You'll need to initialize and update the submodule reference if you fork narl. 76 | 77 | Test sources are in the ```src/tests/testnarl``` folder. There is a makefile for g++ and a .sln file for Visual Studio in ```src```. 78 | -------------------------------------------------------------------------------- /doc/aggregate.md: -------------------------------------------------------------------------------- 1 | # aggregate count and sequenceequal 2 | 3 | ## aggregate 4 | 5 | This operation is a general purpose reduction (folding) operation that can be used to sum a collection. 6 | 7 | It is an overloaded expression. The simple version just takes an accumulator expression, the other version also takes an initial value as a seed. 8 | 9 | ```c++ 10 | auto sum = from( { 2, 4, 8 } ) | aggregate( []( int curr, int val ) { return curr + val; } ); 11 | auto product = from( { 2, 4, 8 } ) | aggregate( 1, []( int curr, int val ) { return curr * val; } ); 12 | ``` 13 | 14 | ## count 15 | 16 | This operation is a specialised form of aggregate that simply returns the number of elements in a range. 17 | 18 | ```c++ 19 | auto num = from( { 1, 2, 3, 5, 8, 13 } ) | where( []( int i ) { return i % 2 == 0; } ) | count(); 20 | ``` 21 | 22 | # sequenceequal 23 | 24 | This operation is in this section only because it is a variation of a fold that collapses to ```true``` if two ranges have the same elements in the same order. 25 | 26 | ```c++ 27 | auto same = from( { 1, 2, 3 } ) | sequenceequal( from( { 1, 2, 3 } ) ); 28 | ``` 29 | 30 | [Home](../README.md) 31 | [Index](../README.md#Usage) 32 | -------------------------------------------------------------------------------- /doc/anyall.md: -------------------------------------------------------------------------------- 1 | # any and all 2 | 3 | ## any 4 | 5 | This operation returns ```true``` if the given predicate returns ```true``` for any element in the range. If no predicate is given, the semantics are that it returns ```true``` if there are any elements. 6 | 7 | ```c++ 8 | bool exists = from( { 1, 2, 3 } ) | any( []( int i ) { return i % 2 == 0; } ); 9 | bool overlap - from( { 1, 2, 3 } ) | intersect_with( from( { 4, 5, 6 } ) ) | any(); 10 | ``` 11 | 12 | (See [Set operations](setops.md) for ```intersect_with```) 13 | 14 | ## all 15 | 16 | This operation returns ```true``` if all of the elements of a range match the given predicate. 17 | 18 | ```c++ 19 | bool even = from( { 2, 4, 6 } ) | all( []( int i ) { return i % 2 == 0; } ); 20 | ``` 21 | 22 | It is equivalent to a negated ```any``` for the same range and inverted predicate, i.e.: 23 | ```c++ 24 | bool odd = !( from( { 2, 4, 6 } ) | any( []( int i ) { return i % 2 != 0; } ) ); 25 | ``` 26 | 27 | [Home](../README.md) 28 | [Index](../README.md#Usage) 29 | -------------------------------------------------------------------------------- /doc/groupby.md: -------------------------------------------------------------------------------- 1 | # groupby and join 2 | 3 | ## groupby 4 | 5 | This operation is a simple joining operation that groups range elements together by a provided key. The resulting range''s elements are composite items comprising the matched key, and a contained range of the elements which match it. 6 | 7 | The order of returned items'' keys is not specified. 8 | 9 | ```c++ 10 | // The key selector here produces boolean keys 11 | auto groups = from( { 1, 2, 3, 4 } ) | groupby( []( int i ) { return i % 2 == 0; } ); 12 | 13 | for( auto kv : groups ) 14 | { 15 | std::cout << std::boolalpha << kv.key << ":"; 16 | for( const auto & val : kv.values ) 17 | { 18 | std::cout << val << " "; 19 | } 20 | std::cout << std::endl; 21 | } 22 | ``` 23 | 24 | ## join 25 | 26 | This is a more sophisticated joining operation that emulates an ```inner join``` in database parlance. The inputs are an inner and outer range, and a key selection expression for each of them, and a transformation for an element from each of the two provided ranges. 27 | 28 | The call to the transformation function is made for each element from inner and outer that match according to their keys. The input ranges can be of different types, but the keys from each must be of the same or a convertible type. 29 | 30 | By default, the keys from each range are compared using ```<```. An optional comparer function can also be provided. 31 | 32 | ```c++ 33 | struct left 34 | { 35 | int id; 36 | double val; 37 | }; 38 | struct right 39 | { 40 | int id; 41 | std::string name; 42 | }; 43 | std::vector< left > inner 44 | { 45 | left{ 0, 0.1 }, 46 | left{ 1, 1.1 }, 47 | left{ 2, 2.1 }, 48 | }; 49 | std::vector< right > outer 50 | { 51 | right{ 0, "Zero" }, 52 | right{ 2, "Two" }, 53 | right{ 4, "Four" } 54 | }; 55 | 56 | auto joined = from( inner ) | join( from( outer ), 57 | []( const left & i ) { return i.id; }, // inner key selector 58 | []( const right & i ) { return i.id; }, // outer key selector 59 | []( const left & l, const right & r ) // transformation 60 | { return std::make_tuple( std::get< 0 >( l ), std::get< 1 >( l ), std::get< 1 >( r ); } ) ); 61 | 62 | // Produces tuple< int, double, string > of 63 | // ( 0, 0.1, "Zero" ) 64 | // ( 2, 2.1, "Two" ) 65 | 66 | ``` 67 | 68 | [Home](../README.md) 69 | [Index](../README.md#Usage) 70 | 71 | -------------------------------------------------------------------------------- /doc/range.md: -------------------------------------------------------------------------------- 1 | # Range operations 2 | 3 | There are several range types produced by calling one or more of the various expression functions declared elsewhere in the docs. The range types aren''t directly related, except by behaviour: the set of common operations for some given range object ```r``` are as follows: 4 | 5 | ```c++ 6 | item_type v = *r; // dereference the current position to get the value 7 | static_cast< bool >( r );// determine if the range is valid 8 | 9 | ++r; // increment the range object by one position 10 | auto copy = r++; // increment the range but return the position prior to the increment... 11 | item_type v1 = *r++; // Get the current element and increment the range in one go 12 | --r; // decrement the range position 13 | auto copy = r--; // decrement the range position but return the position prior to the decrement... 14 | item_type v2 = *r--; // Get the current element and decrement the range in one go 15 | ``` 16 | 17 | Attempting to dereference a range that is invalid (i.e. ```static_cast< bool >( r ) == false```) results in a ```range_access_exception```. NB: a range can be made invalid by incrementing past the last element or decrementing past the first element. If the range has elements, then decrementing or incrementing (respectively) makes the range "valid" once more. 18 | 19 | ## from 20 | 21 | This is the operation to create a range object. Ranges can be created from a standard initialization list, or any collection which can be used in a range-based (different range!) for loop (i.e. any ```x``` for which ```begin( x )``` and ```end( x )``` are well-defined). 22 | 23 | The ```from``` operation handles temporaries by moving the argument into a managed ```std::vector``` of the correct value type. Calling ```from``` with a named object (lvalue) produces a ```range``` object that directly references that object through the iterator pair obtained by calling ```begin``` and ```end``` for it. 24 | 25 | ```c++ 26 | auto r1 = from( { 1, 2, 3 } ); // r-value init list, creates a vector of ints to reference 27 | 28 | auto i = { 1, 2, 3 }; 29 | auto r2 = from( i ); // l-value init list, references the contents of i directly 30 | 31 | auto r3 = from( std::vector< std::string >() ); // r-value container (empty), which is moved to an owned-container 32 | 33 | std::list< double > d { 0.1, 2.3, 4.5 }; 34 | auto r4 = from( d ); // l-value container of doubles, r4 references d iterators directly 35 | ``` 36 | 37 | ## to 38 | 39 | This is the operation to turn a ```range``` back into a standard container. Currently only ```std::vector```, ```std::list```, ```std::deque``` and ```std::forward_list``` are supported. 40 | 41 | ```c++ 42 | auto r = from( { 1, 2, 3 } ); 43 | auto v = r | to< std::vector >(); 44 | auto l = r | to< std::list >(); 45 | auto d = r | to< std::deque >(); 46 | auto f = r | to< std::forward_list >(); 47 | ``` 48 | 49 | ## make_range 50 | 51 | This is an one of two alternate ways to make a range, and has three overloads. 52 | (1) makes a default range from a type, which must support ```++``` to get the next value. This produces (effectively) an infinite range. 53 | (2) is the same type of default range, but begins at a provided value 54 | 55 | ```c++ 56 | auto def = make_range< int >(); 57 | auto init = make_range< int >( 5 ); 58 | 59 | // def Produces { 0, 1, 2, 3, ... std::numeric_limits< int >::max} 60 | // init produces { 5, 6, 7, ... std::numeric_limits< int >::max} 61 | ``` 62 | (3) This third overload can be used to provide a completely user-defined range. Whenever the resulting range is incremented (using ```++```), the callback is invoked to get the next item. The previous value is passed to callback function. An initial value is passed in to the ```make_range``` function. 63 | 64 | ```c++ 65 | auto custom = make_range< int >( 2, []( int i ) { return i + 5; } ); 66 | 67 | // Produces { 2, 10, 50, 2500, ... } 68 | ``` 69 | 70 | ## fill_range 71 | 72 | This is a variant of ```make_range``` which fills a range of given type with a single value. 73 | 74 | ```c++ 75 | auto r = fill_range< int >( 128 ); 76 | 77 | // Produces { 128, 128, 128, ... } 78 | ``` 79 | 80 | ## range 81 | 82 | There is limited support for a local named variable of ```range``` type that can be used to refer to any range object. It supports all the operations of the basic ranges (```*```, ```++```, ```--``` and conversion to ```bool```). 83 | 84 | ```c++ 85 | range< int > r; 86 | r = from( { 1, 2, 3 } ) | select( []( int i ) { return i * 100; } ); 87 | 88 | for( auto i : r ) 89 | { 90 | std::cout << i << ":"; 91 | } 92 | std::cout << "\n"; 93 | 94 | r = from( { 2, 4, 6, 8, 10, 12 } ) | where( []( int i ) { return i % 3 == 0; } ); 95 | for( auto i : r ) 96 | { 97 | std::cout << i << ":"; 98 | } 99 | std::cout << "\n"; 100 | ``` 101 | 102 | ## cycle 103 | 104 | Given an input range, produce an infinite range by cycling its contents, i.e. when iterating the range reaches the end, re-start at the beginning 105 | 106 | ```c++ 107 | auto r = from( { 1, 2, 3 } ) | cycle() | take( 5 ); 108 | for( auto i : r ) 109 | { 110 | std::cout << i << ":"; 111 | } 112 | std::cout << "\n"; 113 | 114 | // 1:2:3:1:2 115 | ``` 116 | 117 | [Home](../README.md) 118 | [Index](../README.md#Usage) 119 | -------------------------------------------------------------------------------- /doc/select.md: -------------------------------------------------------------------------------- 1 | # select where selectmany zipwith 2 | 3 | ## select 4 | 5 | This is the transforming operation. It takes the elements of an input range and produces elements transformed from them. The resulting elements may have different values, or perhaps a different type. 6 | 7 | ```c++ 8 | auto transformed = from( { 1, 2, 3 } ) | select( []( int i ) { return std::to_string( i * 10 ) } ); 9 | 10 | // Produces { "10", "20", "30" } 11 | ``` 12 | 13 | ## where 14 | 15 | This is the basic filtering operation which only returns elements which match the provided predicate. 16 | 17 | ```c++ 18 | auto filtered = from( { 1, 2, 3, 4 } ) | where( []( int i ) { return i % 2 == 0; } ); 19 | 20 | // Produces { 2, 4 } 21 | ``` 22 | 23 | ## selectmany 24 | 25 | This is a flattening operation, and is similar to the ```bind``` operation for amplified types in functional programming. The provided expression needs to return a range; the ranges from each of the original elements are then "flattened" into a single range of individual elements from those ranges (as if they were concatenated). 26 | 27 | ```c++ 28 | struct item 29 | { 30 | int id; 31 | std::vector< std::string > subitems; 32 | }; 33 | std::vector< item > items { 34 | item { 1, { "1", "One" } }, 35 | item { 1, { "2", "Two" } }, 36 | item { 1, { "3", "Three" } }, 37 | }; 38 | auto r = from( items ) | selectmany( []( const item & i ) { return from( i.subitems ); } ); 39 | 40 | // Produces { "1", "One", "2", "Two", "3", "Three" } 41 | ``` 42 | 43 | ## zipwith 44 | 45 | This operation takes an input range and associates it with one (or more) other ranges such that for 2 ranges r1 and r2, 46 | the new result range''s elements are (r1[0],r2[0]), (r1[1],r2[1]), ... (r1[n],r2[n]). 47 | 48 | Zipping multiple ranges is not supported in Visual Studion 2013. 49 | 50 | ```c++ 51 | auto zipped = from( { 1, 2, 3 } ) | zipwith( from( { "1", "2", "3" } ) ); 52 | auto zipped_n = from( { 1, 2, 3 } ) | zipwith( from( { "1", "2", "3" } ), from( { "One", "Two", "Three" } ) ); 53 | 54 | ``` 55 | 56 | [Home](../README.md) 57 | [Index](../README.md#Usage) 58 | -------------------------------------------------------------------------------- /doc/setops.md: -------------------------------------------------------------------------------- 1 | # distinct except intersect_with union_with 2 | 3 | ## distinct 4 | 5 | This operation returns a range where duplicates in the input have been removed. The input range must be ordered. The ```distinct``` operation can optionally take a comparison function which defaults to ```std::less```. A strictly weak-orderd input is required. 6 | 7 | If a custom comparer is provided, it should ideally be the same comparer used to sort the input (it **must** return the same for any 2 elements as that used to sort the range). 8 | 9 | See also [sorted](select.md). 10 | 11 | ```c++ 12 | auto unique = from( { 1, 1, 2, 3, 3 } ) | distinct(); 13 | 14 | struct item 15 | { 16 | int id; 17 | std::string name; 18 | }; 19 | 20 | std::vector< item > data; // unordered 21 | auto r = from( data ) 22 | | sorted( []( const item & l, const item & r ) { return l.id < r.id; } ) 23 | | distinct( []( const item & l, const item & r ) { return l.id < r.id; } ); 24 | ``` 25 | 26 | ## except 27 | 28 | This operation produces the set difference between the source range and another input range. Both ranges must be ordered, and as with ```distinct```, the comparison for ordering should be the same as that used to order the ranges. By default, ```std::less``` is used if none is provided. 29 | 30 | Items from the first range not in the second are returned. 31 | 32 | Where an item occurs multiple times in either range, they are matched to the second range individually (as for std::set_difference). For example, if an item occurs ```m``` times in the left range and ```n``` times in the right range, the result output will contain ```m-n``` occurrences of it. 33 | 34 | 35 | ```c++ 36 | auto diff = from( { 1, 2, 2, 3, 4 } ) | except( from( { 2, 4, 8 } ) ); 37 | 38 | // produces { 1, 2, 3 } 39 | ``` 40 | 41 | ## intersect_with 42 | 43 | This operation produces the set intersection between the source range and another input range. Both ranges must be ordered, and as with ```distinct```, the comparison for ordering should be the same as that used to order the ranges. By default, ```std::less``` is used if none is provided. 44 | 45 | items from the first range that are also in the second range are returned. 46 | 47 | Where an item occurs multiple times in either range, they are matched individually (as for std::set_intersection). So, if the left range has ```m``` occurrences of an item, and the right range has ```n``` occurrences, the result will contain the minimum of ```m``` and ```n```. 48 | 49 | ```c++ 50 | auto common = from( { 1, 2, 2, 3, 4 } ) | intersect_with( from( { 2, 2, 4, 4, 8 } ) ); 51 | 52 | // Produces { 2, 2, 4 } 53 | ``` 54 | 55 | ## union_with 56 | 57 | This operation produces the set union between the source range and another input range. Both ranges must be ordered, and as with ```distinct```, the comparison for ordering should be the same as that used to order the ranges. By default, ```std::less``` is used if none is provided. 58 | 59 | Where an item occurs multiple times in either range, then all elements from the left range are returned, along with any remaining items from the right range not already matched to an item. E.g. if an item occurs ```m``` times in the left range and ```n``` times in the right range, the returned range contains ```m+std::max(n-m,0)``` occurrences. 60 | 61 | ```c++ 62 | auto both = from( { 1, 2, 2, 3, 4 } ) | union_with( from( { 2, 4, 4, 8 } ) ); 63 | 64 | // Produces { 1, 2, 2, 3, 4, 4, 8 } 65 | ``` 66 | 67 | [Home](../README.md) 68 | [Index](../README.md#Usage) 69 | 70 | -------------------------------------------------------------------------------- /doc/skiptake.md: -------------------------------------------------------------------------------- 1 | # skip skip_while take and take_while 2 | 3 | ## skip 4 | 5 | This operation skips over the first ```N``` elements, effectively starting the range on the ```N+1``` element. 6 | 7 | ```c++ 8 | auto r = from( { 1, 2, 3, 4, 5 } ) | skip( 3 ); 9 | 10 | //produces { 4, 5 } 11 | ``` 12 | 13 | ## skip_while 14 | 15 | This operation skips over elements *until* the provided predicate is false. 16 | 17 | ```c++ 18 | auto r = from( { 1, 2, 3, 4, 5 } ) | skip_while( []( int i ) { return i <= 3; } ); 19 | 20 | //produces { 4, 5 } 21 | ``` 22 | 23 | ## take 24 | 25 | This operation produces ```N``` elements from the input and then stops (becomes invalid) 26 | 27 | ```c++ 28 | auto r = from( { 1, 2, 3, 4, 5 } ) | take( 3 ); 29 | 30 | //produces { 1, 2, 3 } 31 | ``` 32 | 33 | This is especially useful for limiting the number of elements returned from an otherwise infinite range, produced by [make_range](range.md#make_range) and [fill_range](range.md#fill_range). 34 | 35 | ## take_while 36 | 37 | This operation takes elements from the range until the provided predicate is false. 38 | 39 | ```c++ 40 | auto r = from( { 1, 2, 3, 4, 5 } ) | take_while( []( int i ) { return i <= 3; } ); 41 | 42 | //produces { 1, 2, 3 } 43 | ``` 44 | 45 | This is especially useful for limiting the number of elements returned from an otherwise infinite range, produced by [make_range](range.md#make_range) and [fill_range](range.md#fill_range). 46 | 47 | [Home](../README.md) 48 | [Index](../README.md#Usage) 49 | 50 | -------------------------------------------------------------------------------- /doc/sorting.md: -------------------------------------------------------------------------------- 1 | # sorted merge_with 2 | 3 | ## sorted 4 | 5 | The operation sorts the input range according to the provided comparison operation. If no comparison is provided, ```std::less``` is used. The comparison operation should take two elements and return ```true``` if the left is less than the right. 6 | 7 | This operation buffers the input range and copies the elements, so introduces a break in a streamed expression. 8 | 9 | The sorting is stable. The buffer is a ```std::list``` and sorting uses the list''s ```sort``` member function. 10 | 11 | ```c++ 12 | auto r = from( { 3, 2, 1 } ) | sorted(); 13 | 14 | // Produces { 3, 2, 1 } 15 | ``` 16 | 17 | Not recommended, but this produces a reverse-ordered range: 18 | ```c++ 19 | auto r = from( { 1, 2, 3 } ) | sorted( []( int left, int right ) { return right < left; } ); 20 | 21 | // Produces { 1, 2, 3 } 22 | ``` 23 | 24 | ## merge_with 25 | 26 | 27 | This operation merges two already ordered ranges into a single ordered range. 28 | 29 | ```c++ 30 | auto left = from( { 1, 2, 4, 8, 16 }; 31 | auto r = left | merge( from( { 2, 3, 4, 5, 6, 7, 8 } ) ); 32 | 33 | //Produces { 1, 2, 3, 4, 5, 6, 7, 8, 16 } 34 | ``` 35 | 36 | ## reverse 37 | 38 | Does exactly what it says on the tin - produces the elements of the input range in reverse order. Notably, this operation does **not** buffer the input - it is a streaming operation. 39 | 40 | ```c++ 41 | auto reversed = from( { 1, 2, 3 } ) | reverse() 42 | 43 | // Produces { 3, 2, 1 } 44 | ``` 45 | 46 | [Home](../README.md) 47 | [Index](../README.md#Usage) 48 | -------------------------------------------------------------------------------- /src/clang.mak: -------------------------------------------------------------------------------- 1 | CLANGINC=-Id:/bin/mingw64/include/c++/4.8.1 -Id:/bin/mingw64/include/c++/4.8.1/x86_64-w64-mingw32 -pedantic 2 | #-fsyntax-only 3 | # CLANGINC=-Ic:/bin/gcc/mingw/include/c++/4.8.1 -Ic:/bin/gcc/mingw/include/c++/4.8.1/x86_64-w64-mingw32 -pedantic -fsyntax-only 4 | INCLUDE=$(CLANGINC) -Inarl -I../externals/catch/single_include 5 | OBJDIR=tmp 6 | SRCDIR=tests/testnarl 7 | 8 | OBJS= $(OBJDIR)/testnarl.oclang \ 9 | $(OBJDIR)/test_concatenating_range.oclang \ 10 | $(OBJDIR)/test_diffing_range.oclang \ 11 | $(OBJDIR)/test_distinct_range.oclang \ 12 | $(OBJDIR)/test_filtering_range.oclang \ 13 | $(OBJDIR)/test_grouping_range.oclang \ 14 | $(OBJDIR)/test_intersecting_range.oclang \ 15 | $(OBJDIR)/test_iterable_range.oclang \ 16 | $(OBJDIR)/test_joined_range.oclang \ 17 | $(OBJDIR)/test_merging_range.oclang \ 18 | $(OBJDIR)/test_partial_range.oclang \ 19 | $(OBJDIR)/test_range_accumulate.oclang \ 20 | $(OBJDIR)/test_range_factory.oclang \ 21 | $(OBJDIR)/test_range_generator.oclang \ 22 | $(OBJDIR)/test_range_predicate.oclang \ 23 | $(OBJDIR)/test_reversed_range.oclang \ 24 | $(OBJDIR)/test_selectmany_range.oclang \ 25 | $(OBJDIR)/test_sorted_range.oclang \ 26 | $(OBJDIR)/test_tocontainer_range.oclang \ 27 | $(OBJDIR)/test_transforming_range.oclang \ 28 | $(OBJDIR)/test_unioning_range.oclang \ 29 | $(OBJDIR)/test_zipped_range.oclang \ 30 | $(OBJDIR)/narl_stl.oclang \ 31 | 32 | CPPFLAGS=-std=c++11 -Wall -Wextra -Wpedantic 33 | CC=clang++ 34 | 35 | testnarlclang.exe: $(OBJS) 36 | ECHO $(CC) $(CPPFLAGS) -o $@ $^ 37 | 38 | include $(OBJS:.oclang=.dclang) 39 | 40 | $(OBJDIR): 41 | -mkdir $(OBJDIR) 42 | 43 | $(OBJDIR)/%.oclang: $(SRCDIR)/%.cpp 44 | $(CC) $(CPPFLAGS) -c -o $@ $< $(INCLUDE) 45 | 46 | $(OBJDIR)/%.dclang: $(SRCDIR)/%.cpp 47 | @set -e; rm -f $@; \ 48 | $(CC) -MM $(CPPFLAGS) $(INCLUDE) $< > $@.$$$$; \ 49 | sed 's,\($*\)\.o[ :]*,$(OBJDIR)/\1.o $@ : ,g' < $@.$$$$ > $@; \ 50 | rm -f $@.$$$$ 51 | -------------------------------------------------------------------------------- /src/exp/iterable_range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | namespace xri 17 | { 18 | 19 | template< typename range_type > 20 | class basic_range 21 | { 22 | public: 23 | auto any() -> bool { return true; } 24 | 25 | template< typename unary_predicate > 26 | auto any( unary_predicate fn ) -> bool { return false; } 27 | 28 | template< typename unary_predicate > 29 | auto all( unary_predicate fn ) -> bool { return true; } 30 | 31 | auto count() -> size_t { return 0; } 32 | }; 33 | 34 | template< template< typename, typename > class range_type, typename expression_type > 35 | class range_factory 36 | { 37 | public: 38 | range_factory( expression_type action ) : action{ action } { } 39 | 40 | template< typename range_of > 41 | auto operator()( range_of r ) -> range_type< range_of, expression_type > 42 | { 43 | return range_type< range_of, expression_type >{ r, action }; 44 | } 45 | 46 | private: 47 | expression_type action; 48 | }; 49 | 50 | template< template< typename > class range_type, typename expression_type > 51 | class range_factory_1 52 | { 53 | public: 54 | range_factory_1( expression_type action ) : action{ action } { } 55 | 56 | template< typename range_of > 57 | auto operator()( range_of r ) -> range_type< range_of > 58 | { 59 | return range_type< range_of >{ r, action }; 60 | } 61 | 62 | private: 63 | expression_type action; 64 | }; 65 | 66 | template< template< typename, typename > class range_type, typename expression_type > 67 | auto make_range_factory( expression_type expr ) -> range_factory< range_type, expression_type > 68 | { 69 | return range_factory< range_type, expression_type >{ expr }; 70 | } 71 | 72 | template< template< typename > class range_type, typename expression_type > 73 | auto make_range_factory( expression_type expr ) -> range_factory_1< range_type, expression_type > 74 | { 75 | return range_factory_1< range_type, expression_type >{ expr }; 76 | } 77 | 78 | template< typename iterator_type, typename value_type_tag=typename iterator_type::value_type > 79 | class iterable_range 80 | { 81 | public: 82 | typedef value_type_tag value_type; 83 | 84 | iterable_range( iterator_type begin, iterator_type end ) 85 | : pos{ begin }, end_pos{ end } { } 86 | 87 | auto operator*() const -> value_type 88 | { 89 | return *pos; 90 | } 91 | 92 | auto operator++() -> iterable_range & 93 | { 94 | ++pos; 95 | return *this; 96 | } 97 | auto operator++( int ) -> iterable_range 98 | { 99 | iterable_range tmp{ *this }; 100 | operator++(); 101 | return tmp; 102 | } 103 | 104 | explicit operator bool() const { return pos != end_pos; } 105 | 106 | private: 107 | iterator_type pos, end_pos; 108 | }; 109 | 110 | template< typename container_type > 111 | auto make_range( const container_type & ctr ) -> iterable_range< typename container_type::const_iterator > 112 | { 113 | return iterable_range< typename container_type::const_iterator >{ begin( ctr ), end( ctr ) }; 114 | } 115 | 116 | template< typename array_type, size_t N > 117 | auto make_range( array_type( &array )[ N ] ) -> iterable_range< array_type*, array_type > 118 | { 119 | return iterable_range< array_type*, array_type >{ array, array + N }; 120 | } 121 | 122 | 123 | template< typename range_type, typename transformation > 124 | class transforming_range 125 | { 126 | private: 127 | range_type r; 128 | transformation fn; 129 | 130 | public: 131 | transforming_range( range_type r, transformation fn ) 132 | : r{ r }, fn{ fn } { } 133 | 134 | auto operator*() const -> decltype( fn( *r ) ) 135 | { 136 | return fn( *r ); 137 | } 138 | 139 | auto operator++() -> transforming_range & 140 | { 141 | ++r; 142 | return *this; 143 | } 144 | auto operator++( int ) -> transforming_range 145 | { 146 | transforming_range tmp{ *this }; 147 | operator++(); 148 | return tmp; 149 | } 150 | 151 | explicit operator bool() const { return !!r; } 152 | 153 | }; 154 | 155 | template< typename range_type, typename transformation > 156 | auto select( range_type r, transformation fn ) -> transforming_range< range_type, transformation > 157 | { 158 | return transforming_range< range_type, transformation >{ r, fn }; 159 | } 160 | 161 | template< typename transformation > 162 | auto select( transformation fn ) -> range_factory< transforming_range, transformation > 163 | { 164 | return make_range_factory< transforming_range >( fn ); 165 | } 166 | 167 | template< typename range_type, typename unary_predicate > 168 | class filtering_range 169 | { 170 | private: 171 | void find_next_match() const 172 | { 173 | while( r && !fn( *r ) ) 174 | ++r; 175 | } 176 | 177 | mutable range_type r; 178 | unary_predicate fn; 179 | 180 | public: 181 | filtering_range( range_type r, unary_predicate fn ) : r{ r }, fn{ fn } 182 | { } 183 | 184 | auto operator*() const -> decltype( *r ) 185 | { 186 | find_next_match(); 187 | return *r; 188 | } 189 | 190 | auto operator++() -> filtering_range & 191 | { 192 | ++r; 193 | find_next_match(); 194 | return *this; 195 | } 196 | auto operator++( int ) -> filtering_range 197 | { 198 | filtering_range tmp{ *this }; 199 | operator++(); 200 | return tmp; 201 | } 202 | 203 | explicit operator bool() const { find_next_match(); return !!r; } 204 | 205 | }; 206 | 207 | template< typename range_type, typename unary_predicate > 208 | auto where( range_type range, unary_predicate fn ) -> filtering_range< range_type, unary_predicate > 209 | { 210 | return filtering_range< range_type, unary_predicate >{ range, fn }; 211 | } 212 | 213 | template< typename unary_predicate > 214 | auto where( unary_predicate fn ) -> decltype( make_range_factory< filtering_range >( fn ) ) 215 | { 216 | return make_range_factory< filtering_range >( fn ); 217 | } 218 | 219 | template< typename range_type > 220 | class limited_range 221 | { 222 | private: 223 | void skip() 224 | { 225 | while( r && count < 0 ) 226 | { 227 | ++r; 228 | ++count; 229 | } 230 | } 231 | range_type r; 232 | int count; 233 | 234 | public: 235 | limited_range( range_type r, int count ) 236 | : r{ r }, count{ count } 237 | { 238 | skip(); 239 | } 240 | 241 | auto operator*() const -> decltype( *r ) 242 | { 243 | return *r; 244 | } 245 | auto operator++() -> limited_range & 246 | { 247 | if( r ) 248 | { 249 | ++r; 250 | --count; 251 | } 252 | return *this; 253 | } 254 | auto operator++( int ) -> limited_range 255 | { 256 | limited_range tmp{ *this }; 257 | operator++(); 258 | return tmp; 259 | } 260 | explicit operator bool() const 261 | { 262 | return !!r && count > 0; 263 | } 264 | }; 265 | 266 | template< typename range_type > 267 | auto take( range_type range, size_t count ) -> limited_range< range_type > 268 | { 269 | return limited_range< range_type >{ range, static_cast< int >( count ) }; 270 | } 271 | 272 | auto take( size_t count ) -> decltype( make_range_factory< limited_range >( static_cast< int >( count ) ) ) 273 | { 274 | return make_range_factory< limited_range >( static_cast< int >( count ) ); 275 | } 276 | 277 | 278 | template< typename range_type, typename range_factory_type > 279 | auto operator|( range_type range, range_factory_type factory ) -> decltype( factory( range ) ) 280 | { 281 | return factory( range ); 282 | } 283 | 284 | template< typename range_type, typename value_type > 285 | class range_output_iterator : public std::iterator< std::input_iterator_tag, value_type > 286 | { 287 | public: 288 | range_output_iterator( const range_type & r ) 289 | : r{ r } 290 | { 291 | } 292 | 293 | auto operator!=( const range_output_iterator & r ) const -> bool 294 | { 295 | return !operator==( r ); 296 | } 297 | 298 | auto operator==( const range_output_iterator & ) const -> bool 299 | { 300 | return !r; 301 | } 302 | 303 | auto operator++() -> range_output_iterator & 304 | { 305 | ++r; 306 | return *this; 307 | } 308 | 309 | auto operator*() const -> value_type 310 | { 311 | return *r; 312 | } 313 | 314 | private: 315 | range_type r; 316 | 317 | }; 318 | 319 | template< typename range_type > 320 | auto begin( range_type r ) -> range_output_iterator< range_type, decltype( *r ) > 321 | { 322 | return range_output_iterator< range_type, decltype( *r ) >{ r }; 323 | } 324 | template< typename range_type > 325 | auto end( range_type r ) -> range_output_iterator< range_type, decltype( *r ) > 326 | { 327 | return range_output_iterator< range_type, decltype( *r ) >{ r }; 328 | } 329 | 330 | } 331 | 332 | 333 | -------------------------------------------------------------------------------- /src/exp/makefile: -------------------------------------------------------------------------------- 1 | INCLUDE=-Ixri -I../../externals/catch/single_include 2 | SRC=test.cpp 3 | OBJS=test.o 4 | 5 | %.o: %.cpp 6 | g++ -std=c++11 -c -o $@ $< -Wall $(INCLUDE) 7 | 8 | test.exe: $(OBJS) 9 | g++ -std=c++11 -o $@ $^ 10 | 11 | tests: clean test.exe 12 | .\test.exe 13 | 14 | clean: 15 | -rm *.o 16 | -rm *.exe 17 | -------------------------------------------------------------------------------- /src/exp/test.cpp: -------------------------------------------------------------------------------- 1 | #define CATCH_CONFIG_MAIN 2 | #include 3 | 4 | #include "iterable_range.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | using namespace xri; 14 | 15 | //std::string to_string( int i ) { std::stringstream strm; strm << i; return strm.str(); } 16 | 17 | 18 | TEST_CASE( "Range is constructable from standard collection and iterable", "[range][init][iterable][stl]" ) 19 | { 20 | std::vector< int > data { 1, 2, 3 }; 21 | auto range = make_range( data ); 22 | 23 | REQUIRE( *range++ == data[ 0 ] ); 24 | REQUIRE( *range++ == data[ 1 ] ); 25 | REQUIRE( *range++ == data[ 2 ] ); 26 | } 27 | 28 | TEST_CASE( "Transformation of elements results in new range leaving originals intact", "[range][transform]" ) 29 | { 30 | std::vector< int > data { 1, 2, 3 }; 31 | auto range = make_range( data ); 32 | 33 | using namespace std; 34 | auto result = select( range, []( int i ) { return to_string( i ); } ); 35 | 36 | std::string expected[] = { "1", "2", "3" }; 37 | 38 | REQUIRE( *result++ == expected[ 0 ] ); 39 | REQUIRE( *result++ == expected[ 1 ] ); 40 | REQUIRE( *result++ == expected[ 2 ] ); 41 | 42 | REQUIRE( *range++ == data[ 0 ] ); 43 | REQUIRE( *range++ == data[ 1 ] ); 44 | REQUIRE( *range++ == data[ 2 ] ); 45 | } 46 | 47 | TEST_CASE( "Filtering elements contains just the matches", "[range][filter]" ) 48 | { 49 | std::vector< int > data { 1, 2, 3 }; 50 | auto range = make_range( data ); 51 | 52 | auto result = where( range, []( int i ) { return i % 2 != 0; } ); 53 | 54 | REQUIRE( *result++ == data[ 0 ] ); 55 | REQUIRE( *result++ == data[ 2 ] ); 56 | } 57 | 58 | TEST_CASE( "Filtering range returns correct matches when first element is a mismatch", "[range][filter][empty]" ) 59 | { 60 | std::vector< int > data { 2, 3, 4 }; 61 | auto range = make_range( data ); 62 | 63 | auto result = where( range, []( int i ) { return i % 2 != 0; } ); 64 | 65 | REQUIRE( !!result ); 66 | REQUIRE( *result++ == data[ 1 ] ); 67 | } 68 | 69 | TEST_CASE( "Filtering range is immediately invalid when no elements match", "[range][filter][nomatch]" ) 70 | { 71 | std::vector< int > data { 2, 3, 4 }; 72 | auto range = make_range( data ); 73 | 74 | auto result = where( range, []( int ) { return false; } ); 75 | 76 | REQUIRE( ! result ); 77 | } 78 | 79 | TEST_CASE( "Take returns a range with the specified number of elements", "[range][take][inline]" ) 80 | { 81 | std::vector< int > data { 1, 2, 4, 8, 16 }; 82 | auto range = make_range( data ); 83 | 84 | auto result = take( range, 1 ); 85 | 86 | REQUIRE( *result++ == data[ 0 ] ); 87 | REQUIRE( !result ); 88 | } 89 | 90 | TEST_CASE( "Ranges can be composed using the overloaded operator", "[range][composition][operator]" ) 91 | { 92 | std::vector< int > data { 1, 2, 3 }; 93 | auto range = make_range( data ); 94 | 95 | auto result = range | where( []( int i ) { return i % 2 != 0; } ) 96 | | select( []( int i ) { return i * 10; } ); 97 | 98 | REQUIRE( *result++ == data[ 0 ] * 10 ); 99 | REQUIRE( *result++ == data[ 2 ] * 10 ); 100 | REQUIRE( ! result ); 101 | } 102 | 103 | TEST_CASE( "Range can be limited to a number of elements with take without invalidating original range", "[range][take]" ) 104 | { 105 | std::vector< int > data { 1, 2, 3, 4, 5 }; 106 | auto range = make_range( data ); 107 | 108 | auto result = range | take( 3 ); 109 | 110 | REQUIRE( *result++ == data[ 0 ] ); 111 | REQUIRE( *result++ == data[ 1 ] ); 112 | REQUIRE( *result++ == data[ 2 ] ); 113 | REQUIRE( !result ); 114 | 115 | REQUIRE( *range == data[ 0 ] ); 116 | } 117 | 118 | 119 | TEST_CASE( "Range can be used to populate a standard lib container", "[range][export][stl]" ) 120 | { 121 | using namespace std; 122 | 123 | vector< int > data { 1, 2, 3 }; 124 | auto range = make_range( data ) | select( []( int x ) { return to_string( x ); } ); 125 | 126 | vector< string > result { begin( range ), end( range ) }; 127 | 128 | REQUIRE( result.size() == data.size() ); 129 | REQUIRE( to_string( data[ 0 ] ) == result[ 0 ] ); 130 | REQUIRE( to_string( data[ 1 ] ) == result[ 1 ] ); 131 | REQUIRE( to_string( data[ 2 ] ) == result[ 2 ] ); 132 | } 133 | 134 | 135 | -------------------------------------------------------------------------------- /src/exp/tests.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.20623.1 VSUPREVIEW 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tests", "tests.vcxproj", "{D3803D29-537A-4B95-8BFD-ADF5FA4B5947}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Release|Win32 = Release|Win32 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {D3803D29-537A-4B95-8BFD-ADF5FA4B5947}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {D3803D29-537A-4B95-8BFD-ADF5FA4B5947}.Debug|Win32.Build.0 = Debug|Win32 16 | {D3803D29-537A-4B95-8BFD-ADF5FA4B5947}.Release|Win32.ActiveCfg = Release|Win32 17 | {D3803D29-537A-4B95-8BFD-ADF5FA4B5947}.Release|Win32.Build.0 = Release|Win32 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /src/exp/tests.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | 15 | 16 | 17 | {D3803D29-537A-4B95-8BFD-ADF5FA4B5947} 18 | Win32Proj 19 | tests 20 | 21 | 22 | 23 | Application 24 | true 25 | v120 26 | Unicode 27 | 28 | 29 | Application 30 | false 31 | v120 32 | true 33 | Unicode 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | true 47 | 48 | 49 | false 50 | 51 | 52 | 53 | 54 | 55 | Level4 56 | Disabled 57 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 58 | ..\..\externals\catch\single_include 59 | 60 | 61 | Console 62 | true 63 | 64 | 65 | 66 | 67 | Level3 68 | 69 | 70 | MaxSpeed 71 | true 72 | true 73 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 74 | 75 | 76 | Console 77 | true 78 | true 79 | true 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /src/makefile: -------------------------------------------------------------------------------- 1 | CLANGINC=-Id:/bin/mingw64/include/c++/4.8.1 -Id:/bin/mingw64/include/c++/4.8.1/x86_64-w64-mingw32 -pedantic 2 | INCLUDE=-Inarl -I../externals/catch/single_include 3 | OBJDIR=tmp 4 | SRCDIR=tests/testnarl 5 | 6 | # * aggregate 7 | # * all 8 | # * any 9 | # * concat 10 | # * count 11 | # * distinct 12 | # * except 13 | # * groupby 14 | # * join 15 | # * intersect 16 | # * range 17 | # * reverse 18 | # * select 19 | # * selectmany 20 | # * sequenceequal 21 | # * skip 22 | # * skipwhile 23 | # * sorted 24 | # * take 25 | # * takewhile 26 | # * to... 27 | # * union 28 | # * where 29 | # * zip 30 | # - average ( aggregate ) 31 | # - cast ( select ) 32 | # - default ( n/a ) 33 | # - defaultifempty ( n/a ) 34 | # - elementat ( where? ) 35 | # - empty 36 | # - first ( * ) 37 | # - max 38 | # - min 39 | # - oftype ( where ) 40 | # - repeat ( special case of generate ) 41 | # - sum ( aggregate ) 42 | # - contains ( same as any( predicatee ) ) 43 | # groupjoin 44 | # last 45 | # single 46 | 47 | OBJS= $(OBJDIR)/testnarl.o \ 48 | $(OBJDIR)/test_concatenating_range.o \ 49 | $(OBJDIR)/test_cycling_range.o \ 50 | $(OBJDIR)/test_diffing_range.o \ 51 | $(OBJDIR)/test_distinct_range.o \ 52 | $(OBJDIR)/test_filtering_range.o \ 53 | $(OBJDIR)/test_grouping_range.o \ 54 | $(OBJDIR)/test_intersecting_range.o \ 55 | $(OBJDIR)/test_iterable_range.o \ 56 | $(OBJDIR)/test_joined_range.o \ 57 | $(OBJDIR)/test_merging_range.o \ 58 | $(OBJDIR)/test_partial_range.o \ 59 | $(OBJDIR)/test_range_accumulate.o \ 60 | $(OBJDIR)/test_range_factory.o \ 61 | $(OBJDIR)/test_range_generator.o \ 62 | $(OBJDIR)/test_range_predicate.o \ 63 | $(OBJDIR)/test_reversed_range.o \ 64 | $(OBJDIR)/test_selectmany_range.o \ 65 | $(OBJDIR)/test_sorted_range.o \ 66 | $(OBJDIR)/test_tocontainer_range.o \ 67 | $(OBJDIR)/test_transforming_range.o \ 68 | $(OBJDIR)/test_unioning_range.o \ 69 | $(OBJDIR)/test_zipped_range.o \ 70 | $(OBJDIR)/narl_stl.o \ 71 | 72 | CPPFLAGS=-std=c++11 -Wall -Wextra -Wpedantic 73 | CC=g++ 74 | 75 | .PHONY: tests 76 | tests: testnarl.exe 77 | .\testnarl.exe 78 | 79 | .PHONY: clean 80 | clean: 81 | -rm $(OBJS) 82 | -rm testnarl.exe 83 | 84 | .PHONY: release 85 | release: 86 | echo $(CC) $(CPPFLAGS) $(INCLUDE) -O3 -o narl_tests_opt.exe $(SRCDIR)/*.cpp 87 | 88 | testnarl.exe: $(OBJS) 89 | $(CC) $(CPPFLAGS) -o $@ $^ 90 | 91 | include $(OBJS:.o=.d) 92 | 93 | $(OBJDIR)/%.o: $(SRCDIR)/%.cpp 94 | $(CC) $(CPPFLAGS) -c -o $@ $< $(INCLUDE) 95 | 96 | $(OBJDIR)/%.d: $(SRCDIR)/%.cpp 97 | -mkdir $(OBJDIR) 98 | @set -e; rm -f $@; \ 99 | $(CC) -MM $(CPPFLAGS) $(INCLUDE) $< > $@.$$$$; \ 100 | sed 's,\($*\)\.o[ :]*,$(OBJDIR)/\1.o $@ : ,g' < $@.$$$$ > $@; \ 101 | rm -f $@.$$$$ 102 | -------------------------------------------------------------------------------- /src/makefile_speed: -------------------------------------------------------------------------------- 1 | CLANGINC=-Id:/bin/mingw64/include/c++/4.8.1 -Id:/bin/mingw64/include/c++/4.8.1/x86_64-w64-mingw32 -pedantic 2 | INCLUDE=-Inarl -I/work/dev/lib/boost_1_55_0 -I../externals/catch/single_include 3 | OBJDIR=tmp 4 | SRCDIR=tests/perf 5 | 6 | OBJS= $(OBJDIR)/narl_speed.o \ 7 | 8 | CPPFLAGS=-std=c++11 -Wall -Wextra -Wpedantic -O3 9 | CC=g++ 10 | 11 | .PHONY: tests 12 | tests: testnarlspeed.exe 13 | .\testnarlspeed.exe -s 14 | 15 | .PHONY: clean 16 | clean: 17 | -rm $(OBJS) 18 | -rm testnarlspeed.exe 19 | 20 | .PHONY: release 21 | release: 22 | echo $(CC) $(CPPFLAGS) $(INCLUDE) -O3 -o narl_tests_opt.exe $(SRCDIR)/*.cpp 23 | 24 | testnarlspeed.exe: $(OBJS) 25 | $(CC) $(CPPFLAGS) -o $@ $^ 26 | 27 | include $(OBJS:.o=.d) 28 | 29 | $(OBJDIR): 30 | -mkdir $(OBJDIR) 31 | 32 | $(OBJDIR)/%.o: $(SRCDIR)/%.cpp 33 | $(CC) $(CPPFLAGS) -c -o $@ $< $(INCLUDE) 34 | 35 | $(OBJDIR)/%.d: $(SRCDIR)/%.cpp 36 | @set -e; rm -f $@; \ 37 | $(CC) -MM $(CPPFLAGS) $(INCLUDE) $< > $@.$$$$; \ 38 | sed 's,\($*\)\.o[ :]*,$(OBJDIR)/\1.o $@ : ,g' < $@.$$$$ > $@; \ 39 | rm -f $@.$$$$ 40 | -------------------------------------------------------------------------------- /src/narl.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.30110.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "narl", "narl.vcxproj", "{A4A9CE62-FEA4-4FB2-8093-1C91ADC278F8}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "narl_speed", "narl_speed.vcxproj", "{29CF8510-5FC9-413D-995E-249E9E83B1A9}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Win32 = Debug|Win32 13 | Debug|x64 = Debug|x64 14 | Release|Win32 = Release|Win32 15 | Release|x64 = Release|x64 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {A4A9CE62-FEA4-4FB2-8093-1C91ADC278F8}.Debug|Win32.ActiveCfg = Debug|Win32 19 | {A4A9CE62-FEA4-4FB2-8093-1C91ADC278F8}.Debug|Win32.Build.0 = Debug|Win32 20 | {A4A9CE62-FEA4-4FB2-8093-1C91ADC278F8}.Debug|x64.ActiveCfg = Debug|x64 21 | {A4A9CE62-FEA4-4FB2-8093-1C91ADC278F8}.Debug|x64.Build.0 = Debug|x64 22 | {A4A9CE62-FEA4-4FB2-8093-1C91ADC278F8}.Release|Win32.ActiveCfg = Release|Win32 23 | {A4A9CE62-FEA4-4FB2-8093-1C91ADC278F8}.Release|Win32.Build.0 = Release|Win32 24 | {A4A9CE62-FEA4-4FB2-8093-1C91ADC278F8}.Release|x64.ActiveCfg = Release|x64 25 | {A4A9CE62-FEA4-4FB2-8093-1C91ADC278F8}.Release|x64.Build.0 = Release|x64 26 | {29CF8510-5FC9-413D-995E-249E9E83B1A9}.Debug|Win32.ActiveCfg = Debug|Win32 27 | {29CF8510-5FC9-413D-995E-249E9E83B1A9}.Debug|Win32.Build.0 = Debug|Win32 28 | {29CF8510-5FC9-413D-995E-249E9E83B1A9}.Debug|x64.ActiveCfg = Debug|x64 29 | {29CF8510-5FC9-413D-995E-249E9E83B1A9}.Debug|x64.Build.0 = Debug|x64 30 | {29CF8510-5FC9-413D-995E-249E9E83B1A9}.Release|Win32.ActiveCfg = Release|Win32 31 | {29CF8510-5FC9-413D-995E-249E9E83B1A9}.Release|Win32.Build.0 = Release|Win32 32 | {29CF8510-5FC9-413D-995E-249E9E83B1A9}.Release|x64.ActiveCfg = Release|x64 33 | {29CF8510-5FC9-413D-995E-249E9E83B1A9}.Release|x64.Build.0 = Release|x64 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | EndGlobal 39 | -------------------------------------------------------------------------------- /src/narl.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav 15 | 16 | 17 | {3cc62be8-4862-42f5-a622-296306092398} 18 | 19 | 20 | 21 | 22 | narl 23 | 24 | 25 | narl 26 | 27 | 28 | narl 29 | 30 | 31 | narl 32 | 33 | 34 | narl 35 | 36 | 37 | narl 38 | 39 | 40 | narl 41 | 42 | 43 | narl 44 | 45 | 46 | narl 47 | 48 | 49 | narl 50 | 51 | 52 | narl 53 | 54 | 55 | narl 56 | 57 | 58 | narl 59 | 60 | 61 | narl 62 | 63 | 64 | narl 65 | 66 | 67 | narl 68 | 69 | 70 | narl 71 | 72 | 73 | narl 74 | 75 | 76 | narl 77 | 78 | 79 | narl 80 | 81 | 82 | narl 83 | 84 | 85 | narl 86 | 87 | 88 | narl 89 | 90 | 91 | narl 92 | 93 | 94 | narl 95 | 96 | 97 | narl 98 | 99 | 100 | narl 101 | 102 | 103 | narl 104 | 105 | 106 | narl 107 | 108 | 109 | 110 | 111 | Source Files 112 | 113 | 114 | Source Files 115 | 116 | 117 | Source Files 118 | 119 | 120 | Source Files 121 | 122 | 123 | Source Files 124 | 125 | 126 | Source Files 127 | 128 | 129 | Source Files 130 | 131 | 132 | Source Files 133 | 134 | 135 | Source Files 136 | 137 | 138 | Source Files 139 | 140 | 141 | Source Files 142 | 143 | 144 | Source Files 145 | 146 | 147 | Source Files 148 | 149 | 150 | Source Files 151 | 152 | 153 | Source Files 154 | 155 | 156 | Source Files 157 | 158 | 159 | Source Files 160 | 161 | 162 | Source Files 163 | 164 | 165 | Source Files 166 | 167 | 168 | Source Files 169 | 170 | 171 | Source Files 172 | 173 | 174 | Source Files 175 | 176 | 177 | Source Files 178 | 179 | 180 | -------------------------------------------------------------------------------- /src/narl/concatenating_range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "range_factory.h" 4 | 5 | 6 | namespace narl 7 | { 8 | 9 | template< typename range_type, typename other_range > 10 | class concatenating_range 11 | { 12 | 13 | private: 14 | range_type r; 15 | other_range o; 16 | bool before_begin; 17 | 18 | 19 | public: 20 | concatenating_range( range_type r, other_range o ) 21 | : r{ r }, o{ o }, before_begin{ false } 22 | { 23 | } 24 | 25 | 26 | auto operator*() const -> decltype( *r ) 27 | { 28 | if( !r ) 29 | return *o; 30 | return *r; 31 | } 32 | 33 | auto operator++() -> concatenating_range & 34 | { 35 | if( before_begin ) 36 | ++r; 37 | else 38 | if( !r ) 39 | ++o; 40 | else 41 | ++r; 42 | before_begin = before_begin ? false : before_begin; 43 | return *this; 44 | } 45 | 46 | auto operator++( int ) -> concatenating_range 47 | { 48 | concatenating_range tmp{ *this }; 49 | ++*this; 50 | return tmp; 51 | } 52 | 53 | auto operator--() -> concatenating_range & 54 | { 55 | if( !r ) 56 | --o; 57 | if( !!r || !o ) 58 | { 59 | --r; 60 | before_begin = !r; 61 | } 62 | return *this; 63 | } 64 | 65 | auto operator--( int ) -> concatenating_range 66 | { 67 | concatenating_range tmp{ *this }; 68 | --*this; 69 | return tmp; 70 | } 71 | 72 | explicit operator bool() const 73 | { 74 | return !before_begin && !( !r && !o ); 75 | } 76 | 77 | void goto_end() 78 | { 79 | r.goto_end(); 80 | o.goto_end(); 81 | } 82 | 83 | }; 84 | 85 | 86 | template< typename range_type > 87 | auto concat( range_type r ) -> decltype( make_factory< concatenating_range >( r ) ) 88 | { 89 | return make_factory< concatenating_range >( r ); 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/narl/cycling_range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "range_factory.h" 4 | 5 | 6 | namespace narl 7 | { 8 | 9 | template< typename range_type > 10 | class cycling_range 11 | { 12 | 13 | private: 14 | range_type r, orig; 15 | 16 | public: 17 | cycling_range( range_type r ) 18 | : r{ r }, orig{ r } 19 | { 20 | } 21 | 22 | 23 | auto operator*() const -> decltype( *r ) 24 | { 25 | return *r; 26 | } 27 | 28 | auto operator++() -> cycling_range & 29 | { 30 | if( !++r ) 31 | r = orig; 32 | return *this; 33 | } 34 | 35 | auto operator++( int ) -> cycling_range 36 | { 37 | cycling_range tmp{ *this }; 38 | ++*this; 39 | return tmp; 40 | } 41 | 42 | auto operator--() -> cycling_range & 43 | { 44 | if( !--r ) 45 | goto_end(); 46 | return *this; 47 | } 48 | 49 | auto operator--( int ) -> cycling_range 50 | { 51 | cycling_range tmp{ *this }; 52 | --*this; 53 | return tmp; 54 | } 55 | 56 | void goto_end() 57 | { 58 | r.goto_end(); 59 | } 60 | 61 | explicit operator bool() const 62 | { 63 | return r || orig; 64 | } 65 | 66 | }; 67 | 68 | inline auto cycle() -> decltype( make_factory< cycling_range >() ) 69 | { 70 | return make_factory< cycling_range >(); 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/narl/diffing_range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "range_factory.h" 4 | 5 | #include 6 | 7 | 8 | namespace narl 9 | { 10 | 11 | template< typename range_type, typename other_range, typename comparer > 12 | class diffing_range 13 | { 14 | 15 | private: 16 | mutable range_type r; 17 | mutable other_range o; 18 | comparer cmp; 19 | 20 | static void skip_forward( range_type & r, other_range & o, comparer cmp ) 21 | { 22 | if( !r ) 23 | o.goto_end(); 24 | //if( r && o && !cmp( *r, *o ) ) 25 | while( r && o && !cmp( *r, *o ) ) 26 | { 27 | if( !cmp( *o, *r ) ) 28 | ++r; 29 | if( r && !cmp( *r, *o ) ) 30 | ++o; 31 | } 32 | } 33 | 34 | static void skip_backward( range_type & r, other_range & o, comparer cmp ) 35 | { 36 | while( !r && o ) 37 | --o; 38 | while( r && o && !cmp( *o, *r ) ) 39 | { 40 | if( !cmp( *r, *o ) ) 41 | --r; 42 | if( r && !cmp( *o, *r ) ) 43 | --o; 44 | } 45 | } 46 | 47 | void( *skip )( range_type & r, other_range & o, comparer cmp ); 48 | 49 | 50 | public: 51 | diffing_range( range_type r, other_range o, comparer cmp ) 52 | : r{ r }, o{ o }, cmp( cmp ), skip{ skip_forward } 53 | { 54 | } 55 | 56 | 57 | auto operator*() const -> decltype( *r ) 58 | { 59 | skip( r, o, cmp ); 60 | return *r; 61 | } 62 | 63 | auto operator++() -> diffing_range & 64 | { 65 | skip = skip_forward; 66 | if( !r && !o ) 67 | { 68 | ++r; 69 | ++o; 70 | } 71 | else 72 | ++r; 73 | skip( r, o, cmp ); 74 | return *this; 75 | } 76 | 77 | auto operator++( int ) -> diffing_range 78 | { 79 | skip( r, o, cmp ); 80 | diffing_range tmp{ *this }; 81 | ++*this; 82 | return tmp; 83 | } 84 | 85 | auto operator--() -> diffing_range & 86 | { 87 | skip = skip_backward; 88 | if( !r && !o ) 89 | { 90 | --r; 91 | --o; 92 | } 93 | else 94 | --r; 95 | skip( r, o, cmp ); 96 | return *this; 97 | } 98 | 99 | auto operator--( int ) -> diffing_range 100 | { 101 | diffing_range tmp{ *this }; 102 | --*this; 103 | return tmp; 104 | } 105 | 106 | explicit operator bool() const 107 | { 108 | skip( r, o, cmp ); 109 | return !!r; 110 | } 111 | 112 | void goto_end() 113 | { 114 | r.goto_end(); 115 | o.goto_end(); 116 | } 117 | 118 | }; 119 | 120 | 121 | template< typename range_type, typename other_range > 122 | class diffing_range_default : public diffing_range< range_type, other_range, std::less< decltype( *std::declval< range_type >() ) > > 123 | { 124 | 125 | public: 126 | diffing_range_default( range_type r, other_range o ) 127 | : diffing_range< range_type, other_range, std::less< decltype( *r ) > >( r, o, std::less< decltype( *r ) >() ) 128 | { 129 | } 130 | 131 | }; 132 | 133 | 134 | template< typename range_type, typename comparer > 135 | auto except( range_type r, comparer cmp ) -> decltype( make_factory< diffing_range >( r, cmp ) ) 136 | { 137 | return make_factory< diffing_range >( r, cmp ); 138 | } 139 | 140 | template< typename range_type > 141 | auto except( range_type r ) 142 | -> decltype( make_factory< diffing_range_default >( r ) ) 143 | { 144 | return make_factory< diffing_range_default >( r ); 145 | } 146 | 147 | } 148 | -------------------------------------------------------------------------------- /src/narl/distinct_range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "range_factory.h" 4 | 5 | 6 | namespace narl 7 | { 8 | 9 | template< typename range_type, typename comparer > 10 | class distinct_range 11 | { 12 | 13 | private: 14 | range_type r; 15 | comparer cmp; 16 | 17 | 18 | public: 19 | distinct_range( range_type r, comparer cmp ) 20 | : r{ r }, cmp( cmp ) 21 | { 22 | } 23 | 24 | 25 | auto operator*() const -> decltype( *r ) 26 | { 27 | return *r; 28 | } 29 | 30 | auto operator++() -> distinct_range & 31 | { 32 | if( !r ) 33 | ++r; 34 | else 35 | { 36 | auto v = *r; 37 | while( ++r && cmp( v, *r ) ) 38 | ; 39 | } 40 | return *this; 41 | } 42 | 43 | auto operator++( int ) -> distinct_range 44 | { 45 | distinct_range tmp{ *this }; 46 | ++*this; 47 | return tmp; 48 | } 49 | 50 | auto operator--() -> distinct_range & 51 | { 52 | if( !r ) 53 | --r; 54 | else 55 | { 56 | auto v = *r; 57 | while( --r && cmp( *r, v ) ) 58 | ; 59 | } 60 | return *this; 61 | } 62 | 63 | auto operator--( int ) -> distinct_range 64 | { 65 | distinct_range tmp{ *this }; 66 | --*this; 67 | return tmp; 68 | } 69 | 70 | explicit operator bool() const 71 | { 72 | return !!r; 73 | } 74 | 75 | void goto_end() 76 | { 77 | r.goto_end(); 78 | } 79 | 80 | }; 81 | 82 | template< typename range_type > 83 | class distinct_range_default : public distinct_range< range_type, std::equal_to< decltype( *std::declval< range_type >() ) > > 84 | { 85 | 86 | public: 87 | distinct_range_default( range_type r ) 88 | : distinct_range< range_type, std::equal_to< decltype( *r ) > >( r, std::equal_to< decltype( *r ) >() ) 89 | { 90 | } 91 | 92 | }; 93 | 94 | 95 | template< typename comparer > 96 | auto distinct( comparer cmp ) -> decltype( make_factory< distinct_range >( cmp ) ) 97 | { 98 | return make_factory< distinct_range >( cmp ); 99 | } 100 | 101 | auto inline distinct() -> decltype( make_factory< distinct_range_default >() ) 102 | { 103 | return make_factory< distinct_range_default >(); 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /src/narl/filtering_range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "range_factory.h" 4 | 5 | 6 | namespace narl 7 | { 8 | 9 | template< typename range_type, typename predicate > 10 | class filtering_range 11 | { 12 | 13 | private: 14 | mutable range_type r; 15 | predicate filter; 16 | 17 | void find_next_match() const 18 | { 19 | while( r && !filter( *r ) ) 20 | ++r; 21 | } 22 | 23 | void find_prev_match() const 24 | { 25 | while( r && !filter( *r ) ) 26 | --r; 27 | } 28 | 29 | public: 30 | filtering_range( range_type r, predicate filter ) 31 | : r{ r }, filter( filter ) 32 | { 33 | } 34 | 35 | 36 | auto operator*() const -> decltype( *r ) 37 | { 38 | find_next_match(); 39 | return *r; 40 | } 41 | 42 | auto operator++() -> filtering_range & 43 | { 44 | ++r; 45 | find_next_match(); 46 | return *this; 47 | } 48 | 49 | auto operator++( int ) -> filtering_range 50 | { 51 | find_next_match(); 52 | filtering_range tmp{ *this }; 53 | ++*this; 54 | return tmp; 55 | } 56 | 57 | auto operator--() -> filtering_range & 58 | { 59 | --r; 60 | find_prev_match(); 61 | return *this; 62 | } 63 | 64 | auto operator--( int ) -> filtering_range 65 | { 66 | find_prev_match(); 67 | filtering_range tmp{ *this }; 68 | --*this; 69 | return tmp; 70 | } 71 | 72 | void goto_end() 73 | { 74 | r.goto_end(); 75 | } 76 | 77 | explicit operator bool() const 78 | { 79 | find_next_match(); 80 | return !!r; 81 | } 82 | 83 | }; 84 | 85 | 86 | template< typename expression > 87 | auto where( expression expr ) -> decltype( make_factory< filtering_range >( expr ) ) 88 | { 89 | return make_factory< filtering_range >( expr ); 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/narl/grouping_range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "iterable_range.h" 4 | #include "range_factory.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | namespace narl 14 | { 15 | 16 | template< typename range_type, typename key_selector > 17 | class grouping_range 18 | { 19 | 20 | private: 21 | mutable range_type r; 22 | key_selector key; 23 | 24 | #ifndef _MSC_VER 25 | typedef decltype( key( *r ) ) key_type; 26 | typedef std::vector< decltype( *r ) > value_type; 27 | #else 28 | typedef typename std::result_of< key_selector( decltype( *std::declval< range_type >() ) ) >::type key_type; 29 | typedef std::vector< decltype( *std::declval< range_type >() ) > value_type; 30 | #endif 31 | 32 | mutable std::shared_ptr< std::map< key_type, value_type > > groups; 33 | mutable typename std::map< key_type, value_type >::const_iterator pos; 34 | bool before_begin; 35 | 36 | void buildgroups() const 37 | { 38 | if( ! groups ) 39 | { 40 | auto local = std::make_shared< std::map< key_type, value_type > >(); 41 | while( r ) 42 | { 43 | const auto & i = *r++; 44 | ( *local )[ key( i ) ].push_back( i ); 45 | } 46 | groups = local; 47 | pos = std::begin( *groups ); 48 | } 49 | } 50 | 51 | struct grouping 52 | { 53 | grouping( key_type key, iterable_range< typename value_type::const_iterator, typename value_type::value_type > values ) 54 | : key{ key }, values{ values } 55 | { } 56 | key_type key; 57 | iterable_range< typename value_type::const_iterator, typename value_type::value_type > values; 58 | }; 59 | 60 | 61 | public: 62 | grouping_range( range_type r, key_selector key ) 63 | : r{ r }, key( key ), before_begin{ false } 64 | { 65 | } 66 | 67 | grouping_range( const grouping_range & other ) 68 | : r{ other.r }, key( other.key ), groups{ other.groups }, pos{ other.pos }, before_begin{ other.before_begin } 69 | { 70 | } 71 | 72 | 73 | auto operator*() const -> grouping 74 | { 75 | buildgroups(); 76 | return grouping{ pos->first, from( pos->second ) }; 77 | } 78 | 79 | auto operator++() -> grouping_range & 80 | { 81 | buildgroups(); 82 | if( pos != std::end( *groups ) ) 83 | { 84 | ++pos; 85 | before_begin = before_begin ? false : before_begin; 86 | } 87 | return *this; 88 | } 89 | 90 | auto operator++( int ) -> grouping_range 91 | { 92 | buildgroups(); 93 | grouping_range tmp{ *this }; 94 | operator++(); 95 | return tmp; 96 | } 97 | 98 | auto operator--() -> grouping_range & 99 | { 100 | buildgroups(); 101 | if( ! before_begin ) 102 | { 103 | before_begin = pos == std::begin( *groups ); 104 | if( ! before_begin ) 105 | --pos; 106 | } 107 | return *this; 108 | } 109 | 110 | auto operator--( int ) -> grouping_range 111 | { 112 | buildgroups(); 113 | grouping_range tmp{ *this }; 114 | --*this; 115 | return tmp; 116 | } 117 | 118 | explicit operator bool() const 119 | { 120 | buildgroups(); 121 | return !before_begin && pos != std::end( *groups ); 122 | } 123 | 124 | void goto_end() 125 | { 126 | buildgroups(); 127 | pos = std::end( *groups ); 128 | } 129 | 130 | }; 131 | 132 | 133 | template< typename key_selector > 134 | auto groupby( key_selector key ) 135 | -> decltype( make_factory< grouping_range >( key ) ) 136 | { 137 | return make_factory< grouping_range >( key ); 138 | } 139 | 140 | } 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /src/narl/intersecting_range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "range_factory.h" 4 | 5 | 6 | namespace narl 7 | { 8 | 9 | template< typename range_type, typename other_range, typename comparer > 10 | class intersecting_range 11 | { 12 | 13 | private: 14 | mutable range_type r; 15 | mutable other_range o; 16 | comparer cmp; 17 | 18 | void find_next_match() const 19 | { 20 | while( r && o && !are_equal() ) 21 | { 22 | while( r && ( !o || cmp( *r, *o ) ) ) ++r; 23 | while( o && ( !r || cmp( *o, *r ) ) ) ++o; 24 | } 25 | } 26 | 27 | void find_prev_match() const 28 | { 29 | while( r && o && !are_equal() ) 30 | { 31 | while( o && ( !r || cmp( *r, *o ) ) ) --o; 32 | while( r && ( !o || cmp( *o, *r ) ) ) --r; 33 | } 34 | } 35 | 36 | bool are_equal() const 37 | { 38 | auto l = *r; 39 | auto r = *o; 40 | return !( cmp( l, r ) || cmp( r, l ) ); 41 | } 42 | 43 | 44 | public: 45 | intersecting_range( range_type r, other_range o, comparer cmp ) 46 | : r{ r }, o{ o }, cmp( cmp ) 47 | { 48 | } 49 | 50 | 51 | auto operator*() const -> decltype( *r ) 52 | { 53 | find_next_match(); 54 | return *r; 55 | } 56 | 57 | auto operator++() -> intersecting_range & 58 | { 59 | ++o; 60 | ++r; 61 | find_next_match(); 62 | return *this; 63 | } 64 | 65 | auto operator++( int ) -> intersecting_range 66 | { 67 | find_next_match(); 68 | intersecting_range tmp{ *this }; 69 | ++*this; 70 | return tmp; 71 | } 72 | 73 | auto operator--() -> intersecting_range & 74 | { 75 | --r; 76 | --o; 77 | find_prev_match(); 78 | return *this; 79 | } 80 | 81 | auto operator--( int ) -> intersecting_range 82 | { 83 | find_next_match(); 84 | intersecting_range tmp{ *this }; 85 | --*this; 86 | return tmp; 87 | } 88 | 89 | explicit operator bool() const 90 | { 91 | find_next_match(); 92 | return !!r && !!o; 93 | } 94 | 95 | void goto_end() 96 | { 97 | r.goto_end(); 98 | o.goto_end(); 99 | } 100 | 101 | }; 102 | 103 | template< typename range_type, typename other_range > 104 | class intersecting_range_default : public intersecting_range< range_type, other_range, std::less< decltype( *std::declval< range_type >() ) > > 105 | { 106 | 107 | public: 108 | intersecting_range_default( range_type r, other_range other ) 109 | : intersecting_range< range_type, other_range, std::less< decltype( *r ) > >( r, other, std::less< decltype( *r ) >() ) 110 | { 111 | } 112 | 113 | }; 114 | 115 | 116 | template< typename range_type, typename comparer > 117 | auto intersect_with( range_type r, comparer cmp ) 118 | -> decltype( make_factory< intersecting_range >( r, cmp ) ) 119 | { 120 | return make_factory< intersecting_range >( r, cmp ); 121 | } 122 | 123 | template< typename range_type > 124 | auto intersect_with( range_type r ) 125 | -> decltype( make_factory< intersecting_range_default >( r ) ) 126 | { 127 | return make_factory< intersecting_range_default >( r ); 128 | } 129 | 130 | } 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /src/narl/iterable_range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | namespace narl 11 | { 12 | 13 | template< typename iterator_type, typename value_type > 14 | class iterable_range 15 | { 16 | 17 | public: 18 | iterable_range( iterator_type startpos, iterator_type endpos ) 19 | : startpos{ startpos }, endpos{ endpos }, pos{ startpos }, before_begin{ false } 20 | { 21 | } 22 | 23 | 24 | auto operator*() const -> value_type 25 | { 26 | if( ! operator bool() ) 27 | throw std::out_of_range( "Attempt to access an invalid range object" ); 28 | return *pos; 29 | } 30 | 31 | auto operator++() -> iterable_range & 32 | { 33 | if( pos != endpos ) 34 | { 35 | if( before_begin ) 36 | before_begin = false; 37 | else 38 | ++pos; 39 | } 40 | return *this; 41 | } 42 | 43 | auto operator++( int ) -> iterable_range 44 | { 45 | iterable_range tmp{ *this }; 46 | ++*this; 47 | return tmp; 48 | } 49 | 50 | auto operator--() -> iterable_range & 51 | { 52 | if( !before_begin ) 53 | { 54 | if( pos == startpos ) 55 | before_begin = true; 56 | else 57 | --pos; 58 | } 59 | return *this; 60 | } 61 | 62 | auto operator--( int ) -> iterable_range 63 | { 64 | iterable_range tmp{ *this }; 65 | --*this; 66 | return tmp; 67 | } 68 | 69 | void goto_end() 70 | { 71 | pos = endpos; 72 | } 73 | 74 | explicit operator bool() const 75 | { 76 | return !before_begin && pos != endpos; 77 | } 78 | 79 | 80 | private: 81 | iterator_type startpos, endpos; 82 | iterator_type pos; 83 | bool before_begin; 84 | }; 85 | 86 | 87 | template< template< typename... > class container_type, typename value_type > 88 | class own_container_range 89 | { 90 | 91 | public: 92 | #ifndef _MSC_VER 93 | own_container_range( container_type< value_type > && src ) 94 | #else 95 | own_container_range( container_type< value_type, std::allocator< value_type > > && src ) 96 | #endif 97 | #ifndef _MSC_VER 98 | : src{ std::make_shared< container_type< value_type > >( std::move( src ) ) }, pos{ std::begin( *( this->src ) ) }, before_begin{ false } 99 | #else 100 | : src{ std::make_shared< container_type< value_type, std::allocator< value_type > > >( std::move( src ) ) }, pos{ std::begin( *( this->src ) ) }, before_begin{ false } 101 | #endif 102 | { 103 | } 104 | 105 | own_container_range( std::initializer_list< value_type > && src ) 106 | #ifndef _MSC_VER 107 | : src{ std::make_shared< container_type< value_type > >( std::move( src ) ) }, pos{ std::begin( *( this->src ) ) }, before_begin{ false } 108 | #else 109 | : src{ std::make_shared< container_type< value_type, std::allocator< value_type > > >( std::move( src ) ) }, pos{ std::begin( *( this->src ) ) }, before_begin{ false } 110 | #endif 111 | { 112 | } 113 | 114 | 115 | auto operator*() const -> value_type 116 | { 117 | if( ! operator bool() ) 118 | throw std::out_of_range( "Attempt to access an invalid range object" ); 119 | return *pos; 120 | } 121 | 122 | auto operator++() -> own_container_range & 123 | { 124 | if( pos != std::end( *src ) ) 125 | { 126 | if( before_begin ) 127 | before_begin = false; 128 | else 129 | ++pos; 130 | } 131 | return *this; 132 | } 133 | 134 | auto operator++( int ) -> own_container_range 135 | { 136 | own_container_range tmp{ *this }; 137 | ++*this; 138 | return tmp; 139 | } 140 | 141 | auto operator--() -> own_container_range & 142 | { 143 | if( !before_begin ) 144 | { 145 | if( pos == std::begin( *src ) ) 146 | before_begin = true; 147 | else 148 | --pos; 149 | } 150 | return *this; 151 | } 152 | 153 | auto operator--( int ) -> own_container_range 154 | { 155 | own_container_range tmp{ *this }; 156 | --*this; 157 | return tmp; 158 | } 159 | 160 | explicit operator bool() const 161 | { 162 | return !before_begin && pos != std::end( *src ); 163 | } 164 | 165 | void goto_end() 166 | { 167 | pos = std::end( *src ); 168 | } 169 | 170 | 171 | private: 172 | #ifndef _MSC_VER 173 | std::shared_ptr< container_type< value_type > > src; 174 | typename container_type< value_type >::const_iterator pos; 175 | #else 176 | std::shared_ptr< container_type< value_type, std::allocator< value_type > > > src; 177 | typename container_type< value_type, std::allocator< value_type > >::const_iterator pos; 178 | #endif 179 | bool before_begin; 180 | }; 181 | 182 | 183 | template< typename container > 184 | auto from( const container & src ) 185 | -> iterable_range< typename container::const_iterator, typename container::value_type > 186 | { 187 | return iterable_range< typename container::const_iterator, typename container::value_type > 188 | { std::begin( src ), std::end( src ) }; 189 | } 190 | 191 | template< template< typename... > class container, typename value_type > 192 | #ifndef _MSC_VER 193 | auto from( container< value_type > && c ) 194 | #else 195 | // template< template< typename, typename > class container, typename value_type > 196 | auto from( container< value_type, std::allocator< value_type > > && c ) 197 | #endif 198 | -> own_container_range< container, value_type > 199 | { 200 | return own_container_range< container, value_type > { std::move( c ) }; 201 | } 202 | 203 | template< typename value_type, size_t len > 204 | auto from( value_type( &array )[ len ] ) 205 | -> iterable_range< const value_type*, value_type > 206 | { 207 | return iterable_range< const value_type*, value_type > 208 | { array, array + len }; 209 | } 210 | 211 | template< typename item_type > 212 | auto from( const std::initializer_list< item_type > & src ) 213 | -> iterable_range< typename std::initializer_list< item_type >::const_iterator, item_type > 214 | { 215 | return iterable_range< typename std::initializer_list< item_type >::const_iterator, item_type > 216 | { std::begin( src ), std::end( src ) }; 217 | } 218 | 219 | template< typename item_type > 220 | auto from( std::initializer_list< item_type > && src ) 221 | -> own_container_range< std::vector, item_type > 222 | { 223 | return own_container_range< std::vector, item_type > 224 | { std::move( src ) }; 225 | } 226 | 227 | inline auto from( const char * const src ) 228 | -> iterable_range< const char * , char > 229 | { 230 | return iterable_range< const char * , char > 231 | { src, src + std::strlen( src ) }; 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /src/narl/joined_range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "range.h" 4 | #include "range_factory.h" 5 | 6 | 7 | namespace narl 8 | { 9 | 10 | template< typename inner_range, typename outer_range, typename inner_key_selector, typename outer_key_selector, typename transformation, typename key_comparer > 11 | class joined_range 12 | { 13 | 14 | private: 15 | mutable range< decltype( *std::declval< inner_range >() ) > r, old_r; 16 | mutable outer_range o; 17 | bool reset_r; 18 | inner_key_selector inner; 19 | outer_key_selector outer; 20 | transformation expr; 21 | key_comparer cmp; 22 | 23 | void find_next() const 24 | { 25 | while( r && o && !are_equal() ) 26 | { 27 | while( r && o && cmp( inner( *r ), outer( *o ) ) ) ++r; 28 | while( o && r && cmp( outer( *o ), inner( *r ) ) ) ++o; 29 | } 30 | } 31 | 32 | void find_prev_match() const 33 | { 34 | while( r && o && !( are_equal() ) ) 35 | { 36 | while( r && o && cmp( inner( *r ), outer( *o ) ) ) --o; 37 | while( r && o && cmp( outer( *o ), inner( *r ) ) ) --r; 38 | } 39 | } 40 | 41 | bool are_equal() const 42 | { 43 | auto left = inner( *r ); 44 | auto right = outer( *o ); 45 | return !( cmp( left, right ) || cmp( right, left ) ); 46 | } 47 | 48 | 49 | public: 50 | joined_range( inner_range r, outer_range o, inner_key_selector inner, outer_key_selector outer, transformation expr, key_comparer cmp ) 51 | : r{ r }, old_r{ r }, o{ o }, reset_r{ false }, inner( inner ), outer( outer ), expr( expr ), cmp( cmp ) 52 | { 53 | } 54 | 55 | 56 | auto operator*() const -> decltype( expr( *r, *o ) ) 57 | { 58 | find_next(); 59 | return expr( *r, *o ); 60 | } 61 | 62 | auto operator++() -> joined_range & 63 | { 64 | if( !r || !o ) 65 | { 66 | if( !r ) ++r; 67 | if( !o ) ++o; 68 | } 69 | else 70 | { 71 | auto tmp = r; 72 | if( o && r && ++tmp && !cmp( outer( *o ), inner( *tmp ) ) ) 73 | { 74 | old_r = r++; 75 | reset_r = true; 76 | } 77 | else 78 | { 79 | ++o; 80 | if( reset_r ) 81 | { 82 | r = old_r; 83 | reset_r = false; 84 | } 85 | } 86 | } 87 | find_next(); 88 | return *this; 89 | } 90 | 91 | auto operator++( int ) -> joined_range 92 | { 93 | find_next(); 94 | joined_range tmp{ *this }; 95 | ++*this; 96 | return tmp; 97 | } 98 | 99 | auto operator--() -> joined_range & 100 | { 101 | if( !r || !o ) 102 | { 103 | if( !r ) --r; 104 | if( !o ) --o; 105 | } 106 | else 107 | { 108 | auto tmp = r; 109 | if( o && r && --tmp && !cmp( inner( *tmp ), outer( *o ) ) ) 110 | { 111 | old_r = r--; 112 | reset_r = true; 113 | } 114 | else 115 | { 116 | --o; 117 | if( reset_r ) 118 | { 119 | r = old_r; 120 | reset_r = false; 121 | } 122 | } 123 | } 124 | find_prev_match(); 125 | return *this; 126 | } 127 | 128 | auto operator--( int ) -> joined_range 129 | { 130 | find_next(); 131 | joined_range tmp{ *this }; 132 | --*this; 133 | return tmp; 134 | } 135 | 136 | explicit operator bool() const 137 | { 138 | find_next(); 139 | return r && o; 140 | } 141 | 142 | void goto_end() 143 | { 144 | r.goto_end(); 145 | o.goto_end(); 146 | } 147 | 148 | }; 149 | 150 | struct join_cmp 151 | { 152 | template< typename left_type > 153 | bool operator()( const left_type & l, const left_type & r ) const 154 | { 155 | return l < r; 156 | } 157 | }; 158 | template< typename inner_range, typename outer_range, typename inner_key_selector, typename outer_key_selector, typename transformation > 159 | class joined_range_default : public joined_range< inner_range, outer_range, inner_key_selector, outer_key_selector, transformation, join_cmp > 160 | { 161 | 162 | public: 163 | joined_range_default( inner_range r, outer_range o, inner_key_selector inner, outer_key_selector outer, transformation t ) 164 | : joined_range< inner_range, outer_range, inner_key_selector, outer_key_selector, transformation, join_cmp >( r, o, inner, outer, t, join_cmp() ) 165 | { 166 | } 167 | 168 | }; 169 | 170 | template< typename outer_range, typename inner_key_selector, typename outer_key_selector, typename transformation > 171 | auto join( outer_range o, inner_key_selector inner, outer_key_selector outer, transformation t ) -> decltype( make_factory< joined_range_default >( o, inner, outer, t ) ) 172 | { 173 | return make_factory< joined_range_default >( o, inner, outer, t ); 174 | } 175 | 176 | } 177 | -------------------------------------------------------------------------------- /src/narl/merging_range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "range_factory.h" 4 | 5 | 6 | namespace narl 7 | { 8 | 9 | template< typename range_type, typename other_range_type, typename comparitor > 10 | class merging_range 11 | { 12 | 13 | private: 14 | range_type r; 15 | other_range_type o; 16 | comparitor cmp; 17 | 18 | 19 | public: 20 | merging_range( range_type r, other_range_type o, comparitor cmp ) 21 | : r{ r }, o{ o }, cmp( cmp ) 22 | { 23 | } 24 | 25 | 26 | auto operator*() const -> decltype( *r ) 27 | { 28 | if( r && o ) 29 | return cmp( *r, *o ) ? *r : *o; 30 | if( r ) return *r; 31 | return *o; 32 | } 33 | 34 | auto operator++() -> merging_range & 35 | { 36 | if( r && o ) 37 | { 38 | if( cmp( *r, *o ) ) 39 | ++r; 40 | else 41 | ++o; 42 | } 43 | else 44 | { 45 | ++r; 46 | ++o; 47 | } 48 | return *this; 49 | } 50 | 51 | auto operator++( int ) -> merging_range 52 | { 53 | merging_range tmp { *this }; 54 | ++*this; 55 | return tmp; 56 | } 57 | 58 | auto operator--() -> merging_range & 59 | { 60 | --r; 61 | --o; 62 | if( r && o ) 63 | { 64 | if( cmp( *r, *o ) ) 65 | ++r; 66 | else 67 | ++o; 68 | } 69 | return *this; 70 | } 71 | 72 | auto operator--( int ) -> merging_range 73 | { 74 | merging_range tmp { *this }; 75 | --*this; 76 | return tmp; 77 | } 78 | 79 | explicit operator bool() const 80 | { 81 | return !!r || !!o; 82 | } 83 | 84 | void goto_end() 85 | { 86 | r.goto_end(); 87 | o.goto_end(); 88 | } 89 | 90 | }; 91 | 92 | template< typename range_type, typename other_range_type > 93 | class merging_range_default : public merging_range< range_type, other_range_type, std::less< decltype( *std::declval< range_type >() ) > > 94 | { 95 | 96 | public: 97 | merging_range_default( range_type r, other_range_type o ) 98 | : merging_range< range_type, other_range_type, std::less< decltype( *r ) > >( r, o, std::less< decltype( *r ) >() ) 99 | { 100 | } 101 | 102 | }; 103 | 104 | 105 | template< typename other_range_type, typename comparitor > 106 | auto merge_with( other_range_type o, comparitor cmp ) -> decltype( make_factory< merging_range >( o, cmp ) ) 107 | { 108 | return make_factory< merging_range >( o, cmp ); 109 | } 110 | 111 | template< typename other_range_type > 112 | auto merge_with( other_range_type o ) -> decltype( make_factory< merging_range_default >( o ) ) 113 | { 114 | return make_factory< merging_range_default >( o ); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /src/narl/narl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "concatenating_range.h" 4 | #include "cycling_range.h" 5 | #include "diffing_range.h" 6 | #include "distinct_range.h" 7 | #include "filtering_range.h" 8 | #include "grouping_range.h" 9 | #include "intersecting_range.h" 10 | #include "iterable_range.h" 11 | #include "joined_range.h" 12 | #include "merging_range.h" 13 | #include "partial_range.h" 14 | #include "range.h" 15 | #include "range_accumulate.h" 16 | #include "range_factory.h" 17 | #include "range_input_iterator.h" 18 | #include "range_generator.h" 19 | #include "range_predicate.h" 20 | #include "range_tocontainer.h" 21 | #include "reversed_range.h" 22 | #include "selectmany_range.h" 23 | #include "sorted_range.h" 24 | #include "transforming_range.h" 25 | #include "unioning_range.h" 26 | #include "zipping_range.h" 27 | 28 | 29 | namespace narl 30 | { 31 | 32 | template< typename range_type, typename factory_type > 33 | auto operator|( range_type r, factory_type factory ) 34 | -> decltype( factory( r ) ) 35 | { 36 | return factory( r ); 37 | } 38 | 39 | 40 | template< typename range_type > 41 | auto operator|( range_type r, range_0_factory< range_validator > v ) -> bool 42 | { 43 | auto result = v( r ); 44 | return result.value(); 45 | } 46 | 47 | template< typename range_type, typename argument_type > 48 | auto operator|( range_type r, range_2_factory< range_predicate, argument_type > v ) -> bool 49 | { 50 | auto result = v( r ); 51 | return result.value(); 52 | } 53 | 54 | template< typename range_type, typename argument_type > 55 | auto operator|( range_type r, range_2_factory< range_predicate_inverter, argument_type > v ) -> bool 56 | { 57 | auto result = v( r ); 58 | return result.value(); 59 | } 60 | 61 | template< typename range_type, typename other_range_type > 62 | auto operator|( range_type r, range_2_factory< range_equality_default, other_range_type > v ) -> bool 63 | { 64 | auto result = v( r ); 65 | return result.value(); 66 | } 67 | 68 | 69 | #ifndef _MSC_VER 70 | 71 | template< typename range_type, typename other_range_type, typename comparitor > 72 | auto operator|( range_type r, range_N_factory< range_equality, other_range_type, comparitor > v ) -> bool 73 | { 74 | auto result = v( r ); 75 | return result.value(); 76 | } 77 | 78 | template< typename range_type, typename argument_type, typename accumulator > 79 | auto operator|( range_type r, range_N_factory< range_accumulate, argument_type, accumulator > v ) -> decltype( v( r ).value() ) 80 | { 81 | auto result = v( r ); 82 | return result.value(); 83 | } 84 | 85 | #else 86 | 87 | template< typename range_type, typename other_range_type, typename comparitor > 88 | auto operator|( range_type r, range_3_factory< range_equality, other_range_type, comparitor > v ) -> bool 89 | { 90 | auto result = v( r ); 91 | return result.value(); 92 | } 93 | 94 | template< typename range_type, typename argument_type, typename accumulator > 95 | auto operator|( range_type r, range_3_factory< range_accumulate, argument_type, accumulator > v ) -> decltype( v( r ).value() ) 96 | { 97 | auto result = v( r ); 98 | return result.value(); 99 | } 100 | 101 | #endif 102 | 103 | template< typename range_type, typename accumulator > 104 | auto operator|( range_type r, range_2_factory< range_default_accumulate, accumulator > v ) -> decltype( v( r ).value() ) 105 | { 106 | auto result = v( r ); 107 | return result.value(); 108 | } 109 | 110 | template< typename range_type > 111 | auto operator|( range_type r, range_0_factory< range_counter > v ) -> decltype( v( r ).value() ) 112 | { 113 | auto result = v( r ); 114 | return result.value(); 115 | } 116 | 117 | } 118 | 119 | 120 | -------------------------------------------------------------------------------- /src/narl/partial_range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "range_factory.h" 4 | 5 | 6 | namespace narl 7 | { 8 | 9 | template< typename range_type, typename limiting_type > 10 | class partial_range 11 | { 12 | 13 | private: 14 | mutable range_type r; 15 | mutable limiting_type limiter; 16 | 17 | 18 | public: 19 | partial_range( range_type r, limiting_type limiter ) 20 | : r{ r }, limiter{ limiter } 21 | { 22 | } 23 | 24 | 25 | auto operator*() const -> decltype( *r ) 26 | { 27 | limiter.skip( r ); 28 | return *r; 29 | } 30 | 31 | auto operator++() -> partial_range & 32 | { 33 | limiter.skip( r ); 34 | limiter.step( r ); 35 | return *this; 36 | } 37 | 38 | auto operator++( int ) -> partial_range 39 | { 40 | limiter.skip( r ); 41 | partial_range tmp{ *this }; 42 | ++*this; 43 | return tmp; 44 | } 45 | 46 | auto operator--() -> partial_range & 47 | { 48 | limiter.skip( r ); 49 | limiter.back( r ); 50 | return *this; 51 | } 52 | 53 | auto operator--( int ) -> partial_range 54 | { 55 | limiter.skip( r ); 56 | partial_range tmp{ *this }; 57 | --*this; 58 | return tmp; 59 | } 60 | 61 | void goto_end() 62 | { 63 | limiter.skip( r ); 64 | limiter.goto_end( r ); 65 | } 66 | 67 | explicit operator bool() const 68 | { 69 | limiter.skip( r ); 70 | return !!r && limiter.valid(); 71 | } 72 | 73 | }; 74 | 75 | 76 | class skipper 77 | { 78 | 79 | template< typename range_type, typename limiting_type > 80 | friend class partial_range; 81 | 82 | 83 | public: 84 | skipper( unsigned count ) 85 | : count{ count }, pos{ 1 } 86 | { } 87 | 88 | 89 | private: 90 | template< typename range_type > 91 | void skip( range_type & r ) 92 | { 93 | while( r && count > 0 ) 94 | { 95 | ++r; 96 | --count; 97 | } 98 | } 99 | 100 | template< typename range_type > 101 | void step( range_type & r ) 102 | { 103 | if( pos == 0 || r ) 104 | { 105 | ++r; 106 | ++pos; 107 | } 108 | } 109 | 110 | template< typename range_type > 111 | void back( range_type & r ) 112 | { 113 | if( pos > 0 ) 114 | { 115 | --r; 116 | --pos; 117 | } 118 | } 119 | 120 | auto valid() -> bool 121 | { 122 | return pos > 0; 123 | } 124 | 125 | template< typename range_type > 126 | void goto_end( range_type & r ) 127 | { 128 | while( r ) 129 | step( r ); 130 | } 131 | 132 | unsigned count; 133 | unsigned pos; 134 | 135 | }; 136 | 137 | class taker 138 | { 139 | 140 | template< typename range_type, typename limiting_type > 141 | friend class partial_range; 142 | 143 | 144 | public: 145 | taker( unsigned count ) 146 | : start{ count }, count{ count } 147 | { } 148 | 149 | 150 | private: 151 | template< typename range_type > 152 | void skip( const range_type & ) { } 153 | 154 | template< typename range_type > 155 | void step( range_type & r ) 156 | { 157 | if( count > start || ( count > 0 && r ) ) 158 | { 159 | --count; 160 | ++r; 161 | } 162 | } 163 | 164 | template< typename range_type > 165 | void back( range_type & r ) 166 | { 167 | if( count <= start && r ) 168 | { 169 | ++count; 170 | --r; 171 | } 172 | } 173 | 174 | auto valid() -> bool 175 | { 176 | return count <= start && count > 0; 177 | } 178 | 179 | template< typename range_type > 180 | void goto_end( range_type & r ) 181 | { 182 | while( valid() && r ) 183 | step( r ); 184 | } 185 | 186 | unsigned start; 187 | unsigned count; 188 | 189 | }; 190 | 191 | 192 | template< typename expression > 193 | class skipping_while 194 | { 195 | 196 | template< typename range_type, typename limiting_type > 197 | friend class partial_range; 198 | 199 | 200 | public: 201 | skipping_while( expression expr ) 202 | : skipped{ false }, expr( expr ), pos{ 1 } 203 | { } 204 | 205 | 206 | private: 207 | template< typename range_type > 208 | void skip( range_type & r ) 209 | { 210 | while( !skipped && r && expr( *r ) ) 211 | ++r; 212 | skipped = true; 213 | } 214 | 215 | template< typename range_type > 216 | void step( range_type & r ) 217 | { 218 | if( r ) 219 | { 220 | ++r; 221 | ++pos; 222 | } 223 | } 224 | 225 | template< typename range_type > 226 | void back( range_type & r ) 227 | { 228 | if( pos > 0 ) 229 | { 230 | --r; 231 | --pos; 232 | } 233 | } 234 | 235 | auto valid() -> bool 236 | { 237 | return pos > 0; 238 | } 239 | 240 | template< typename range_type > 241 | void goto_end( range_type & r ) 242 | { 243 | while( r ) 244 | step( r ); 245 | } 246 | 247 | bool skipped; 248 | expression expr; 249 | unsigned pos; 250 | 251 | }; 252 | 253 | template< typename expression > 254 | auto make_skipping_while( expression expr ) -> skipping_while< expression > 255 | { 256 | return skipping_while< expression >{ expr }; 257 | } 258 | 259 | 260 | template< typename expression > 261 | class taking_while 262 | { 263 | 264 | template< typename range_type, typename limiting_type > 265 | friend class partial_range; 266 | 267 | 268 | public: 269 | taking_while( expression expr ) 270 | : expr( expr ), stopped{ false }, pos{ 1 } 271 | { } 272 | 273 | 274 | private: 275 | template< typename range_type > 276 | bool check( range_type r ) 277 | { 278 | if( !stopped && r && !expr( *r ) ) 279 | stopped = true; 280 | return !stopped; 281 | } 282 | 283 | template< typename range_type > 284 | void skip( range_type r ) 285 | { 286 | check( r ); 287 | } 288 | 289 | template< typename range_type > 290 | void step( range_type & r ) 291 | { 292 | if( pos == 0 || check( r ) ) 293 | { 294 | ++r; 295 | ++pos; 296 | } 297 | } 298 | 299 | template< typename range_type > 300 | void back( range_type & r ) 301 | { 302 | if( pos > 0 && r ) 303 | { 304 | --r; 305 | --pos; 306 | stopped = stopped ? false : stopped; 307 | } 308 | } 309 | 310 | auto valid() -> bool 311 | { 312 | return !stopped && pos > 0; 313 | } 314 | 315 | template< typename range_type > 316 | void goto_end( range_type & r ) 317 | { 318 | while( pos == 0 || check( r ) ) 319 | step( r ); 320 | } 321 | 322 | expression expr; 323 | bool stopped; 324 | unsigned pos; 325 | 326 | }; 327 | 328 | template< typename expression > 329 | auto make_taking_while( expression expr ) -> taking_while< expression > 330 | { 331 | return taking_while< expression >{ expr }; 332 | } 333 | 334 | 335 | inline auto skip( unsigned count ) -> decltype( make_factory< partial_range >( skipper( count ) ) ) 336 | { 337 | return make_factory< partial_range >( skipper( count ) ); 338 | } 339 | 340 | inline auto take( unsigned count ) -> decltype( make_factory< partial_range >( taker( count ) ) ) 341 | { 342 | return make_factory< partial_range >( taker( count ) ); 343 | } 344 | 345 | 346 | template< typename expression > 347 | auto skip_while( expression expr ) -> decltype( make_factory< partial_range >( make_skipping_while( expr ) ) ) 348 | { 349 | return make_factory< partial_range >( make_skipping_while( expr ) ); 350 | } 351 | 352 | template< typename expression > 353 | auto take_while( expression expr ) -> decltype( make_factory< partial_range >( make_taking_while( expr ) ) ) 354 | { 355 | return make_factory< partial_range >( make_taking_while( expr ) ); 356 | } 357 | 358 | } 359 | -------------------------------------------------------------------------------- /src/narl/range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | namespace narl 7 | { 8 | 9 | template< typename value_type > 10 | class range 11 | { 12 | 13 | public: 14 | range() 15 | { 16 | } 17 | 18 | range( const range & other ) 19 | : r{ other.r ? other.r->clone() : nullptr } 20 | { 21 | } 22 | 23 | range( range && other ) 24 | : r{ std::move( other.r ) } 25 | { 26 | } 27 | 28 | template< typename range_type > 29 | range( const range_type & other ) 30 | : r{ std::unique_ptr< range_wrapper< range_type > >{ new range_wrapper< range_type >{ other } } } 31 | { 32 | } 33 | 34 | template< typename range_type > 35 | auto operator=( const range_type & other ) -> range & 36 | { 37 | range tmp{ other }; 38 | tmp.r.swap( r ); 39 | return *this; 40 | } 41 | 42 | auto operator=( range && other ) -> range & 43 | { 44 | r = std::move( other.r ); 45 | return *this; 46 | } 47 | 48 | auto operator=( const range & other ) -> range & 49 | { 50 | range tmp { other }; 51 | tmp.r.swap( r ); 52 | return *this; 53 | } 54 | 55 | 56 | auto operator*() const -> value_type 57 | { 58 | return r->current(); 59 | } 60 | 61 | auto operator++() -> range & 62 | { 63 | r->next(); 64 | return *this; 65 | } 66 | 67 | auto operator++( int ) -> range 68 | { 69 | range tmp{ *this }; 70 | ++*this; 71 | return tmp; 72 | } 73 | 74 | auto operator--() -> range & 75 | { 76 | r->previous(); 77 | return *this; 78 | } 79 | 80 | auto operator--( int ) -> range 81 | { 82 | range tmp{ *this }; 83 | --*this; 84 | return tmp; 85 | } 86 | 87 | explicit operator bool() const 88 | { 89 | return r && r->valid(); 90 | } 91 | 92 | void goto_end() 93 | { 94 | r->goto_end(); 95 | } 96 | 97 | 98 | private: 99 | 100 | class range_adapter 101 | { 102 | public: 103 | virtual std::unique_ptr< range_adapter > clone() const = 0; 104 | virtual value_type current() const = 0; 105 | virtual void next() = 0; 106 | virtual void previous() = 0; 107 | virtual bool valid() const = 0; 108 | virtual void goto_end() = 0; 109 | }; 110 | 111 | template< typename range_type > 112 | class range_wrapper : public range_adapter 113 | { 114 | public: 115 | range_wrapper( range_type r ) 116 | : r{ r } 117 | { 118 | } 119 | 120 | virtual std::unique_ptr< range_adapter > clone() const override 121 | { 122 | return std::unique_ptr< range_adapter >{ new range_wrapper< range_type >( r ) }; 123 | } 124 | 125 | virtual value_type current() const 126 | { 127 | return *r; 128 | } 129 | virtual void next() 130 | { 131 | ++r; 132 | } 133 | virtual void previous() 134 | { 135 | --r; 136 | } 137 | virtual bool valid() const 138 | { 139 | return !!r; 140 | } 141 | virtual void goto_end() 142 | { 143 | r.goto_end(); 144 | } 145 | 146 | range_type r; 147 | }; 148 | 149 | std::unique_ptr< range_adapter > r; 150 | 151 | }; 152 | 153 | } 154 | -------------------------------------------------------------------------------- /src/narl/range_accumulate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "range_factory.h" 4 | 5 | #include 6 | 7 | 8 | namespace narl 9 | { 10 | 11 | template< typename range_type, typename seed, typename accumulator > 12 | class range_accumulate 13 | { 14 | 15 | private: 16 | mutable range_type r; 17 | seed initial; 18 | accumulator a; 19 | 20 | 21 | public: 22 | range_accumulate( range_type r, seed initial, accumulator a ) 23 | : r{ r }, initial{ initial }, a( a ) 24 | { 25 | } 26 | 27 | 28 | auto value() const -> decltype( a( initial, *r ) ) 29 | { 30 | if( ! r ) 31 | throw std::invalid_argument( "Cannot accumulate over an empty range" ); 32 | 33 | auto current = a( initial, *r++ ); 34 | while( r ) 35 | current = a( current, *r++ ); 36 | return current; 37 | } 38 | 39 | }; 40 | 41 | template< typename range_type, typename accumulator > 42 | class range_default_accumulate 43 | { 44 | 45 | private: 46 | mutable range_type r; 47 | accumulator a; 48 | 49 | 50 | public: 51 | range_default_accumulate( range_type r, accumulator a ) 52 | : r{ r }, a( a ) 53 | { 54 | } 55 | 56 | 57 | auto value() const -> decltype( a( *r, *r ) ) 58 | { 59 | if( !r ) 60 | throw std::invalid_argument( "Cannot accumulate over an empty range" ); 61 | 62 | auto current = *r++; 63 | while( r ) 64 | current = a( current, *r++ ); 65 | return current; 66 | } 67 | 68 | }; 69 | 70 | 71 | template< typename range_type > 72 | class range_counter 73 | { 74 | 75 | private: 76 | mutable range_type r; 77 | 78 | 79 | public: 80 | range_counter( range_type r ) 81 | : r{ r } 82 | { 83 | } 84 | 85 | 86 | auto value() const -> unsigned 87 | { 88 | unsigned c = 0; 89 | if( r ) 90 | while( r++ ) 91 | ++c; 92 | return c; 93 | } 94 | 95 | }; 96 | 97 | 98 | template< typename seed, typename accumulator > 99 | auto aggregate( seed initial, accumulator expr ) -> decltype( make_factory< range_accumulate >( initial, expr ) ) 100 | { 101 | return make_factory< range_accumulate >( initial, expr ); 102 | } 103 | 104 | template< typename accumulator > 105 | auto aggregate( accumulator expr ) -> decltype( make_factory< range_default_accumulate >( expr ) ) 106 | { 107 | return make_factory< range_default_accumulate >( expr ); 108 | } 109 | 110 | inline auto count() -> decltype( make_factory< range_counter >() ) 111 | { 112 | return make_factory< range_counter >(); 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /src/narl/range_factory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | namespace narl 5 | { 6 | 7 | template< template< typename > class range_type > 8 | class range_0_factory 9 | { 10 | 11 | public: 12 | template< typename range_of > 13 | auto operator()( range_of r ) const -> range_type< range_of > 14 | { 15 | return range_type< range_of >{ r }; 16 | } 17 | 18 | }; 19 | 20 | template< template< typename > class range_type, typename argument_type > 21 | class range_1_factory 22 | { 23 | 24 | public: 25 | range_1_factory( argument_type expr ) 26 | : expr{ expr } 27 | { 28 | } 29 | 30 | template< typename range_of > 31 | auto operator()( range_of r ) const -> range_type< range_of > 32 | { 33 | return range_type< range_of >{ r, expr }; 34 | } 35 | 36 | 37 | private: 38 | argument_type expr; 39 | 40 | }; 41 | 42 | template< template< typename, typename > class range_type, typename argument_type > 43 | class range_2_factory 44 | { 45 | 46 | public: 47 | range_2_factory( const argument_type & arg ) 48 | : arg( arg ) 49 | { 50 | } 51 | 52 | 53 | template< typename range_of > 54 | auto operator()( const range_of & r ) const -> range_type< range_of, argument_type > 55 | { 56 | return range_type< range_of, argument_type >{ r, arg }; 57 | } 58 | 59 | 60 | private: 61 | argument_type arg; 62 | 63 | }; 64 | 65 | template< template< typename... > class range_type, typename... others > 66 | class range_N_factory; 67 | 68 | template< template< typename... > class range_type, typename argument_type > 69 | class range_N_factory< range_type, argument_type > 70 | { 71 | 72 | public: 73 | range_N_factory( argument_type arg ) 74 | : arg( arg ) 75 | { 76 | } 77 | 78 | 79 | template< typename range_of, typename... others > 80 | auto build( range_of r, others... rest ) const -> range_type< range_of, others..., argument_type > 81 | { 82 | return range_type< range_of, others..., argument_type >{ r, rest..., arg }; 83 | } 84 | 85 | template< typename range_of > 86 | auto operator()( range_of r ) const -> decltype( this->build( r ) ) 87 | { 88 | return build( r ); 89 | } 90 | 91 | 92 | private: 93 | argument_type arg; 94 | 95 | }; 96 | 97 | template< template< typename... > class range_type, typename next_type, typename... others > 98 | class range_N_factory< range_type, next_type, others... > : public range_N_factory< range_type, others... > 99 | { 100 | typedef range_N_factory< range_type, others... > base; 101 | 102 | private: 103 | next_type next; 104 | 105 | public: 106 | range_N_factory( next_type next, others... rest ) 107 | : base{ rest... }, next( next ) 108 | { 109 | } 110 | 111 | 112 | template< typename range_of > 113 | auto operator()( range_of r ) const -> decltype( this->base::build( r, next ) ) 114 | { 115 | return base::build( r, next ); 116 | } 117 | 118 | template< typename range_of, typename... tail > 119 | auto build( range_of r, tail... rest ) const -> decltype( this->base::build( r, rest..., next ) ) 120 | { 121 | return base::build( r, rest..., next ); 122 | } 123 | 124 | }; 125 | 126 | 127 | template< template< typename > class range_type > 128 | auto make_factory() 129 | -> range_0_factory< range_type > 130 | { 131 | return range_0_factory< range_type >{ }; 132 | } 133 | 134 | template< template< typename > class range_type, typename argument_type > 135 | auto make_factory( argument_type expr ) 136 | -> range_1_factory< range_type, argument_type > 137 | { 138 | return range_1_factory< range_type, argument_type >{ expr }; 139 | } 140 | 141 | template< template< typename, typename > class range_type, typename argument_type > 142 | auto make_factory( argument_type arg ) 143 | -> range_2_factory< range_type, argument_type > 144 | { 145 | return range_2_factory< range_type, argument_type >{ arg }; 146 | } 147 | 148 | #ifndef _MSC_VER 149 | 150 | template< template< typename... > class range_type, typename next_type, typename... argument_type > 151 | auto make_factory( next_type arg, argument_type... expr ) 152 | -> range_N_factory< range_type, next_type, argument_type... > 153 | { 154 | return range_N_factory< range_type, next_type, argument_type... >{ arg, expr... }; 155 | } 156 | 157 | #else 158 | 159 | template< template< typename, typename, typename > class range_type, typename other_range_type, typename argument_type > 160 | class range_3_factory 161 | { 162 | 163 | public: 164 | range_3_factory( other_range_type o, argument_type arg ) 165 | : o( o ), arg( arg ) 166 | { 167 | } 168 | 169 | 170 | template< typename range_of > 171 | auto operator()( range_of r ) const -> range_type< range_of, other_range_type, argument_type > 172 | { 173 | return range_type< range_of, other_range_type, argument_type >{ r, o, arg }; 174 | } 175 | 176 | 177 | private: 178 | other_range_type o; 179 | argument_type arg; 180 | 181 | }; 182 | 183 | template< template< typename, typename, typename > class range_type, typename other_range_type, typename argument_type > 184 | auto make_factory( other_range_type o, argument_type arg ) 185 | -> range_3_factory< range_type, other_range_type, argument_type > 186 | { 187 | return range_3_factory< range_type, other_range_type, argument_type >{ o, arg }; 188 | } 189 | 190 | template< template< typename, typename, typename, typename, typename > class range_type, typename other_range_type, typename arg1_t, typename arg2_t, typename arg3_t > 191 | class range_5_factory 192 | { 193 | 194 | public: 195 | range_5_factory( other_range_type o, arg1_t arg1, arg2_t arg2, arg3_t arg3 ) 196 | : o( o ), arg1( arg1 ), arg2( arg2 ), arg3( arg3 ) 197 | { 198 | } 199 | 200 | 201 | template< typename range_of > 202 | auto operator()( range_of r ) const -> range_type< range_of, other_range_type, arg1_t, arg2_t, arg3_t > 203 | { 204 | return range_type< range_of, other_range_type, arg1_t, arg2_t, arg3_t >{ r, o, arg1, arg2, arg3 }; 205 | } 206 | 207 | 208 | private: 209 | other_range_type o; 210 | arg1_t arg1; 211 | arg2_t arg2; 212 | arg3_t arg3; 213 | 214 | }; 215 | 216 | template< template< typename, typename, typename, typename, typename > class range_type, typename other_range_type, typename arg1_t, typename arg2_t, typename arg3_t > 217 | auto make_factory( other_range_type o, arg1_t arg1, arg2_t arg2, arg3_t arg3 ) 218 | -> range_5_factory< range_type, other_range_type, arg1_t, arg2_t, arg3_t > 219 | { 220 | return range_5_factory< range_type, other_range_type, arg1_t, arg2_t, arg3_t >{ o, arg1, arg2, arg3 }; 221 | } 222 | 223 | #endif 224 | 225 | } 226 | -------------------------------------------------------------------------------- /src/narl/range_generator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | namespace narl 5 | { 6 | 7 | template< typename item_type > 8 | class range_generator 9 | { 10 | 11 | private: 12 | item_type v; 13 | 14 | 15 | public: 16 | range_generator() 17 | : v{ item_type{} } 18 | { 19 | } 20 | 21 | range_generator( const item_type & v ) 22 | : v{ v } 23 | { 24 | } 25 | 26 | 27 | auto operator *() const -> item_type 28 | { 29 | return v; 30 | } 31 | 32 | auto operator++() -> range_generator & 33 | { 34 | ++v; 35 | return *this; 36 | } 37 | 38 | auto operator++( int ) -> range_generator 39 | { 40 | range_generator tmp{ *this }; 41 | ++*this; 42 | return tmp; 43 | } 44 | 45 | explicit operator bool() const 46 | { 47 | return true; 48 | } 49 | 50 | }; 51 | 52 | 53 | template< typename item_type, typename callback > 54 | class range_generator_callback 55 | { 56 | 57 | private: 58 | item_type v; 59 | callback fn; 60 | 61 | public: 62 | range_generator_callback( const item_type & init, callback fn ) 63 | : v{ init }, fn( fn ) 64 | { 65 | } 66 | 67 | 68 | auto operator *() const -> item_type 69 | { 70 | return v; 71 | } 72 | 73 | auto operator++() -> range_generator_callback & 74 | { 75 | v = fn( v ); 76 | return *this; 77 | } 78 | 79 | auto operator++( int ) -> range_generator_callback 80 | { 81 | range_generator_callback tmp{ *this }; 82 | ++*this; 83 | return tmp; 84 | } 85 | 86 | explicit operator bool() const 87 | { 88 | return true; 89 | } 90 | 91 | }; 92 | 93 | struct identity 94 | { 95 | template< typename T > 96 | const T & operator()( const T & t ) { return t; } 97 | }; 98 | 99 | template< typename item_type > 100 | class range_generator_callback_default : public range_generator_callback< item_type, identity > 101 | { 102 | 103 | public: 104 | range_generator_callback_default( const item_type & i ) 105 | : range_generator_callback< item_type, identity >( i, identity() ) 106 | { 107 | } 108 | 109 | }; 110 | 111 | template< typename item_type > 112 | auto make_range() -> range_generator< item_type > 113 | { 114 | return range_generator< item_type >{ }; 115 | } 116 | 117 | template< typename item_type > 118 | auto make_range( const item_type & init ) -> range_generator< item_type > 119 | { 120 | return range_generator< item_type >{ init }; 121 | } 122 | 123 | template< typename item_type > 124 | auto fill_range( const item_type & init ) -> range_generator_callback_default< item_type > 125 | { 126 | return range_generator_callback_default< item_type >{ init }; 127 | } 128 | 129 | template< typename item_type, typename callback > 130 | auto make_range( const item_type & init, callback fn ) -> range_generator_callback< item_type, callback > 131 | { 132 | return range_generator_callback< item_type, callback >{ init, fn }; 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /src/narl/range_input_iterator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include 5 | 6 | 7 | namespace narl 8 | { 9 | 10 | template< typename range_type, typename value_type > 11 | class range_input_iterator : public std::iterator< std::input_iterator_tag, value_type > 12 | { 13 | 14 | public: 15 | range_input_iterator( range_type r ) 16 | : r{ r } 17 | { 18 | } 19 | 20 | 21 | auto operator!=( range_input_iterator r ) const -> bool 22 | { 23 | return !operator==( r ); 24 | } 25 | 26 | auto operator==( range_input_iterator ) const -> bool 27 | { 28 | return !r; 29 | } 30 | 31 | auto operator++() -> range_input_iterator & 32 | { 33 | ++r; 34 | return *this; 35 | } 36 | 37 | auto operator*() const -> value_type 38 | { 39 | return *r; 40 | } 41 | 42 | 43 | private: 44 | range_type r; 45 | 46 | }; 47 | 48 | 49 | template< typename range_type > 50 | auto begin( range_type r ) -> range_input_iterator< range_type, decltype( *r ) > 51 | { 52 | return range_input_iterator< range_type, decltype( *r ) >{ r }; 53 | } 54 | 55 | template< typename range_type > 56 | auto end( range_type r ) -> range_input_iterator< range_type, decltype( *r ) > 57 | { 58 | return range_input_iterator< range_type, decltype( *r ) >{ r }; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/narl/range_predicate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "filtering_range.h" 4 | #include "iterable_range.h" 5 | #include "range_factory.h" 6 | 7 | #include 8 | #include 9 | 10 | 11 | namespace narl 12 | { 13 | 14 | template< typename range_type, typename expression > 15 | class range_predicate 16 | { 17 | 18 | public: 19 | range_predicate( range_type r, expression expr ) 20 | : r{ filtering_range< range_type, expression >{ r, expr } } 21 | { 22 | } 23 | 24 | 25 | auto value() const -> bool 26 | { 27 | return !!r; 28 | } 29 | 30 | 31 | private: 32 | filtering_range< range_type, expression > r; 33 | 34 | }; 35 | 36 | 37 | template< typename range_type, typename other_range_type, typename comparitor > 38 | class range_equality 39 | { 40 | 41 | public: 42 | range_equality( range_type r, other_range_type o, comparitor cmp ) 43 | : r{ r }, o{ o }, cmp( cmp ) 44 | { 45 | } 46 | 47 | 48 | auto value() const -> bool 49 | { 50 | while( r && o && cmp( *r, *o ) ) 51 | { 52 | ++r; 53 | ++o; 54 | } 55 | return !r && !o; 56 | } 57 | 58 | 59 | private: 60 | mutable range_type r; 61 | mutable other_range_type o; 62 | comparitor cmp; 63 | 64 | }; 65 | 66 | 67 | template< typename range_type, typename other_range_type > 68 | class range_equality_default : public range_equality< range_type, other_range_type, std::equal_to< decltype( *std::declval< range_type >() ) > > 69 | { 70 | 71 | public: 72 | range_equality_default( range_type r, other_range_type o ) 73 | : range_equality< range_type, other_range_type, std::equal_to< decltype( *r ) > >( r, o, std::equal_to< decltype( *r ) >() ) 74 | { 75 | } 76 | 77 | }; 78 | 79 | 80 | template< typename range_type > 81 | class range_validator 82 | { 83 | 84 | public: 85 | range_validator( range_type r ) 86 | : r{ r } 87 | { 88 | } 89 | 90 | 91 | auto value() const -> bool 92 | { 93 | return !!r; 94 | } 95 | 96 | 97 | private: 98 | range_type r; 99 | 100 | }; 101 | 102 | 103 | template< typename range_type, typename expression > 104 | class range_predicate_inverter 105 | { 106 | 107 | public: 108 | range_predicate_inverter( range_type r, expression expr ) 109 | : r{ filtering_range< range_type, negate >{ r, negate( r, expr ) } } 110 | { 111 | } 112 | 113 | 114 | auto value() const -> bool 115 | { 116 | return !r; 117 | } 118 | 119 | 120 | private: 121 | struct negate 122 | { 123 | range_type lr; 124 | expression expr; 125 | negate( range_type lr, expression expr ) 126 | : lr{ lr }, expr( expr ) 127 | { } 128 | bool operator()( const decltype( *std::declval< range_type >() ) & v ) const 129 | { return !expr( v ); } 130 | }; 131 | 132 | filtering_range< range_type, negate > r; 133 | 134 | }; 135 | 136 | 137 | inline auto any() -> decltype( make_factory< range_validator >() ) 138 | { 139 | return make_factory< range_validator >(); 140 | } 141 | 142 | template< typename expression > 143 | auto any( expression expr ) -> decltype( make_factory< range_predicate >( expr ) ) 144 | { 145 | return make_factory< range_predicate >( expr ); 146 | } 147 | 148 | template< typename other_range_type, typename comparitor > 149 | auto sequence_equal( other_range_type o, comparitor cmp ) 150 | -> decltype( make_factory< range_equality >( o, cmp ) ) 151 | { 152 | return make_factory< range_equality >( o, cmp ); 153 | } 154 | 155 | template< typename other_range_type > 156 | auto sequence_equal( other_range_type o ) 157 | -> decltype( make_factory< range_equality_default >( o ) ) 158 | { 159 | return make_factory< range_equality_default >( o ); 160 | } 161 | 162 | template< typename expression > 163 | auto all( expression expr ) -> decltype( make_factory< range_predicate_inverter >( expr ) ) 164 | { 165 | return make_factory< range_predicate_inverter >( expr ); 166 | } 167 | 168 | } 169 | -------------------------------------------------------------------------------- /src/narl/range_tocontainer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "range_factory.h" 4 | #include "range_input_iterator.h" 5 | 6 | 7 | namespace narl 8 | { 9 | 10 | template< template< typename... > class container_type > 11 | class to_container 12 | { 13 | 14 | public: 15 | 16 | template< typename range_type > 17 | auto operator()( range_type r ) const 18 | #ifndef _MSC_VER 19 | -> container_type< decltype( *r ) > 20 | #else 21 | -> container_type< decltype( *r ), std::allocator< decltype( *r ) > > 22 | #endif 23 | { 24 | #ifndef _MSC_VER 25 | return container_type< decltype( *r ) > { begin( r ), end( r ) }; 26 | #else 27 | return container_type< decltype( *r ), std::allocator< decltype( *r ) > > { begin( r ), end( r ) }; 28 | #endif 29 | } 30 | 31 | }; 32 | 33 | 34 | template< template< typename... > class container > 35 | auto to() -> decltype( to_container< container >() ) 36 | { 37 | return to_container< container >(); 38 | } 39 | 40 | } 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/narl/reversed_range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "range_factory.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | namespace narl 11 | { 12 | 13 | template< typename range_type > 14 | class reversed_range; 15 | 16 | template<> 17 | class range_0_factory< reversed_range > 18 | { 19 | 20 | public: 21 | 22 | template< typename other_range_type > 23 | auto operator()( other_range_type r ) const -> reversed_range< other_range_type > 24 | { 25 | return reversed_range< other_range_type >{ r }; 26 | } 27 | 28 | template< typename other_range_type > 29 | auto operator()( reversed_range< other_range_type > r ) const -> other_range_type 30 | { 31 | return r.r; 32 | } 33 | }; 34 | 35 | 36 | template< typename range_type > 37 | class reversed_range 38 | { 39 | 40 | friend class range_0_factory< ::narl::reversed_range >; 41 | 42 | private: 43 | range_type r; 44 | mutable range_type retro; 45 | mutable bool reversed; 46 | 47 | void do_reverse() const 48 | { 49 | if( ! reversed ) 50 | { 51 | retro.goto_end(); 52 | --retro; 53 | reversed = true; 54 | } 55 | } 56 | 57 | 58 | public: 59 | reversed_range( range_type r ) 60 | : r{ r }, retro{ r }, reversed{ false } 61 | { 62 | } 63 | 64 | auto operator*() const -> decltype( *r ) 65 | { 66 | do_reverse(); 67 | return *retro; 68 | } 69 | 70 | auto operator++() -> reversed_range & 71 | { 72 | do_reverse(); 73 | --retro; 74 | return *this; 75 | } 76 | 77 | auto operator++( int ) -> reversed_range 78 | { 79 | do_reverse(); 80 | reversed_range tmp{ *this }; 81 | ++*this; 82 | return tmp; 83 | } 84 | 85 | auto operator--() -> reversed_range & 86 | { 87 | do_reverse(); 88 | ++retro; 89 | return *this; 90 | } 91 | 92 | auto operator--( int ) -> reversed_range 93 | { 94 | reversed_range tmp{ *this }; 95 | do_reverse(); 96 | --*this; 97 | return tmp; 98 | } 99 | 100 | explicit operator bool() const 101 | { 102 | do_reverse(); 103 | return !!retro; 104 | } 105 | 106 | void goto_end() 107 | { 108 | r.goto_end(); 109 | } 110 | 111 | }; 112 | 113 | 114 | inline auto reverse() -> decltype( make_factory< reversed_range >() ) 115 | { 116 | return make_factory< reversed_range >(); 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /src/narl/selectmany_range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "range.h" 4 | #include "range_factory.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | namespace narl 12 | { 13 | 14 | template< typename range_type, typename binder > 15 | class selectmany_range 16 | { 17 | 18 | private: 19 | mutable range_type r; 20 | binder expr; 21 | 22 | #ifndef _MSC_VER 23 | mutable range< decltype( *expr( *r ) ) > buffer; 24 | mutable decltype( *r ) current; 25 | #else 26 | typedef decltype( *std::declval< range_type >() ) param_type; 27 | typedef typename std::result_of< binder( param_type ) >::type result_type; 28 | mutable range< decltype( *std::declval< result_type >() ) > buffer; 29 | mutable param_type current; 30 | #endif 31 | 32 | void extract() const 33 | { 34 | if( r ) 35 | { 36 | if( !buffer ) 37 | { 38 | current = *r; 39 | buffer = expr( current ); 40 | } 41 | } 42 | else 43 | buffer = range< decltype( *expr( *r ) ) >{}; 44 | } 45 | 46 | 47 | public: 48 | selectmany_range( range_type r, binder expr ) 49 | : r{ r }, expr( expr ) 50 | { 51 | } 52 | 53 | 54 | auto operator*() const -> decltype( *buffer ) 55 | { 56 | extract(); 57 | return *buffer; 58 | } 59 | 60 | auto operator++() -> selectmany_range & 61 | { 62 | if( !r || ( buffer && !++buffer ) ) 63 | { 64 | ++r; 65 | extract(); 66 | } 67 | return *this; 68 | } 69 | 70 | auto operator++( int ) -> selectmany_range 71 | { 72 | extract(); 73 | selectmany_range tmp{ *this }; 74 | ++*this; 75 | return tmp; 76 | } 77 | 78 | auto operator--() -> selectmany_range & 79 | { 80 | if( !buffer || !--buffer ) 81 | { 82 | --r; 83 | extract(); 84 | if( buffer ) 85 | { 86 | buffer.goto_end(); 87 | --buffer; 88 | } 89 | } 90 | return *this; 91 | } 92 | 93 | auto operator--( int ) -> selectmany_range 94 | { 95 | extract(); 96 | selectmany_range tmp{ *this }; 97 | --*this; 98 | return tmp; 99 | } 100 | 101 | explicit operator bool() const 102 | { 103 | extract(); 104 | return r && buffer; 105 | } 106 | 107 | void goto_end() 108 | { 109 | r.goto_end(); 110 | } 111 | 112 | }; 113 | 114 | template< typename binder > 115 | auto selectmany( binder b ) -> decltype( make_factory< selectmany_range >( b ) ) 116 | { 117 | return make_factory< selectmany_range >( b ); 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /src/narl/sorted_range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "range_factory.h" 4 | #include "range_input_iterator.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace narl 12 | { 13 | 14 | template< typename range_type, typename ordering > 15 | class sorted_range 16 | { 17 | 18 | private: 19 | bool before_begin; 20 | range_type r; 21 | ordering cmp; 22 | #ifndef _MSC_VER 23 | mutable std::shared_ptr< std::list< decltype( *r ) > > buffer; 24 | mutable typename std::list< decltype( *r ) >::const_iterator pos; 25 | #else 26 | mutable std::shared_ptr< std::list< decltype( *std::declval< range_type >() ) > > buffer; 27 | mutable typename std::list< decltype( *std::declval< range_type >() ) >::const_iterator pos; 28 | #endif 29 | 30 | void buildsort() const 31 | { 32 | if( !buffer ) 33 | { 34 | buffer = std::make_shared< std::list< decltype( *r ) > >( begin( r ), end( r ) ); 35 | buffer->sort( [&]( const decltype( *r ) & left, const decltype( *r ) & right ) 36 | { return cmp( left, right ); } ); 37 | pos = std::begin( *buffer ); 38 | } 39 | } 40 | 41 | 42 | public: 43 | sorted_range( range_type r, ordering cmp ) 44 | : before_begin{ false }, r{ r }, cmp( cmp ) 45 | { 46 | } 47 | 48 | sorted_range( const sorted_range & other ) 49 | : before_begin{ other.before_begin }, r{ other.r }, cmp( other.cmp ), buffer{ other.buffer }, pos{ other.pos } 50 | { 51 | } 52 | 53 | 54 | auto operator*() const -> decltype( *r ) 55 | { 56 | buildsort(); 57 | return *pos; 58 | } 59 | 60 | auto operator++() -> sorted_range & 61 | { 62 | buildsort(); 63 | if( pos != std::end( *buffer ) ) 64 | { 65 | if( before_begin ) 66 | before_begin = false; 67 | else 68 | ++pos; 69 | } 70 | return *this; 71 | } 72 | 73 | auto operator++( int ) -> sorted_range 74 | { 75 | buildsort(); 76 | sorted_range tmp{ *this }; 77 | ++*this; 78 | return tmp; 79 | } 80 | 81 | auto operator--() -> sorted_range & 82 | { 83 | buildsort(); 84 | if( !before_begin ) 85 | { 86 | if( pos == std::begin( *buffer ) ) 87 | before_begin = true; 88 | else 89 | --pos; 90 | } 91 | return *this; 92 | } 93 | 94 | auto operator--( int ) -> sorted_range 95 | { 96 | buildsort(); 97 | sorted_range tmp{ *this }; 98 | --*this; 99 | return tmp; 100 | } 101 | 102 | explicit operator bool() const 103 | { 104 | buildsort(); 105 | return !before_begin && pos != std::end( *buffer ); 106 | } 107 | 108 | void goto_end() 109 | { 110 | buildsort(); 111 | pos = std::end( *buffer ); 112 | } 113 | 114 | }; 115 | 116 | 117 | template< typename range_type > 118 | class sorted_range_default 119 | : public sorted_range< range_type, std::less< decltype( *std::declval< range_type >() ) > > 120 | { 121 | 122 | public: 123 | sorted_range_default( range_type r ) 124 | : sorted_range< range_type, std::less< decltype( *std::declval< range_type >() ) > >( r, std::less< decltype( *r ) >() ) 125 | { 126 | } 127 | 128 | }; 129 | 130 | 131 | template< typename ordering > 132 | auto sorted( ordering cmp ) -> decltype( make_factory< sorted_range >( cmp ) ) 133 | { 134 | return make_factory< sorted_range >( cmp ); 135 | } 136 | 137 | inline auto sorted() -> decltype( make_factory< sorted_range_default >() ) 138 | { 139 | return make_factory< sorted_range_default >(); 140 | } 141 | 142 | } 143 | -------------------------------------------------------------------------------- /src/narl/transforming_range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "range_factory.h" 4 | 5 | 6 | namespace narl 7 | { 8 | 9 | template< typename range_type, typename transformation > 10 | class transforming_range 11 | { 12 | 13 | private: 14 | range_type r; 15 | transformation expr; 16 | 17 | 18 | public: 19 | transforming_range( range_type r, transformation expr ) 20 | : r{ r }, expr( expr ) 21 | { 22 | } 23 | 24 | 25 | auto operator*() const -> decltype( expr( *r ) ) 26 | { 27 | return expr( *r ); 28 | } 29 | 30 | auto operator++() -> transforming_range & 31 | { 32 | ++r; 33 | return *this; 34 | } 35 | 36 | auto operator++( int ) -> transforming_range 37 | { 38 | transforming_range tmp{ *this }; 39 | ++*this; 40 | return tmp; 41 | } 42 | 43 | auto operator--() -> transforming_range & 44 | { 45 | --r; 46 | return *this; 47 | } 48 | 49 | auto operator--( int ) -> transforming_range 50 | { 51 | transforming_range tmp{ *this }; 52 | --*this; 53 | return tmp; 54 | } 55 | 56 | explicit operator bool() const 57 | { 58 | return !!r; 59 | } 60 | 61 | void goto_end() 62 | { 63 | r.goto_end(); 64 | } 65 | 66 | }; 67 | 68 | 69 | template< typename expression > 70 | auto select( expression expr ) -> decltype( make_factory< transforming_range >( expr ) ) 71 | { 72 | return make_factory< transforming_range >( expr ); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/narl/unioning_range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "range_factory.h" 4 | 5 | #include 6 | 7 | 8 | namespace narl 9 | { 10 | 11 | template< typename range_type, typename other_range, typename comparer > 12 | class unioning_range 13 | { 14 | 15 | private: 16 | mutable range_type r; 17 | mutable other_range o; 18 | comparer cmp; 19 | 20 | 21 | public: 22 | unioning_range( range_type r, other_range o, comparer cmp ) 23 | : r{ r }, o{ o }, cmp( cmp ) 24 | { 25 | } 26 | 27 | 28 | auto operator*() const -> decltype( *r ) 29 | { 30 | if( r && o ) 31 | return cmp( *r, *o ) ? *r : *o; 32 | if( r ) return *r; 33 | return *o; 34 | } 35 | 36 | auto operator++() -> unioning_range & 37 | { 38 | if( r && o ) 39 | { 40 | if( !cmp( *o, *r ) ) 41 | { 42 | if( !cmp( *r++, *o ) ) 43 | ++o; 44 | } 45 | else 46 | ++o; 47 | } 48 | else 49 | { 50 | ++r; 51 | ++o; 52 | } 53 | return *this; 54 | } 55 | 56 | auto operator++( int ) -> unioning_range 57 | { 58 | unioning_range tmp{ *this }; 59 | ++*this; 60 | return tmp; 61 | } 62 | 63 | auto operator--() -> unioning_range & 64 | { 65 | --r; 66 | --o; 67 | if( r && o ) 68 | { 69 | if( cmp( *r, *o ) ) 70 | ++r; 71 | else if( cmp( *o, *r ) ) 72 | ++o; 73 | } 74 | return *this; 75 | } 76 | 77 | auto operator--( int ) -> unioning_range 78 | { 79 | unioning_range tmp{ *this }; 80 | --*this; 81 | return tmp; 82 | } 83 | 84 | explicit operator bool() const 85 | { 86 | return r || o; 87 | } 88 | 89 | void goto_end() 90 | { 91 | r.goto_end(); 92 | o.goto_end(); 93 | } 94 | 95 | }; 96 | 97 | template< typename range_type, typename other_range > 98 | class unioning_range_default : public unioning_range< range_type, other_range, std::less< decltype( *std::declval< range_type >() ) > > 99 | { 100 | 101 | public: 102 | unioning_range_default( range_type r, other_range o ) 103 | : unioning_range< range_type, other_range, std::less< decltype( *r ) > >( r, o, std::less< decltype( *r ) >() ) 104 | { 105 | } 106 | }; 107 | 108 | 109 | template< typename range_type, typename comparer > 110 | auto union_with( range_type r, comparer cmp ) 111 | -> decltype( make_factory< unioning_range >( r, cmp ) ) 112 | { 113 | return make_factory< unioning_range >( r, cmp ); 114 | } 115 | 116 | template< typename range_type > 117 | auto union_with( range_type r ) 118 | -> decltype( make_factory< unioning_range_default >( r ) ) 119 | { 120 | return make_factory< unioning_range_default >( r ); 121 | } 122 | 123 | } 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /src/narl/zipping_range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef _MSC_VER 4 | 5 | #include "zipping_range_variadic.h" 6 | 7 | #else 8 | 9 | #include "zipping_range_non_variadic.h" 10 | 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /src/narl/zipping_range_non_variadic.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "range_factory.h" 4 | 5 | #include 6 | 7 | 8 | namespace narl 9 | { 10 | 11 | template< typename range_type, typename other_range_type > 12 | class zipping_range 13 | { 14 | 15 | private: 16 | range_type r; 17 | other_range_type other; 18 | 19 | 20 | public: 21 | zipping_range( range_type r, other_range_type other ) 22 | : r{ r }, other{ other } 23 | { 24 | } 25 | 26 | 27 | auto operator*() const -> decltype( std::make_tuple( *r, *other ) ) 28 | { 29 | return std::make_tuple( *r, *other ); 30 | } 31 | 32 | auto operator++() -> zipping_range & 33 | { 34 | ++r; 35 | ++other; 36 | return *this; 37 | } 38 | 39 | auto operator++( int ) -> zipping_range 40 | { 41 | zipping_range tmp{ *this }; 42 | ++*this; 43 | return tmp; 44 | } 45 | 46 | auto operator--() -> zipping_range & 47 | { 48 | --r; 49 | --other; 50 | return *this; 51 | } 52 | 53 | auto operator--( int ) -> zipping_range 54 | { 55 | zipping_range tmp{ *this }; 56 | --*this; 57 | return tmp; 58 | } 59 | 60 | explicit operator bool() const 61 | { 62 | return !!r && !!other; 63 | } 64 | 65 | void goto_end() 66 | { 67 | r.goto_end(); 68 | other.goto_end(); 69 | } 70 | 71 | }; 72 | 73 | 74 | template< typename range_type > 75 | auto zipwith( range_type r ) -> decltype( make_factory< zipping_range >( r ) ) 76 | { 77 | return make_factory< zipping_range >( r ); 78 | } 79 | 80 | } 81 | 82 | 83 | -------------------------------------------------------------------------------- /src/narl/zipping_range_variadic.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "range_factory.h" 4 | 5 | #include 6 | 7 | 8 | namespace narl 9 | { 10 | 11 | template< typename... ranges > 12 | class zipping_range; 13 | 14 | template< typename range_type, typename other_range_type > 15 | class zipping_range< range_type, other_range_type > 16 | { 17 | 18 | private: 19 | range_type r; 20 | other_range_type other; 21 | 22 | 23 | public: 24 | zipping_range( range_type r, other_range_type other ) 25 | : r{ r }, other{ other } 26 | { 27 | } 28 | 29 | 30 | auto operator*() const -> decltype( std::make_tuple( *r, *other ) ) 31 | { 32 | return std::make_tuple( *r, *other ); 33 | } 34 | 35 | auto operator++() -> zipping_range & 36 | { 37 | ++r; 38 | ++other; 39 | return *this; 40 | } 41 | 42 | auto operator++( int ) -> zipping_range 43 | { 44 | zipping_range tmp{ *this }; 45 | ++*this; 46 | return tmp; 47 | } 48 | 49 | auto operator--() -> zipping_range & 50 | { 51 | --r; 52 | --other; 53 | return *this; 54 | } 55 | 56 | auto operator--( int ) -> zipping_range 57 | { 58 | zipping_range tmp{ *this }; 59 | --*this; 60 | return tmp; 61 | } 62 | 63 | explicit operator bool() const 64 | { 65 | return !!r && !!other; 66 | } 67 | 68 | void goto_end() 69 | { 70 | r.goto_end(); 71 | other.goto_end(); 72 | } 73 | 74 | }; 75 | 76 | template< typename range_type, typename... others > 77 | class zipping_range< range_type, others... > : public zipping_range< others... > 78 | { 79 | 80 | typedef zipping_range< others... > base; 81 | 82 | private: 83 | range_type r; 84 | bool before_begin; 85 | 86 | 87 | public: 88 | zipping_range( range_type r, others... rest ) 89 | : base{ rest... }, r{ r }, before_begin{ false } 90 | { 91 | } 92 | 93 | 94 | auto operator*() const -> decltype( std::tuple_cat( std::make_tuple( *r ), std::declval< base >().operator*() ) ) 95 | { 96 | return std::tuple_cat( std::make_tuple( *r ), base::operator*() ); 97 | } 98 | 99 | auto operator++() -> zipping_range & 100 | { 101 | if( before_begin || operator bool() ) 102 | { 103 | ++r; 104 | base::operator++(); 105 | before_begin = before_begin ? false : before_begin; 106 | } 107 | return *this; 108 | } 109 | 110 | auto operator++( int ) -> zipping_range 111 | { 112 | zipping_range tmp{ *this }; 113 | ++*this; 114 | return tmp; 115 | } 116 | 117 | auto operator--() -> zipping_range & 118 | { 119 | if( !before_begin ) 120 | { 121 | --r; 122 | base::operator--(); 123 | before_begin = !operator bool(); 124 | } 125 | return *this; 126 | } 127 | 128 | auto operator--( int ) -> zipping_range 129 | { 130 | zipping_range tmp{ *this }; 131 | --*this; 132 | return tmp; 133 | } 134 | 135 | explicit operator bool() const 136 | { 137 | return r && base::operator bool(); 138 | } 139 | 140 | void goto_end() 141 | { 142 | r.goto_end(); 143 | base::goto_end(); 144 | } 145 | 146 | }; 147 | 148 | 149 | template< typename... range_type > 150 | auto zipwith( range_type... r ) -> decltype( make_factory< zipping_range >( r... ) ) 151 | { 152 | return make_factory< zipping_range >( r... ); 153 | } 154 | 155 | } 156 | 157 | 158 | -------------------------------------------------------------------------------- /src/narl_speed.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | {29CF8510-5FC9-413D-995E-249E9E83B1A9} 29 | Win32Proj 30 | 31 | 32 | 33 | Application 34 | true 35 | v120 36 | 37 | 38 | Application 39 | true 40 | v120 41 | 42 | 43 | Application 44 | false 45 | v120 46 | 47 | 48 | Application 49 | false 50 | v120 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | true 70 | $(IncludePath) 71 | $(SolutionDir)$(ProjectName)$(Platform)\$(Configuration)\ 72 | $(SolutionDir)$(ProjectName)$(Platform)\$(Configuration)\ 73 | 74 | 75 | true 76 | $(IncludePath) 77 | $(LibraryPath) 78 | $(SolutionDir)$(ProjectName)$(Platform)\$(Configuration)\ 79 | $(SolutionDir)$(ProjectName)$(Platform)\$(Configuration)\ 80 | 81 | 82 | true 83 | $(IncludePath) 84 | $(WindowsSDK_LibraryPath_x86);$(LibraryPath) 85 | $(SolutionDir)$(ProjectName)$(Platform)\$(Configuration)\ 86 | $(SolutionDir)$(ProjectName)$(Platform)\$(Configuration)\ 87 | 88 | 89 | true 90 | $(IncludePath) 91 | $(LibraryPath) 92 | $(SolutionDir)$(ProjectName)$(Platform)\$(Configuration)\ 93 | $(SolutionDir)$(ProjectName)$(Platform)\$(Configuration)\ 94 | 95 | 96 | 97 | _DEBUG;_CONSOLE;_ITERATOR_DEBUG_LEVEL=0;%(PreprocessorDefinitions) 98 | MultiThreadedDebugDLL 99 | Level4 100 | ProgramDatabase 101 | Disabled 102 | ..\externals\catch\single_include;narl;D:\work\dev\lib\boost_1_55_0 103 | true 104 | 105 | 106 | MachineX86 107 | true 108 | Console 109 | 110 | 111 | 112 | 113 | WIN32;_DEBUG;_CONSOLE;_ITERATOR_DEBUG_LEVEL=0;%(PreprocessorDefinitions) 114 | MultiThreadedDebugDLL 115 | Level4 116 | ProgramDatabase 117 | Disabled 118 | ..\externals\catch\single_include;narl;D:\work\dev\lib\boost_1_55_0 119 | true 120 | 121 | 122 | true 123 | Console 124 | 125 | 126 | 127 | 128 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 129 | MultiThreadedDLL 130 | Level4 131 | ProgramDatabase 132 | ..\externals\catch\single_include;narl;D:\work\dev\lib\boost_1_55_0 133 | Full 134 | 135 | 136 | MachineX86 137 | true 138 | Console 139 | true 140 | true 141 | 142 | 143 | 144 | 145 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 146 | MultiThreadedDLL 147 | Level4 148 | ProgramDatabase 149 | ..\externals\catch\single_include;narl;D:\work\dev\lib\boost_1_55_0 150 | Full 151 | 152 | 153 | true 154 | Console 155 | true 156 | true 157 | 158 | 159 | 160 | 161 | 162 | -------------------------------------------------------------------------------- /src/narl_speed.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav 15 | 16 | 17 | {3cc62be8-4862-42f5-a622-296306092398} 18 | 19 | 20 | 21 | 22 | Source Files 23 | 24 | 25 | 26 | 27 | Header Files 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/tests/perf/narl_speed.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define CATCH_CONFIG_MAIN 4 | #include 5 | 6 | #ifndef _MSC_VER 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace boost::adaptors; 16 | #endif 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | using namespace narl; 26 | 27 | 28 | template< typename fn > 29 | auto time_avg( fn f, size_t tries ) -> std::tuple< size_t, std::chrono::microseconds > 30 | { 31 | double result; 32 | 33 | std::chrono::microseconds cumulation { 0 }; 34 | for( auto i : narl::make_range< size_t >() | narl::take( tries ) ) 35 | { 36 | auto start = std::chrono::high_resolution_clock::now(); 37 | result = f(); 38 | auto end = std::chrono::high_resolution_clock::now(); 39 | auto res = std::chrono::duration_cast< std::chrono::milliseconds >( end - start ); 40 | 41 | cumulation = ( cumulation * i + res ) / ( i + 1 ); 42 | } 43 | 44 | return std::make_tuple( result, cumulation ); 45 | } 46 | 47 | 48 | TEST_CASE( "Select where", "" ) 49 | { 50 | const int N = 10000000; 51 | const size_t tries = 3; 52 | 53 | auto items = make_range< int >() | select( []( int i ) { return i % 4 > 0 ? i * 2.3 : i * -3.2; } ) | take( N ); 54 | auto l = items | to< std::vector >(); 55 | 56 | auto stlres = time_avg( [&] 57 | { 58 | std::vector< double > out; 59 | std::transform( begin( l ), 60 | std::partition( begin( l ), end( l ), []( double d ) { return d < 0.0; } ), 61 | std::inserter( out, out.begin() ), []( double d ) { return d * 0.175; } ); 62 | return std::accumulate( out.begin(), out.end(), 0.0 ); 63 | }, tries ); 64 | auto stlnum = std::get< 0 >( stlres ); 65 | auto stltime = std::get< 1 >( stlres ).count() / 1000.0; 66 | INFO( "STL : " << std::setw( 7 ) << std::fixed << std::setprecision( 2 ) << stltime << "ms" ); 67 | 68 | #ifndef _MSC_VER 69 | auto boostres = time_avg( [&] 70 | { 71 | std::vector< double > out; 72 | return boost::accumulate( l 73 | | filtered( []( double d ) { return d < 0.0; } ) 74 | | transformed( []( double d ) { return d * 0.175; } ), 75 | 0.0 ); 76 | }, tries ); 77 | auto boostnum = std::get< 0 >( boostres ); 78 | auto boosttime = std::get< 1 >( boostres ).count() / 1000.0; 79 | INFO( "BOOST : " << std::setw( 7 ) << std::fixed << std::setprecision( 2 ) << boosttime << "ms" ); 80 | #else 81 | auto boostnum = stlnum; 82 | INFO( "BOOST : " << std::setw( 7 ) << "xxx" ); 83 | #endif 84 | 85 | auto narlres = time_avg( [&] 86 | { 87 | return from( l ) //items 88 | | where( []( double d ) { return d < 0.0; } ) 89 | | select( []( double d ) { return d * 0.175; } ) 90 | | aggregate( []( double l, double r ) { return l + r; } ); 91 | }, tries ); 92 | auto narlnum = std::get< 0 >( narlres ); 93 | auto narltime = std::get< 1 >( narlres ).count() / 1000.0; 94 | 95 | INFO( "NARL : " << std::setw( 7 ) << std::fixed << std::setprecision( 2 ) << narltime << "ms" ); 96 | 97 | REQUIRE( ( narlnum == stlnum && narlnum == boostnum ) ); 98 | } 99 | 100 | -------------------------------------------------------------------------------- /src/tests/perf/selectwhere.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace testnarl 4 | { 5 | 6 | 7 | } -------------------------------------------------------------------------------- /src/tests/perf/selectwhere.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | namespace select_where 5 | { 6 | 7 | template< typename range, typename filter, typename xform > 8 | size_t range_test( range r, filter f, xform x ) 9 | { 10 | return r | where( f ) | select( x ) | count(); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/tests/testnarl/test_concatenating_range.cpp: -------------------------------------------------------------------------------- 1 | #include "testnarl.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | 9 | using namespace narl; 10 | 11 | 12 | TEST_CASE( "Concatenating range is lazy evaluated", "[narl][concat][lazy]" ) 13 | { 14 | auto r = make_test_range< concatenating_range >( throwing_range< int >(), from( { 3, 4 } ) ); 15 | 16 | REQUIRE_THROWS_AS( *r, range_access_exception ); 17 | REQUIRE_THROWS_AS( ++r, range_access_exception ); 18 | REQUIRE_THROWS_AS( --r, range_access_exception ); 19 | REQUIRE_THROWS_AS( r++, range_access_exception ); 20 | REQUIRE_THROWS_AS( r--, range_access_exception ); 21 | REQUIRE_THROWS_AS( r && r, range_access_exception ); 22 | } 23 | 24 | 25 | TEST_CASE( "Concatenating range produces elements from r before l", "[narl][concat][lthenr]" ) 26 | { 27 | auto r = make_test_range< concatenating_range >( from( { 1, 2 } ), from( { 3, 4 } ) ); 28 | 29 | REQUIRE( *r++ == 1 ); 30 | REQUIRE( *r++ == 2 ); 31 | REQUIRE( *r++ == 3 ); 32 | REQUIRE( *r++ == 4 ); 33 | REQUIRE( !r ); 34 | } 35 | 36 | 37 | TEST_CASE( "Concatenating range can be moved to the end and decremented", "[narl][concat][gotoend]" ) 38 | { 39 | auto r = make_test_range< concatenating_range >( from( { 1, 2 } ), from( { 3, 4 } ) ); 40 | r.goto_end(); 41 | 42 | REQUIRE( !r ); 43 | --r; 44 | REQUIRE( !!r ); 45 | REQUIRE( *r == 4 ); 46 | } 47 | 48 | 49 | TEST_CASE( "Concatenating range can be post decremented to yield each element", "[narl][concat][postdecrement]" ) 50 | { 51 | auto r = make_test_range< concatenating_range >( from( { 1, 2 } ), from( { 3, 4 } ) ); 52 | r.goto_end(); 53 | --r; 54 | 55 | REQUIRE( *r-- == 4 ); 56 | REQUIRE( *r-- == 3 ); 57 | REQUIRE( *r-- == 2 ); 58 | REQUIRE( *r-- == 1 ); 59 | REQUIRE( !r ); 60 | } 61 | 62 | 63 | TEST_CASE( "Concatenating range can be incremented from before begin", "[narl][concat][beforebegin]" ) 64 | { 65 | auto r = make_test_range< concatenating_range >( from( { 1, 2 } ), from( { 3, 4 } ) ); 66 | --r; 67 | REQUIRE( !r ); 68 | ++r; 69 | REQUIRE( !!r ); 70 | REQUIRE( *r++ == 1 ); 71 | REQUIRE( *r++ == 2 ); 72 | REQUIRE( *r++ == 3 ); 73 | REQUIRE( *r++ == 4 ); 74 | REQUIRE( !r ); 75 | } 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /src/tests/testnarl/test_cycling_range.cpp: -------------------------------------------------------------------------------- 1 | #include "testnarl.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | 10 | using namespace narl; 11 | 12 | 13 | TEST_CASE( "Cycling range with taker is evaluated lazily", "[narl][cycling_range][deferred]" ) 14 | { 15 | auto r = make_test_range< cycling_range >( throwing_range< int >{} ); 16 | 17 | REQUIRE_THROWS_AS( ++r, range_access_exception ); 18 | REQUIRE_THROWS_AS( r++, range_access_exception ); 19 | REQUIRE_THROWS_AS( *r, range_access_exception ); 20 | REQUIRE_THROWS_AS( r && true, range_access_exception ); 21 | } 22 | 23 | 24 | TEST_CASE( "Cycling range restarts input range at the beginning", "[narl][cycling_range][cycle]" ) 25 | { 26 | auto r = make_test_range< cycling_range >( from( { 1, 2 } ) ); 27 | 28 | REQUIRE( *r++ == 1 ); 29 | REQUIRE( *r++ == 2 ); 30 | REQUIRE_FALSE( !r ); 31 | REQUIRE( *r++ == 1 ); 32 | REQUIRE( *r++ == 2 ); 33 | } 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/tests/testnarl/test_distinct_range.cpp: -------------------------------------------------------------------------------- 1 | #include "testnarl.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | 9 | using namespace narl; 10 | 11 | 12 | TEST_CASE( "Distinct range is lazy evaluated", "[narl][distinct][lazy]" ) 13 | { 14 | auto r = make_test_range< distinct_range_default >( throwing_range< int >() ); 15 | 16 | REQUIRE_THROWS_AS( *r, range_access_exception ); 17 | REQUIRE_THROWS_AS( ++r, range_access_exception ); 18 | REQUIRE_THROWS_AS( --r, range_access_exception ); 19 | REQUIRE_THROWS_AS( r++, range_access_exception ); 20 | REQUIRE_THROWS_AS( r--, range_access_exception ); 21 | REQUIRE_THROWS_AS( r && true, range_access_exception ); 22 | } 23 | 24 | 25 | TEST_CASE( "Distinct range returns item if its the only one", "[narl][distinct][only]" ) 26 | { 27 | auto r = make_test_range< distinct_range_default >( from( { 1 } ) ); 28 | REQUIRE( *r++ == 1 ); 29 | REQUIRE( !r ); 30 | } 31 | 32 | 33 | TEST_CASE( "Distinct range skips duplicates from start", "[narl][distinct][duplicates][start]" ) 34 | { 35 | auto r = make_test_range< distinct_range_default >( from( { 1, 1, 2, 3 } ) ); 36 | REQUIRE( !!r ); 37 | REQUIRE( *r++ == 1 ); 38 | REQUIRE( *r++ == 2 ); 39 | REQUIRE( *r++ == 3 ); 40 | REQUIRE( !r ); 41 | } 42 | 43 | 44 | TEST_CASE( "Distinct range skips duplicates at end", "[narl][distinct][duplicates][end]" ) 45 | { 46 | auto r = make_test_range< distinct_range_default >( from( { 1, 2, 3, 3 } ) ); 47 | REQUIRE( !!r ); 48 | REQUIRE( *r++ == 1 ); 49 | REQUIRE( *r++ == 2 ); 50 | REQUIRE( *r++ == 3 ); 51 | REQUIRE( !r ); 52 | } 53 | 54 | 55 | TEST_CASE( "Distinct range skips duplicates in middle", "[narl][distinct][duplicates][middle]" ) 56 | { 57 | auto r = make_test_range< distinct_range_default >( from( { 1, 2, 2, 3 } ) ); 58 | REQUIRE( !!r ); 59 | REQUIRE( *r++ == 1 ); 60 | REQUIRE( *r++ == 2 ); 61 | REQUIRE( *r++ == 3 ); 62 | REQUIRE( !r ); 63 | } 64 | 65 | 66 | TEST_CASE( "Distinct range skips all duplicates", "[narl][distinct][duplicates][all]" ) 67 | { 68 | auto r = make_test_range< distinct_range_default >( from( { 1, 1, 2, 2, 3, 3 } ) ); 69 | REQUIRE( !!r ); 70 | REQUIRE( *r++ == 1 ); 71 | REQUIRE( *r++ == 2 ); 72 | REQUIRE( *r++ == 3 ); 73 | REQUIRE( !r ); 74 | } 75 | 76 | 77 | TEST_CASE( "Distinct range skips all duplicates multiply defined", "[narl][distinct][duplicates][all][multiple]" ) 78 | { 79 | auto r = make_test_range< distinct_range_default >( from( { 1, 1, 1, 2, 2, 2, 3, 3, 3 } ) ); 80 | REQUIRE( !!r ); 81 | REQUIRE( *r++ == 1 ); 82 | REQUIRE( *r++ == 2 ); 83 | REQUIRE( *r++ == 3 ); 84 | REQUIRE( !r ); 85 | } 86 | 87 | 88 | TEST_CASE( "Distinct range can be moved to end and is invalid", "[narl][distinct][gotoend][invalid]" ) 89 | { 90 | auto r = make_test_range< distinct_range_default >( from( { 1, 2 } ) ); 91 | r.goto_end(); 92 | REQUIRE( !r ); 93 | } 94 | 95 | 96 | TEST_CASE( "Distinct range can be decremented from end", "[narl][distinct][decrement][fromend]" ) 97 | { 98 | auto r = make_test_range< distinct_range_default >( from( { 1, 2 } ) ); 99 | r.goto_end(); 100 | --r; 101 | REQUIRE( !!r ); 102 | REQUIRE( *r-- == 2 ); 103 | REQUIRE( *r-- == 1 ); 104 | REQUIRE( !r ); 105 | } 106 | 107 | 108 | TEST_CASE( "Distinct range can be incremented from before begin", "[narl][distinct][increment][beforebegin]" ) 109 | { 110 | auto r = make_test_range< distinct_range_default >( from( { 1, 2 } ) ); 111 | --r; 112 | REQUIRE( !r ); 113 | ++r; 114 | REQUIRE( !!r ); 115 | } 116 | 117 | 118 | TEST_CASE( "Distinct range skips duplicates from start in reverse", "[narl][distinct][duplicates][start][reverse]" ) 119 | { 120 | auto r = make_test_range< distinct_range_default >( from( { 1, 1, 2, 3 } ) ); 121 | r.goto_end(); 122 | REQUIRE( !r-- ); 123 | REQUIRE( *r-- == 3 ); 124 | REQUIRE( *r-- == 2 ); 125 | REQUIRE( *r-- == 1 ); 126 | REQUIRE( !r ); 127 | } 128 | 129 | 130 | TEST_CASE( "Distinct range skips duplicates at end in reverse", "[narl][distinct][duplicates][end][reverse]" ) 131 | { 132 | auto r = make_test_range< distinct_range_default >( from( { 1, 2, 3, 3 } ) ); 133 | r.goto_end(); 134 | REQUIRE( !r-- ); 135 | REQUIRE( *r-- == 3 ); 136 | REQUIRE( *r-- == 2 ); 137 | REQUIRE( *r-- == 1 ); 138 | REQUIRE( !r ); 139 | } 140 | 141 | 142 | TEST_CASE( "Distinct range skips duplicates in middle in reverse", "[narl][distinct][duplicates][middle][reverse]" ) 143 | { 144 | auto r = make_test_range< distinct_range_default >( from( { 1, 2, 2, 3 } ) ); 145 | r.goto_end(); 146 | REQUIRE( !r-- ); 147 | REQUIRE( *r-- == 3 ); 148 | REQUIRE( *r-- == 2 ); 149 | REQUIRE( *r-- == 1 ); 150 | REQUIRE( !r ); 151 | } 152 | 153 | 154 | TEST_CASE( "Distinct range skips all duplicates in reverse", "[narl][distinct][duplicates][all][reverse]" ) 155 | { 156 | auto r = make_test_range< distinct_range_default >( from( { 1, 1, 2, 2, 3, 3 } ) ); 157 | r.goto_end(); 158 | REQUIRE( !r-- ); 159 | REQUIRE( *r-- == 3 ); 160 | REQUIRE( *r-- == 2 ); 161 | REQUIRE( *r-- == 1 ); 162 | REQUIRE( !r ); 163 | } 164 | 165 | 166 | TEST_CASE( "Distinct range can use supplied comparer", "[narl][distinct][customcomparer]" ) 167 | { 168 | auto r = make_test_range< distinct_range >( from( { 5, 4, 3, 3, 3, 1 } ), []( int l, int r ) { return l == r; } ); 169 | 170 | REQUIRE( *r++ == 5 ); 171 | REQUIRE( *r++ == 4 ); 172 | REQUIRE( *r++ == 3 ); 173 | REQUIRE( *r++ == 1 ); 174 | REQUIRE( !r ); 175 | } 176 | 177 | 178 | 179 | -------------------------------------------------------------------------------- /src/tests/testnarl/test_filtering_range.cpp: -------------------------------------------------------------------------------- 1 | #include "testnarl.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | 9 | using namespace narl; 10 | 11 | 12 | TEST_CASE( "Filtering range is evaluated lazily", "[narl][filtering_range][deferred]" ) 13 | { 14 | auto r = make_test_range< filtering_range >( throwing_range< int >{}, []( int ) { return false; } ); 15 | 16 | REQUIRE_THROWS_AS( ++r, range_access_exception ); 17 | REQUIRE_THROWS_AS( r++, range_access_exception ); 18 | REQUIRE_THROWS_AS( *r, range_access_exception ); 19 | REQUIRE_THROWS_AS( r && true, range_access_exception ); 20 | } 21 | 22 | 23 | TEST_CASE( "Filtering range returns first element if its a match", "[marl][filtering_range][firstismatch]" ) 24 | { 25 | auto src = from( { 1, 2 } ); 26 | auto r = make_test_range< filtering_range >( src, []( int i ) { return i % 2 != 0; } ); 27 | 28 | REQUIRE( *r == *src ); 29 | } 30 | 31 | 32 | TEST_CASE( "Filtering range return first matching element when not 1st in range", "[narl][filtering_range][notfirstmatch]" ) 33 | { 34 | auto src = from( { 1, 2, 3 } ); 35 | auto r = make_test_range< filtering_range >( src, []( int i ) { return i % 2 == 0; } ); 36 | 37 | ++src; 38 | REQUIRE( *r == *src ); 39 | } 40 | 41 | 42 | TEST_CASE( "Filtering range returns match when found in last position", "[narl][filtering_range][lastismatch]" ) 43 | { 44 | auto src = from( { 1, 2, 3 } ); 45 | auto r = make_test_range< filtering_range >( src, []( int i ) { return i == 3; } ); 46 | 47 | ++src; ++src; 48 | REQUIRE( *r == *src ); 49 | } 50 | 51 | 52 | TEST_CASE( "Filtering range is immediately invalid if no matches", "[narl][filtering_range][nomatch]" ) 53 | { 54 | auto r = make_test_range< filtering_range >( from( { 1 } ), []( int ) { return false; } ); 55 | 56 | REQUIRE( !r ); 57 | } 58 | 59 | 60 | TEST_CASE( "Filtering range finds subsequent match in adjacent pos", "[narl][filtering_range][next][adjacent]" ) 61 | { 62 | auto src = from( { 1, 3, 5 } ); 63 | auto r = make_test_range< filtering_range >( src, []( int ) { return true; } ); 64 | 65 | REQUIRE( *r == *src ); 66 | ++r; 67 | ++src; 68 | REQUIRE( *r == *src ); 69 | } 70 | 71 | 72 | TEST_CASE( "Filtering range moves to next match", "[narl][filtering_range][next]" ) 73 | { 74 | auto src = from( { 1, 2, 3 } ); 75 | auto r = make_test_range< filtering_range >( src, []( int i ) { return i % 2 != 0; } ); 76 | 77 | REQUIRE( *r++ == *src ); 78 | ++src; 79 | ++src; 80 | REQUIRE( *r == *src ); 81 | } 82 | 83 | 84 | TEST_CASE( "Filtering range becomes invalid after last match", "[narl][filtering_range][invalid][afterlast]" ) 85 | { 86 | auto src = from( { 1, 2, 3, 5 } ); 87 | auto r = make_test_range< filtering_range >( src, []( int i ) { return i % 2 == 0; } ); 88 | 89 | ++src; 90 | REQUIRE( *r++ == *src ); 91 | REQUIRE( !r ); 92 | } 93 | 94 | 95 | TEST_CASE( "Filtering range can be decremented to find previous match", "[narl][filtering_range][decrement]" ) 96 | { 97 | auto src = from( { 1, 2, 3, 4, 5 } ); 98 | auto r = make_test_range< filtering_range >( src, []( int i ) { return i % 2 == 0; } ); 99 | ++r; ++r; 100 | 101 | REQUIRE( *r == 4 ); 102 | --r; 103 | REQUIRE( *r == 2 ); 104 | } 105 | 106 | 107 | TEST_CASE( "Filtering range is invalid when decremented from first match", "[narl][filtering_range][decrement][invalid]" ) 108 | { 109 | auto src = from( { 1, 2, 3 } ); 110 | auto r = make_test_range< filtering_range >( src, []( int i ){ return i % 2 == 0; } ); 111 | 112 | REQUIRE( *r == 2 ); 113 | --r; 114 | REQUIRE( !r ); 115 | } 116 | 117 | 118 | TEST_CASE( "Filtering range goes to first match after decrement followed by increment", "[narl][filtering_range][decrementandincrement]" ) 119 | { 120 | auto src = from( { 1, 2, 3 } ); 121 | auto r = make_test_range< filtering_range >( src, []( int i ) { return i % 2 == 0; } ); 122 | REQUIRE( *r == 2 ); 123 | --r; 124 | REQUIRE( !r ); 125 | ++r; 126 | REQUIRE( *r == 2 ); 127 | } 128 | 129 | 130 | TEST_CASE( "Filtering range goes to last match after increment followed by decrement", "[narl][filtering_range][incrementanddecrement]" ) 131 | { 132 | auto src = from( { 1, 2, 3 } ); 133 | auto r = make_test_range< filtering_range >( src, []( int i ) { return i % 2 == 0; } ); 134 | 135 | REQUIRE( *r++ == 2 ); 136 | REQUIRE( !r-- ); 137 | REQUIRE( !!r ); 138 | REQUIRE( *r == 2 ); 139 | } 140 | 141 | 142 | TEST_CASE( "Filtering range can be moved to the end", "[narl][filtering_range][goto_end]" ) 143 | { 144 | auto src = from( { 1, 2, 3, 4, 5 } ); 145 | auto r = make_test_range< filtering_range >( src, []( int i ) { return i % 2 == 0; } ); 146 | r.goto_end(); 147 | 148 | REQUIRE( !r ); 149 | --r; 150 | REQUIRE( *r == 4 ); 151 | } 152 | 153 | 154 | 155 | -------------------------------------------------------------------------------- /src/tests/testnarl/test_grouping_range.cpp: -------------------------------------------------------------------------------- 1 | #include "testnarl.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | 10 | 11 | using namespace narl; 12 | 13 | 14 | struct item 15 | { 16 | int id; 17 | std::string name; 18 | double val; 19 | }; 20 | 21 | TEST_CASE( "Grouping range is evaluated lazily", "[narl][grouping][lazy]" ) 22 | { 23 | auto r = make_test_range< grouping_range >( throwing_range< int >{}, []( int ) { return 1; } ); 24 | 25 | REQUIRE_THROWS_AS( ++r, range_access_exception ); 26 | REQUIRE_THROWS_AS( r++, range_access_exception ); 27 | REQUIRE_THROWS_AS( *r, range_access_exception ); 28 | REQUIRE_THROWS_AS( r && true, range_access_exception ); 29 | } 30 | 31 | 32 | TEST_CASE( "Grouping range can be incremented to yield next value", "[narl][grouping][increment]" ) 33 | { 34 | std::vector< item > src { 35 | item{ 0, "0", 0.0 }, 36 | item{ 1, "1", 1.1 } 37 | }; 38 | auto r = make_test_range< grouping_range >( from( src ), []( item i ) { return i.id; } ); 39 | 40 | REQUIRE( ( *r ).key == 0 ); 41 | ++r; 42 | REQUIRE( ( *r ).key == 1 ); 43 | } 44 | 45 | 46 | TEST_CASE( "Grouping range can be post-incremented to yield next value", "[narl][grouping][postincrement" ) 47 | { 48 | std::vector< item > src { 49 | item{ 0, "0", 0.0 }, 50 | item{ 1, "1", 1.1 } 51 | }; 52 | auto r = make_test_range< grouping_range >( from( src ), []( item i ) { return i.id; } ); 53 | 54 | REQUIRE( ( *r++ ).key == 0 ); 55 | REQUIRE( ( *r++ ).key == 1 ); 56 | } 57 | 58 | 59 | TEST_CASE( "Grouping range can be decremented to yield previous value", "[narl][grouping][decrement]" ) 60 | { 61 | std::vector< item > src { 62 | item{ 0, "0", 0.0 }, 63 | item{ 1, "1", 1.1 } 64 | }; 65 | auto r = make_test_range< grouping_range >( from( src ), []( item i ) { return i.id; } ); 66 | ++r; 67 | 68 | REQUIRE( ( *r ).key == 1 ); 69 | --r; 70 | REQUIRE( ( *r ).key == 0 ); 71 | } 72 | 73 | 74 | TEST_CASE( "Grouping range can be post-decremented to yield previous value", "[narl][grouping][postdecrement" ) 75 | { 76 | std::vector< item > src { 77 | item{ 0, "0", 0.0 }, 78 | item{ 1, "1", 1.1 } 79 | }; 80 | auto r = make_test_range< grouping_range >( from( src ), []( item i ) { return i.id; } ); 81 | ++r; 82 | REQUIRE( ( *r-- ).key == 1 ); 83 | REQUIRE( ( *r-- ).key == 0 ); 84 | } 85 | 86 | 87 | TEST_CASE( "Grouping range can be moved to end and is invalid", "[narl][grouping][goto_end][invalid]" ) 88 | { 89 | std::vector< item > src { 90 | item{ 0, "0", 0.0 }, 91 | item{ 1, "1", 1.1 } 92 | }; 93 | auto r = make_test_range< grouping_range >( from( src ), []( item i ) { return i.id; } ); 94 | r.goto_end(); 95 | REQUIRE( !r ); 96 | } 97 | 98 | 99 | TEST_CASE( "Grouping range is invalid when before begin", "[narl][grouping][invalid][beforebegin]" ) 100 | { 101 | std::vector< item > src { 102 | item{ 0, "0", 0.0 }, 103 | item{ 1, "1", 1.1 } 104 | }; 105 | auto r = make_test_range< grouping_range >( from( src ), []( item i ) { return i.id; } ); 106 | --r; 107 | REQUIRE( !r ); 108 | } 109 | 110 | 111 | TEST_CASE( "Grouping range can be incremented from before begin", "[narl][grouping][valid][beforebegin][increment]" ) 112 | { 113 | std::vector< item > src { 114 | item{ 0, "0", 0.0 }, 115 | item{ 1, "1", 1.1 } 116 | }; 117 | auto r = make_test_range< grouping_range >( from( src ), []( item i ) { return i.id; } ); 118 | --r; 119 | REQUIRE( !r ); 120 | ++r; 121 | REQUIRE( !!r ); 122 | } 123 | 124 | 125 | TEST_CASE( "Grouping range can be decremented from the end", "[narl][grouping][valid][end][decrement]" ) 126 | { 127 | std::vector< item > src { 128 | item{ 0, "0", 0.0 }, 129 | item{ 1, "1", 1.1 } 130 | }; 131 | auto r = make_test_range< grouping_range >( from( src ), []( item i ) { return i.id; } ); 132 | r.goto_end(); 133 | --r; 134 | REQUIRE( !!r ); 135 | } 136 | 137 | 138 | TEST_CASE( "Grouping range groups items according to provided key selector", "[narl][grouping][key]" ) 139 | { 140 | std::vector< item > src { 141 | item{ 0, "0", 0.0 }, 142 | item{ 0, "00", 0.1 }, 143 | item{ 1, "1", 1.0 } 144 | }; 145 | auto r = make_test_range< grouping_range >( from( src ), []( const item & i ) { return i.id; } ); 146 | 147 | auto i = *r++; 148 | auto v = i.values; 149 | REQUIRE( i.key == 0 ); 150 | REQUIRE( ( *v++ ).name == "0" ); 151 | REQUIRE( ( *v++ ).name == "00" ); 152 | REQUIRE( !v ); 153 | 154 | i = *r++; 155 | v = i.values; 156 | REQUIRE( i.key == 1 ); 157 | REQUIRE( ( *v++ ).name == "1" ); 158 | REQUIRE( !v ); 159 | } 160 | 161 | 162 | TEST_CASE( "Grouping range can be keyed on any field", "[narl][grouping][key][any]" ) 163 | { 164 | std::vector< item > src { 165 | item{ 0, "0", 0.0 }, 166 | item{ 1, "1", 0.1 }, 167 | item{ 2, "1", 1.0 } 168 | }; 169 | auto r = make_test_range< grouping_range >( from( src ), []( const item & i ) { return i.name; } ); 170 | 171 | auto i = *r++; 172 | auto v = i.values; 173 | REQUIRE( i.key == "0" ); 174 | REQUIRE( ( *v++ ).val == 0.0 ); 175 | REQUIRE( !v ); 176 | 177 | auto j = *r++; 178 | v = j.values; 179 | REQUIRE( j.key == "1" ); 180 | REQUIRE( ( *v++ ).val == 0.1 ); 181 | REQUIRE( ( *v++ ).val == 1.0 ); 182 | REQUIRE( !v ); 183 | } 184 | 185 | 186 | -------------------------------------------------------------------------------- /src/tests/testnarl/test_iterable_range.cpp: -------------------------------------------------------------------------------- 1 | #include "testnarl.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | using namespace narl; 13 | 14 | 15 | TEST_CASE( "Range is created from vector source", "[narl][create][vector]" ) 16 | { 17 | std::vector< int > src { 1, 2, 3 }; 18 | auto r = from( src ); 19 | 20 | REQUIRE( ( std::is_same< int, decltype( *r ) >() ) ); 21 | REQUIRE( !!r ); 22 | } 23 | 24 | 25 | TEST_CASE( "Range is created from built in array source", "[narl][create][builtinarray]" ) 26 | { 27 | int src[] = { 1, 2, 3 }; 28 | auto r = from( src ); 29 | 30 | REQUIRE( ( std::is_same< int, decltype( *r ) >() ) ); 31 | REQUIRE( !!r ); 32 | } 33 | 34 | 35 | TEST_CASE( "Range is created from static array source", "[narl][create][staticarray]" ) 36 | { 37 | std::array< int, 3 > src { { 1, 2, 3 } }; 38 | auto r = from( src ); 39 | 40 | REQUIRE( ( std::is_same< int, decltype( *r ) >() ) ); 41 | REQUIRE( !!r ); 42 | } 43 | 44 | 45 | TEST_CASE( "Range is created from named initializer list source", "[narl][create][named][initializer_list]" ) 46 | { 47 | auto data = { 1, 2, 3 }; 48 | auto r = from( data ); 49 | 50 | REQUIRE( ( std::is_same< iterable_range< std::initializer_list< int >::const_iterator, int >, decltype( r ) >() ) ); 51 | REQUIRE( ( std::is_same< int, decltype( *r ) >() ) ); 52 | REQUIRE( !!r ); 53 | } 54 | 55 | 56 | TEST_CASE( "Range is created from initializer list source", "[narl][create][initializer_list]" ) 57 | { 58 | auto r = from( { 1, 2, 3 } ); 59 | 60 | REQUIRE( ( std::is_same< own_container_range< std::vector, int >, decltype( r ) >() ) ); 61 | REQUIRE( ( std::is_same< int, decltype( *r ) >() ) ); 62 | REQUIRE( !!r ); 63 | } 64 | 65 | 66 | TEST_CASE( "Range is created from initializer list of string source", "[narl][create][initializer_list][string]" ) 67 | { 68 | auto r = from( { std::string( "1" ), std::string( "2" ), std::string( "3" ) } ); 69 | 70 | REQUIRE( ( std::is_same< own_container_range< std::vector, std::string >, decltype( r ) >() ) ); 71 | 72 | REQUIRE( !!r ); 73 | REQUIRE( ( std::is_same< std::string, decltype( *r ) >() ) ); 74 | 75 | REQUIRE( *r++ == "1" ); 76 | REQUIRE( *r++ == "2" ); 77 | REQUIRE( *r++ == "3" ); 78 | REQUIRE( !r ); 79 | } 80 | 81 | 82 | TEST_CASE( "Range is created from external initializer list of string source", "[narl][create][initializer_list][external][string]" ) 83 | { 84 | auto src { std::string( "1" ), std::string( "2" ), std::string( "3" ) }; 85 | auto r = from( src ); 86 | REQUIRE( ( std::is_same< iterable_range< std::initializer_list< std::string >::const_iterator, std::string >, decltype( r ) >() ) ); 87 | 88 | REQUIRE( !!r ); 89 | REQUIRE( ( std::is_same< std::string, decltype( *r ) >() ) ); 90 | 91 | REQUIRE( *r++ == "1" ); 92 | REQUIRE( *r++ == "2" ); 93 | REQUIRE( *r++ == "3" ); 94 | REQUIRE( !r ); 95 | } 96 | 97 | 98 | TEST_CASE( "Range created from single element initializer list has one element", "[narl][create][initializer_list][single]" ) 99 | { 100 | auto r = from( { 1 } ); 101 | REQUIRE( !!r++ ); 102 | REQUIRE( !r ); 103 | } 104 | 105 | 106 | TEST_CASE( "Range created from empty source is immediately invalid", "[narl][create][empty][invalid]" ) 107 | { 108 | std::vector< int > src; 109 | auto r = from( src ); 110 | 111 | REQUIRE( !r ); 112 | } 113 | 114 | 115 | TEST_CASE( "Range is created from temporary collection", "[narl][create][temporary][collection]" ) 116 | { 117 | auto r = from( std::list< int > { 1, 2, 3 } ); 118 | 119 | REQUIRE( ( std::is_same< own_container_range< std::list, int >, decltype( r ) >() ) ); 120 | REQUIRE( ( std::is_same< int, decltype( *r ) >() ) ); 121 | } 122 | 123 | 124 | TEST_CASE( "Range can be incremented to yield next value", "[narl][increment]" ) 125 | { 126 | auto r = from( { 1, 2 } ); 127 | 128 | REQUIRE( *r++ == 1 ); 129 | REQUIRE( *r++ == 2 ); 130 | } 131 | 132 | 133 | TEST_CASE( "Range can be pre-incremented to yield next value", "[narl][preincrement]" ) 134 | { 135 | auto r = from( { 1, 2 } ); 136 | 137 | ++r; 138 | REQUIRE( *r == 2 ); 139 | } 140 | 141 | 142 | TEST_CASE( "Range is invalid after incrementing past last element", "[narl][increment][invalid]" ) 143 | { 144 | auto r = from( { 1 } ); 145 | 146 | REQUIRE( !!r ); 147 | ++r; 148 | REQUIRE( !r ); 149 | } 150 | 151 | 152 | TEST_CASE( "Dereferencing an invalid range produces error", "[narl][dereference][invalid][error]" ) 153 | { 154 | auto r = from( { 1 } ); 155 | ++r; 156 | 157 | REQUIRE_THROWS_AS( *r, std::out_of_range ); 158 | } 159 | 160 | 161 | TEST_CASE( "Range cen be decremented to yield previous value", "[narl][predecrement]" ) 162 | { 163 | auto r = from( { 1, 2 } ); 164 | ++r; 165 | REQUIRE( *r == 2 ); 166 | --r; 167 | REQUIRE( *r == 1 ); 168 | } 169 | 170 | 171 | TEST_CASE( "Range can be post-decremented to yield previous value", "[narl][decrement]" ) 172 | { 173 | auto r = from( { 1, 2 } ); 174 | 175 | ++r; 176 | 177 | REQUIRE( *r-- == 2 ); 178 | REQUIRE( *r == 1 ); 179 | } 180 | 181 | 182 | TEST_CASE( "Range can be decremented to be valid after going past the end", "[narl][decrement][pasttheend]" ) 183 | { 184 | auto r = from( { 1, 2 } ); 185 | 186 | ++r; ++r; 187 | REQUIRE( !r ); 188 | --r; 189 | REQUIRE( !!r ); 190 | REQUIRE( *r == 2 ); 191 | } 192 | 193 | 194 | TEST_CASE( "Range is invalid after going past begin", "[narl][decrement][invalid]" ) 195 | { 196 | auto r = from( { 1 } ); 197 | --r; 198 | 199 | REQUIRE( !r ); 200 | } 201 | 202 | 203 | TEST_CASE( "Range can be incremented to be valid after going past begin", "[narl][increment][pastbegin]" ) 204 | { 205 | auto r = from( { 1 } ); 206 | --r; 207 | REQUIRE( !r ); 208 | ++r; 209 | REQUIRE( !!r ); 210 | REQUIRE( *r == 1 ); 211 | } 212 | 213 | 214 | TEST_CASE( "Range can be moved to the end", "[narl][gotoend][invalid]" ) 215 | { 216 | auto r = from( { 1, 2 } ); 217 | r.goto_end(); 218 | REQUIRE( !r-- ); 219 | REQUIRE( *r == 2 ); 220 | } 221 | 222 | 223 | 224 | -------------------------------------------------------------------------------- /src/tests/testnarl/test_merging_range.cpp: -------------------------------------------------------------------------------- 1 | #include "testnarl.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | 9 | using namespace narl; 10 | 11 | 12 | TEST_CASE( "Merging range is lazy evaluated", "[narl][merging_range][lazy]" ) 13 | { 14 | auto r = make_test_range< merging_range >( throwing_range< int >(), from( { 1, 2, 4 } ), std::less< int >() ); 15 | 16 | REQUIRE_THROWS_AS( *r, range_access_exception ); 17 | REQUIRE_THROWS_AS( r && true, range_access_exception ); 18 | REQUIRE_THROWS_AS( ++r, range_access_exception ); 19 | REQUIRE_THROWS_AS( --r, range_access_exception ); 20 | } 21 | 22 | 23 | TEST_CASE( "Merging range with empty is same as first range", "[narl][merging_range][empty][left]" ) 24 | { 25 | std::vector< int > empty; 26 | auto r = make_test_range< merging_range_default >( from( { 1, 2 } ), from( empty ) ); 27 | 28 | REQUIRE( !!r ); 29 | REQUIRE( *r++ == 1 ); 30 | REQUIRE( *r++ == 2 ); 31 | REQUIRE( !r ); 32 | } 33 | 34 | 35 | TEST_CASE( "Merging empty with range is same as second range", "[narl][merging_range][empty][right]" ) 36 | { 37 | std::vector< int > empty; 38 | auto r = make_test_range< merging_range_default >( from( empty ), from( { 1, 2 } ) ); 39 | 40 | REQUIRE( !!r ); 41 | REQUIRE( *r++ == 1 ); 42 | REQUIRE( *r++ == 2 ); 43 | REQUIRE( !r ); 44 | } 45 | 46 | 47 | TEST_CASE( "Merging duplicate ranges has every item", "[narl][merging_range][same]" ) 48 | { 49 | auto r = make_test_range< merging_range_default >( from( { 1, 3 } ), from( { 1, 3 } ) ); 50 | 51 | REQUIRE( *r++ == 1 ); 52 | REQUIRE( *r++ == 1 ); 53 | REQUIRE( *r++ == 3 ); 54 | REQUIRE( *r++ == 3 ); 55 | REQUIRE( !r ); 56 | } 57 | 58 | 59 | TEST_CASE( "Merging contains all items from both ranges", "[narl][merging_range][all]" ) 60 | { 61 | auto r = make_test_range< merging_range_default >( from( { 1, 3 } ), from( { 2, 4 } ) ); 62 | 63 | REQUIRE( *r++ == 1 ); 64 | REQUIRE( *r++ == 2 ); 65 | REQUIRE( *r++ == 3 ); 66 | REQUIRE( *r++ == 4 ); 67 | REQUIRE( !r ); 68 | } 69 | 70 | 71 | TEST_CASE( "Merging contains all items from both ranges with preincrement", "[narl][merging_range][all][preincrement]" ) 72 | { 73 | auto r = make_test_range< merging_range_default >( from( { 1, 3 } ), from( { 2, 4 } ) ); 74 | 75 | REQUIRE( *r == 1 ); 76 | REQUIRE( *++r == 2 ); 77 | REQUIRE( *++r == 3 ); 78 | REQUIRE( *++r == 4 ); 79 | REQUIRE( !++r ); 80 | } 81 | 82 | 83 | TEST_CASE( "Merging range contains all items from both ranges when first element is on the right", "[narl][merging_range][all][firstright]" ) 84 | { 85 | auto r = make_test_range< merging_range_default >( from( { 2, 4 } ), from( { 1, 3 } ) ); 86 | 87 | REQUIRE( *r++ == 1 ); 88 | REQUIRE( *r++ == 2 ); 89 | REQUIRE( *r++ == 3 ); 90 | REQUIRE( *r++ == 4 ); 91 | REQUIRE( !r ); 92 | } 93 | 94 | 95 | TEST_CASE( "Merging contains all items when left is longer", "[narl][merging_range][leftlonger]" ) 96 | { 97 | auto r = make_test_range< merging_range_default >( from( { 0, 2, 4, 6 } ), from( { 1, 2, 3 } ) ); 98 | 99 | REQUIRE( *r++ == 0 ); 100 | REQUIRE( *r++ == 1 ); 101 | REQUIRE( *r++ == 2 ); 102 | REQUIRE( *r++ == 2 ); 103 | REQUIRE( *r++ == 3 ); 104 | REQUIRE( *r++ == 4 ); 105 | REQUIRE( *r++ == 6 ); 106 | REQUIRE( !r ); 107 | } 108 | 109 | 110 | TEST_CASE( "Merging range can be moved to end and decremented to get final element", "[narl][merging_range][gotoend][decrement]" ) 111 | { 112 | auto r = make_test_range< merging_range_default >( from( { 2, 4 } ), from( { 1, 3 } ) ) ; 113 | r.goto_end(); 114 | 115 | REQUIRE( !r ); 116 | --r; 117 | REQUIRE( !!r ); 118 | REQUIRE( *r == 4 ); 119 | } 120 | 121 | 122 | TEST_CASE( "Merging range can be moved to end and decremented to get final element on the right", "[narl][merging_range][gotoend][decrement][right]" ) 123 | { 124 | auto r = make_test_range< merging_range_default >( from( { 1, 3 } ), from( { 2, 4 } ) ) ; 125 | r.goto_end(); 126 | 127 | REQUIRE( !r ); 128 | --r; 129 | REQUIRE( !!r ); 130 | REQUIRE( *r == 4 ); 131 | } 132 | 133 | 134 | TEST_CASE( "Merging range finds all elements in reverse with predecrement", "[narl][merging_range][predecrement]" ) 135 | { 136 | auto r = make_test_range< merging_range_default >( from( { 0, 2, 4, 6 } ), from( { 1, 2, 3 } ) ); 137 | r.goto_end(); 138 | 139 | REQUIRE( *--r == 6 ); 140 | REQUIRE( *--r == 4 ); 141 | REQUIRE( *--r == 3 ); 142 | REQUIRE( *--r == 2 ); 143 | REQUIRE( *--r == 2 ); 144 | REQUIRE( *--r == 1 ); 145 | REQUIRE( *--r == 0 ); 146 | REQUIRE( !--r ); 147 | } 148 | 149 | 150 | TEST_CASE( "Merging range can be incremented from before begin to get first element", "[narl][merging_range][beforebegin][increment]" ) 151 | { 152 | auto r = make_test_range< merging_range_default >( from( { 1, 3 } ), from( { 2, 4 } ) ); 153 | --r; 154 | 155 | REQUIRE( !r++ ); 156 | REQUIRE( !!r ); 157 | REQUIRE( *r == 1 ); 158 | } 159 | 160 | 161 | TEST_CASE( "Merging range can be incremented from before begin to get first element on right", "[narl][merging_range][beforebegin][increment][right]" ) 162 | { 163 | auto r = make_test_range< merging_range_default >( from( { 2, 4 } ), from( { 1, 3 } ) ); 164 | --r; 165 | 166 | REQUIRE( !r++ ); 167 | REQUIRE( !!r ); 168 | REQUIRE( *r == 1 ); 169 | } 170 | 171 | 172 | TEST_CASE( "Merging range can use custom comparer", "[narl][merging_range][customcmp]" ) 173 | { 174 | auto r = make_test_range< merging_range >( from( { 3, 1 } ), from( { 4, 2 } ), []( int l, int r ) { return l > r; } ); 175 | 176 | REQUIRE( *r++ == 4 ); 177 | REQUIRE( *r++ == 3 ); 178 | REQUIRE( *r++ == 2 ); 179 | REQUIRE( *r++ == 1 ); 180 | REQUIRE( !r ); 181 | } 182 | 183 | 184 | -------------------------------------------------------------------------------- /src/tests/testnarl/test_range_accumulate.cpp: -------------------------------------------------------------------------------- 1 | #include "testnarl.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | 10 | 11 | using namespace narl; 12 | 13 | 14 | TEST_CASE( "Range accumulator throws exception when underlying range is empty", "[narl][accumulate]" ) 15 | { 16 | std::vector< int > src; 17 | auto r = make_test_range< range_accumulate >( from( src ), 1, []( int, int ) { return 0; } ); 18 | 19 | REQUIRE_THROWS_AS( r.value(), std::invalid_argument ); 20 | } 21 | 22 | 23 | TEST_CASE( "Range accumulator value is same as seed value when only one item in range", "[narl][accumulate][single]" ) 24 | { 25 | auto r = make_test_range< range_accumulate >( from( { 1 } ), 1, []( int, int i ) { return i; } ); 26 | REQUIRE( r.value() == 1 ); 27 | } 28 | 29 | 30 | TEST_CASE( "Range accumulator applies fn to each item in turn", "[narl][accumulate][eachitem]" ) 31 | { 32 | auto r = make_test_range< range_accumulate >( from( { 1, 2, 3 } ), 1, []( int c, int i ) { return c * i; } ); 33 | REQUIRE( r.value() == 6 ); 34 | } 35 | 36 | 37 | TEST_CASE( "Range default accumulator throws exception when underlying range is empty", "[narl][defaultaccumulate]" ) 38 | { 39 | std::vector< int > src; 40 | auto r = make_test_range< range_default_accumulate >( from( src ), []( int, int ) { return 0; } ); 41 | 42 | REQUIRE_THROWS_AS( r.value(), std::invalid_argument ); 43 | } 44 | 45 | 46 | TEST_CASE( "Range default accumulator uses first element as seed when none provided", "[narl][defaultaccumulate][1stitemseed]" ) 47 | { 48 | auto r = make_test_range< range_default_accumulate >( from( { 2, 3, 4 } ), []( int c, int i ) { return c * i; } ); 49 | REQUIRE( r.value() == 24 ); 50 | } 51 | 52 | 53 | TEST_CASE( "Range default accumulator applies fn to each item in turn", "[narl][defaultaccumulate][eachitem]" ) 54 | { 55 | auto r = make_test_range< range_default_accumulate >( from( { 1, 2, 3 } ), []( int c, int i ) { return c * i; } ); 56 | REQUIRE( r.value() == 6 ); 57 | } 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /src/tests/testnarl/test_range_factory.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | 6 | using namespace narl; 7 | 8 | 9 | template< typename R > 10 | struct dummy_range_0 11 | { 12 | dummy_range_0( R r ) : r{ r } { } 13 | R r; 14 | }; 15 | 16 | template< typename R > 17 | struct dummy_range_1 18 | { 19 | dummy_range_1( R r, int n ) : r{ r }, n{ n } { } 20 | R r; 21 | int n; 22 | }; 23 | 24 | template< typename R, typename T > 25 | struct dummy_range_2 26 | { 27 | dummy_range_2( R r, T t ) : r{ r }, t{ t } { } 28 | R r; 29 | T t; 30 | }; 31 | 32 | 33 | TEST_CASE( "Factory object creates nullary range type", "[narl][range_factory][nullary]" ) 34 | { 35 | range_0_factory< dummy_range_0 > factory{}; 36 | auto result = factory( 2 ); 37 | 38 | REQUIRE( result.r == 2 ); 39 | } 40 | 41 | 42 | TEST_CASE( "Factory object creates unary range type with provided expression", "[narl][range_factory][unary]" ) 43 | { 44 | range_1_factory< dummy_range_1, int > factory{ 10 }; 45 | auto result = factory( 2 ); 46 | 47 | int underlying = 2; 48 | int expected = 10; 49 | REQUIRE( result.r == underlying ); 50 | REQUIRE( result.n == expected ); 51 | } 52 | 53 | 54 | TEST_CASE( "Factory object creates selected range type with provided expression", "[narl][range_factory][binary]" ) 55 | { 56 | range_2_factory< dummy_range_2, int > factory{ 10 }; 57 | auto result = factory( 2 ); 58 | 59 | int underlying = 2; 60 | int expected = 10; 61 | REQUIRE( result.r == underlying ); 62 | REQUIRE( result.t == expected ); 63 | } 64 | 65 | 66 | TEST_CASE( "Factory function creates unary factory object of correct type", "[narl][make_factory][unary]" ) 67 | { 68 | auto factory = make_factory< dummy_range_1 >( 10 ); 69 | auto result = factory( 2 ); 70 | 71 | int underlying = 2; 72 | int expected = 10; 73 | REQUIRE( result.r == underlying ); 74 | REQUIRE( result.n == expected ); 75 | } 76 | 77 | 78 | TEST_CASE( "Factory function creates binary factory object of correct type", "[narl][make_factory][binary]" ) 79 | { 80 | auto factory = make_factory< dummy_range_2 >( 10 ); 81 | auto result = factory( 2 ); 82 | 83 | int underlying = 2; 84 | int expected = 10; 85 | REQUIRE( result.r == underlying ); 86 | REQUIRE( result.t == expected ); 87 | } 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /src/tests/testnarl/test_range_generator.cpp: -------------------------------------------------------------------------------- 1 | #include "testnarl.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | 10 | 11 | using namespace narl; 12 | 13 | 14 | struct generator 15 | { 16 | generator() {} 17 | }; 18 | 19 | TEST_CASE( "Range generator can be instantiated from int", "[narl][range_generator][int]" ) 20 | { 21 | auto r = range_generator< int >{}; 22 | REQUIRE( !!r ); 23 | } 24 | 25 | 26 | TEST_CASE( "Range generator produces expected value on dereference", "[narl][range_generator][int][dereference]" ) 27 | { 28 | auto r = make_range< int >(); 29 | REQUIRE( *r == 0 ); 30 | } 31 | 32 | 33 | TEST_CASE( "Range generator produces next value after postincrement", "[narl][range_generator][int][postinc]" ) 34 | { 35 | auto r = range_generator< int >{}; 36 | REQUIRE( *r++ == 0 ); 37 | REQUIRE( *r++ == 1 ); 38 | REQUIRE( *r++ == 2 ); 39 | } 40 | 41 | 42 | TEST_CASE( "Range generator produces next value after preincrement", "[narl][range_generator][int][preinc]" ) 43 | { 44 | auto r = range_generator< int >{}; 45 | ++r; 46 | REQUIRE( *r == 1 ); 47 | ++r; 48 | REQUIRE( *r == 2 ); 49 | } 50 | 51 | 52 | TEST_CASE( "Range generator can be instantiated from user type", "[narl][range_generator][userdef]" ) 53 | { 54 | auto r = range_generator< int >{}; 55 | REQUIRE( !!r ); 56 | } 57 | 58 | 59 | TEST_CASE( "Range generator from user type produces correct type on dereference", "[narl][range_generator][userdef][dereferencetype]" ) 60 | { 61 | auto r = range_generator< generator >{}; 62 | REQUIRE( ( std::is_same< decltype( *r ), generator >() ) ); 63 | } 64 | 65 | 66 | TEST_CASE( "Range generator accepts a callback for values", "[narl][range_generator][userdef][callback]" ) 67 | { 68 | auto r = make_test_range< range_generator_callback >( 0, []( int i ) { return i + 1; } ); 69 | REQUIRE( *r++ == 0 ); 70 | REQUIRE( *r++ == 1 ); 71 | REQUIRE( *r++ == 2 ); 72 | } 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /src/tests/testnarl/test_range_predicate.cpp: -------------------------------------------------------------------------------- 1 | #include "testnarl.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | 9 | using namespace narl; 10 | 11 | 12 | TEST_CASE( "Range validator is true if underlying object is true", "[narl][range_validator]" ) 13 | { 14 | auto src = from( { 1 } ); 15 | auto r = make_test_range< range_validator >( src ); 16 | 17 | REQUIRE( r.value() ); 18 | } 19 | 20 | 21 | TEST_CASE( "Range validator is false if underlying range is invalid", "[narl][range_validator][invalid]" ) 22 | { 23 | auto src = from( { 1 } ); 24 | ++src; 25 | auto r = make_test_range< range_validator >( src ); 26 | 27 | REQUIRE( !r.value() ); 28 | } 29 | 30 | 31 | TEST_CASE( "Range predicate is true if filter of underlying range is true", "[narl][range_predicate]" ) 32 | { 33 | auto src = from( { 1 } ); 34 | auto r = make_test_range< range_predicate >( src, []( int ) { return true; } ); 35 | 36 | REQUIRE( !!r.value() ); 37 | } 38 | 39 | 40 | TEST_CASE( "Range predicate is false if filter of underlying range is false", "[narl][range_predicate][invalid]" ) 41 | { 42 | auto src = from( { 1 } ); 43 | auto r = make_test_range< range_predicate >( src, []( int ) { return false; } ); 44 | 45 | REQUIRE( !r.value() ); 46 | } 47 | 48 | 49 | TEST_CASE( "Inverter predicate is true if filter of underlying range is true", "[narl][inverter]" ) 50 | { 51 | auto src = from( { 1 } ); 52 | auto r = make_test_range< range_predicate_inverter >( src, []( int ) { return true; } ); 53 | 54 | REQUIRE( !!r.value() ); 55 | } 56 | 57 | 58 | TEST_CASE( "Inverter predicate is false if filter of underlying range is false", "[narl][inverter][invalid]" ) 59 | { 60 | auto src = from( { 1 } ); 61 | auto r = make_test_range< range_predicate_inverter >( src, []( int ) { return false; } ); 62 | 63 | REQUIRE( !r.value() ); 64 | } 65 | 66 | 67 | TEST_CASE( "Range equality is true for two empty ranges", "[narl][equality][bothempty]" ) 68 | { 69 | std::vector< int > empty; 70 | auto r = make_test_range< range_equality >( from( empty ), from( empty ), []( int l, int r ) { return l == r; } ); 71 | 72 | REQUIRE( !!r.value() ); 73 | } 74 | 75 | 76 | TEST_CASE( "Range equality fails for empty vs nonempty", "[narl][equality][emptyleft]" ) 77 | { 78 | std::vector< int > empty; 79 | auto r = make_test_range< range_equality >( from( empty ), from( { 1 } ), []( int l, int r ) { return l == r; } ); 80 | 81 | REQUIRE( !r.value() ); 82 | } 83 | 84 | 85 | TEST_CASE( "Range equality fails for nonempty vs empty", "[narl][equality][emptyright]" ) 86 | { 87 | std::vector< int > empty; 88 | auto r = make_test_range< range_equality >( from( { 1 } ), from( empty ), []( int l, int r ) { return l == r; } ); 89 | 90 | REQUIRE( !r.value() ); 91 | } 92 | 93 | 94 | TEST_CASE( "Range equality fails when left shorter than right", "[narl][equality][shortleft]" ) 95 | { 96 | auto r = make_test_range< range_equality >( from( { 1 } ), from( { 1, 2 } ), []( int l, int r ) { return l == r; } ); 97 | 98 | REQUIRE( !r.value() ); 99 | } 100 | 101 | 102 | TEST_CASE( "Range equality fails when right shorter than left", "[narl][equality][shortright]" ) 103 | { 104 | auto r = make_test_range< range_equality >( from( { 1, 2, 3 } ), from( { 1, 2 } ), []( int l, int r ) { return l == r; } ); 105 | 106 | REQUIRE( !r.value() ); 107 | } 108 | 109 | 110 | TEST_CASE( "Range equality fails when first element mismatch", "[narl][equality][mismatch][first]" ) 111 | { 112 | auto r = make_test_range< range_equality >( from( { 1, 2, 3 } ), from( { 0, 1, 2 } ), []( int l, int r ) { return l == r; } ); 113 | 114 | REQUIRE( !r.value() ); 115 | } 116 | 117 | 118 | TEST_CASE( "Range equality fails when last element mismatch", "[narl][equality][mismatch][last]" ) 119 | { 120 | auto r = make_test_range< range_equality >( from( { 1, 2, 3 } ), from( { 1, 2, 4 } ), []( int l, int r ) { return l == r; } ); 121 | 122 | REQUIRE( !r.value() ); 123 | } 124 | 125 | 126 | TEST_CASE( "Range equality fails when any element mismatch", "[narl][equality][mismatch][any]" ) 127 | { 128 | auto r = make_test_range< range_equality >( from( { 1, 0, 3 } ), from( { 1, 2, 3 } ), []( int l, int r ) { return l == r; } ); 129 | 130 | REQUIRE( !r.value() ); 131 | } 132 | 133 | 134 | TEST_CASE( "Range equality succeeds when ranges are the same", "[narl][equality][equal]" ) 135 | { 136 | auto r = make_test_range< range_equality >( from( { 2, 1, 4, 0 } ), from( { 2, 1, 4, 0 } ), []( int l, int r ) { return l == r; } ); 137 | 138 | REQUIRE( !!r.value() ); 139 | } 140 | 141 | 142 | TEST_CASE( "Range equality uses the provided comparer", "[narl][equality][customcomparer]" ) 143 | { 144 | auto r = make_test_range< range_equality >( from( { 0 } ), from( { 1 } ), []( int l, int r ) { return l != r; } ); 145 | 146 | REQUIRE( !!r.value() ); 147 | } 148 | 149 | 150 | TEST_CASE( "Range equality has a default comparer", "[narl][equality][defaultcomparer]" ) 151 | { 152 | auto r = make_test_range< range_equality_default >( from( { 0, 10, 5 } ), from( { 0, 10, 5 } ) ); 153 | REQUIRE( !!r.value() ); 154 | } 155 | 156 | 157 | -------------------------------------------------------------------------------- /src/tests/testnarl/test_reversed_range.cpp: -------------------------------------------------------------------------------- 1 | #include "testnarl.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | 12 | using namespace narl; 13 | 14 | 15 | TEST_CASE( "Reversed range is evaluated lazily", "[narl][reversed_range][deferred]" ) 16 | { 17 | auto r = make_test_range< reversed_range >( throwing_range< int >{} ); 18 | 19 | REQUIRE_THROWS_AS( ++r, range_access_exception ); 20 | REQUIRE_THROWS_AS( r++, range_access_exception ); 21 | REQUIRE_THROWS_AS( *r, range_access_exception ); 22 | REQUIRE_THROWS_AS( r && true, range_access_exception ); 23 | } 24 | 25 | 26 | TEST_CASE( "Reversed range produces elements in reverse order", "[narl][reversed_range][reversed]" ) 27 | { 28 | auto r = make_test_range< reversed_range >( from( { 2, 1, 0 } ) ); 29 | 30 | REQUIRE( *r++ == 0 ); 31 | REQUIRE( *r++ == 1 ); 32 | REQUIRE( *r++ == 2 ); 33 | REQUIRE( !r ); 34 | } 35 | 36 | 37 | TEST_CASE( "Reversed range of single element procuces that element", "[narl][reversed_range][single]" ) 38 | { 39 | auto r = make_test_range< reversed_range >( from( { 1 } ) ); 40 | 41 | REQUIRE( *r == 1 ); 42 | } 43 | 44 | 45 | TEST_CASE( "Reversed range is invalid after incrementing past the end", "[narl][reversed_range][pasttheend]" ) 46 | { 47 | auto r = make_test_range< reversed_range >( from( { 1 } ) ); 48 | ++r; 49 | 50 | REQUIRE( !r ); 51 | } 52 | 53 | 54 | TEST_CASE( "Reversed range can be decremented to produce previous value", "[narl][reversed_range][decrement]" ) 55 | { 56 | auto r = make_test_range< reversed_range >( from( { 1, 2, 3 } ) ); 57 | ++r; 58 | 59 | REQUIRE( *r == 2 ); 60 | --r; 61 | REQUIRE( *r == 3 ); 62 | } 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /src/tests/testnarl/test_selectmany_range.cpp: -------------------------------------------------------------------------------- 1 | #include "testnarl.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | 9 | using namespace narl; 10 | 11 | 12 | TEST_CASE( "Select many range is lazy evaluated", "[narl][selectmany][lazy]" ) 13 | { 14 | auto r = make_test_range< selectmany_range >( throwing_range< int >(), []( int ) { return from( { 2, 4, 6 } ); } ); 15 | 16 | REQUIRE_THROWS_AS( *r, range_access_exception ); 17 | REQUIRE_THROWS_AS( ++r, range_access_exception ); 18 | REQUIRE_THROWS_AS( r++, range_access_exception ); 19 | REQUIRE_THROWS_AS( --r, range_access_exception ); 20 | REQUIRE_THROWS_AS( r--, range_access_exception ); 21 | REQUIRE_THROWS_AS( r && true, range_access_exception ); 22 | } 23 | 24 | 25 | TEST_CASE( "Select many range produces all elements of inner range", "[narl][selectmany][inner]" ) 26 | { 27 | auto r = make_test_range< selectmany_range >( from( { 1, 2 } ), []( int i ) { return from( { i*2, i*3 } ); } ); 28 | 29 | REQUIRE( !!r ); 30 | REQUIRE( *r++ == 2 ); 31 | REQUIRE( *r++ == 3 ); 32 | REQUIRE( *r++ == 4 ); 33 | REQUIRE( *r++ == 6 ); 34 | REQUIRE( !r ); 35 | } 36 | 37 | 38 | TEST_CASE( "Select many range can be moved to end and decremented for last element", "[narl][selectmany][end][decrement]" ) 39 | { 40 | auto r = make_test_range< selectmany_range >( from( { 1, 2 } ), []( int i ) { return from( { i*2, i*3 } ); } ); 41 | r.goto_end(); 42 | REQUIRE( !r ); 43 | --r; 44 | REQUIRE( !!r ); 45 | REQUIRE( *r == 6 ); 46 | } 47 | 48 | 49 | TEST_CASE( "Select many range produces all elements of inner range in reverse", "[narl][selectmany][inner][reverse]" ) 50 | { 51 | auto r = make_test_range< selectmany_range >( from( { 1, 2 } ), []( int i ) { return from( { i*2, i*3 } ); } ); 52 | r.goto_end(); 53 | --r; 54 | REQUIRE( !!r ); 55 | REQUIRE( *r-- == 6 ); 56 | REQUIRE( *r-- == 4 ); 57 | REQUIRE( *r-- == 3 ); 58 | REQUIRE( *r-- == 2 ); 59 | REQUIRE( !r ); 60 | } 61 | 62 | 63 | TEST_CASE( "Select many range can be incremented from before begin for first element", "[narl][selectmany][beforebegin][increment]" ) 64 | { 65 | auto r = make_test_range< selectmany_range >( 66 | from( { 1, 2 } ), 67 | []( int i ) { return from( { i*2, i*3 } ); } ); 68 | --r; 69 | REQUIRE( !r ); 70 | ++r; 71 | REQUIRE( !!r ); 72 | REQUIRE( *r == 2 ); 73 | } 74 | 75 | 76 | #ifndef _MSC_VER2 77 | 78 | TEST_CASE( "Select many range can return elements of external vector", "[narl][selectmany][externaldata]" ) 79 | { 80 | std::vector< int > data { 'a', 'b', 'c' }; 81 | auto r = make_test_range< selectmany_range >( from( { 1, 2, 3 } ), [&data]( int ) { return from( data ); } ); 82 | 83 | REQUIRE( *r++ == data[ 0 ] ); 84 | REQUIRE( *r++ == data[ 1 ] ); 85 | REQUIRE( *r++ == data[ 2 ] ); 86 | REQUIRE( *r++ == data[ 0 ] ); 87 | REQUIRE( *r++ == data[ 1 ] ); 88 | REQUIRE( *r++ == data[ 2 ] ); 89 | REQUIRE( *r++ == data[ 0 ] ); 90 | REQUIRE( *r++ == data[ 1 ] ); 91 | REQUIRE( *r++ == data[ 2 ] ); 92 | REQUIRE( !r ); 93 | } 94 | 95 | #endif 96 | 97 | -------------------------------------------------------------------------------- /src/tests/testnarl/test_sorted_range.cpp: -------------------------------------------------------------------------------- 1 | #include "testnarl.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | 11 | using namespace narl; 12 | 13 | 14 | TEST_CASE( "Sorted range is lazily evaluated", "[narl][sorted][deferred]" ) 15 | { 16 | auto r = make_test_range< sorted_range >( throwing_range< int >{}, []( int, int ) { return true; } ); 17 | 18 | REQUIRE_THROWS_AS( ++r, range_access_exception ); 19 | REQUIRE_THROWS_AS( r++, range_access_exception ); 20 | REQUIRE_THROWS_AS( *r, range_access_exception ); 21 | REQUIRE_THROWS_AS( r && true, range_access_exception ); 22 | } 23 | 24 | 25 | TEST_CASE( "Sorted range is valid if underlying range is valid", "[narl][sorted][valid]" ) 26 | { 27 | auto r = make_test_range< sorted_range >( from( { 1 } ), []( int, int ) { return true; } ); 28 | REQUIRE( !!r ); 29 | } 30 | 31 | 32 | TEST_CASE( "Sorted range is invalid if underlying range is invalid", "[narl][sorted][invalid]" ) 33 | { 34 | auto r = make_test_range< sorted_range >( from( { 1 } ), []( int, int ) { return true; } ); 35 | REQUIRE( !++r ); 36 | } 37 | 38 | 39 | TEST_CASE( "Sorted range uses minimum calls to comparer", "[narl][sorted][efficient]" ) 40 | { 41 | int count = 0; 42 | int N = 100000; 43 | auto src = make_test_range< partial_range >( make_range< int >(), taker( N ) ); 44 | 45 | auto r = make_test_range< sorted_range >( src, [&]( int l, int r ) { return ++count, r < l; } ); 46 | 47 | REQUIRE( !!r ); 48 | REQUIRE( *r == N-1 ); 49 | 50 | #if defined _MSC_VER && defined _DEBUG 51 | REQUIRE( count < ( N * ( std::log( N ) ) ) * 3 ); 52 | #else 53 | REQUIRE( count < N * ( std::log( N ) ) ); 54 | #endif 55 | } 56 | 57 | 58 | TEST_CASE( "Sorted range can be decremented to yield previous element", "[narl][sorted][decrement]" ) 59 | { 60 | auto r = make_test_range< sorted_range >( from( { 2, 1, 0 } ), []( int l, int r ) { return l < r; } ); 61 | ++r; 62 | REQUIRE( *r-- == 1 ); 63 | REQUIRE( *r-- == 0 ); 64 | REQUIRE( !r ); 65 | } 66 | 67 | 68 | TEST_CASE( "Sorted range can be pre-decremented to yield previous element", "[narl][sorted][predecrement]" ) 69 | { 70 | auto r = make_test_range< sorted_range >( from( { 2, 1, 0 } ), []( int l, int r ) { return l < r; } ); 71 | ++r; 72 | REQUIRE( *r == 1 ); 73 | --r; 74 | REQUIRE( !!r ); 75 | REQUIRE( *r == 0 ); 76 | --r; 77 | REQUIRE( !r ); 78 | } 79 | 80 | 81 | TEST_CASE( "Sorted range is invalid when before begin", "[narl][sorted][pastbegin]" ) 82 | { 83 | auto r = make_test_range< sorted_range >( from( { 1 } ), []( int l, int r ) { return l < r; } ); 84 | --r; 85 | REQUIRE( !r ); 86 | ++r; 87 | REQUIRE( !!r ); 88 | } 89 | 90 | 91 | TEST_CASE( "Sorted range can be moved to the end", "[narl][sorted][goto_end]" ) 92 | { 93 | auto r = make_test_range< sorted_range >( from( { 1, 2 } ), []( int l, int r ) { return l < r; } ); 94 | r.goto_end(); 95 | REQUIRE( !r ); 96 | } 97 | 98 | 99 | TEST_CASE( "Sorted range becomes valid after decrement from the end", "[narl][sorted][decrement_from_end]" ) 100 | { 101 | auto r = make_test_range< sorted_range >( from( { 1, 2 } ), []( int l, int r ) { return l < r; } ); 102 | r.goto_end(); 103 | REQUIRE( !r-- ); 104 | REQUIRE( !!r ); 105 | REQUIRE( *r == 2 ); 106 | } 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /src/tests/testnarl/test_tocontainer_range.cpp: -------------------------------------------------------------------------------- 1 | #include "testnarl.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | using namespace narl; 14 | 15 | 16 | TEST_CASE( "To container range creates a vector", "[narl][to_container][vector]" ) 17 | { 18 | auto r = from( { 1, 2, 3 } ); 19 | auto c = to_container< std::vector >()( r ); 20 | 21 | for( auto i : c ) 22 | { 23 | REQUIRE( i == *r++ ); 24 | } 25 | REQUIRE( !r ); 26 | } 27 | 28 | 29 | TEST_CASE( "To container range creates a list", "[narl][to_container][list]" ) 30 | { 31 | auto r = from( { 1, 2, 3 } ); 32 | auto c = to_container< std::list >()( r ); 33 | 34 | for( auto i : c ) 35 | { 36 | REQUIRE( i == *r++ ); 37 | } 38 | REQUIRE( !r ); 39 | } 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/tests/testnarl/test_transforming_range.cpp: -------------------------------------------------------------------------------- 1 | #include "testnarl.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | 9 | using namespace narl; 10 | 11 | 12 | TEST_CASE( "Transforming range is evaluated lazily", "[narl][transforming_range][deferred]" ) 13 | { 14 | auto r = make_test_range< transforming_range >( throwing_range< int >{}, []( int ) { return 0; } ); 15 | 16 | REQUIRE_THROWS_AS( ++r, range_access_exception ); 17 | REQUIRE_THROWS_AS( r++, range_access_exception ); 18 | REQUIRE_THROWS_AS( *r, range_access_exception ); 19 | REQUIRE_THROWS_AS( r && true, range_access_exception ); 20 | } 21 | 22 | 23 | TEST_CASE( "Transforming range dereference leaves original value intact", "[narl][transforming_range][dereference]" ) 24 | { 25 | int src[] = { 1 }; 26 | auto r = make_test_range< transforming_range >( src, []( int i ) { return i * 2; } ); 27 | 28 | REQUIRE( *r == 2 ); 29 | REQUIRE( src[ 0 ] == 1 ); 30 | } 31 | 32 | 33 | TEST_CASE( "Incrementing Transforming range leaves underlying range unchanged", "[narl][transforming_range][increment]" ) 34 | { 35 | int src[] = { 5 }; 36 | auto u = from( src ); 37 | auto r = make_test_range< transforming_range >( src, []( int i ) { return i * 10; } ); 38 | 39 | REQUIRE( *r++ == 50 ); 40 | REQUIRE( !!u ); 41 | REQUIRE( *u == 5 ); 42 | } 43 | 44 | 45 | TEST_CASE( "Transforming range becomes invalid if incremented past the end", "[narl][transforming_range][invalidation][preinc]" ) 46 | { 47 | auto r = make_test_range< transforming_range >( from( { 1 } ), []( int i ) { return i * 10; } ); 48 | REQUIRE( !!r ); 49 | ++r; 50 | REQUIRE( !r ); 51 | } 52 | 53 | 54 | TEST_CASE( "Transforming range becomes invalid if post-incremented past the end", "[narl][transforming_range][invalidation][postinc]" ) 55 | { 56 | auto r = make_test_range< transforming_range >( from( { 1 } ), []( int i ) { return i * 10; } ); 57 | REQUIRE( !!r ); 58 | r++; 59 | REQUIRE( !r ); 60 | } 61 | 62 | 63 | TEST_CASE( "Transforming range can be decremented to yield previous value", "[narl][transforming_range][decrement]" ) 64 | { 65 | auto r = make_test_range< transforming_range >( from( { 1, 2 } ), []( int i ) { return i * 10; } ); 66 | ++r; 67 | REQUIRE( *r-- == 20 ); 68 | REQUIRE( *r-- == 10 ); 69 | REQUIRE( !r ); 70 | } 71 | 72 | 73 | 74 | TEST_CASE( "Transforming range can be pre-decremented to yield previous value", "[narl][transforming_range][pre-decrement]" ) 75 | { 76 | auto r = make_test_range< transforming_range >( from( { 1, 2 } ), []( int i ) { return i * 10; } ); 77 | ++r; 78 | --r; 79 | REQUIRE( *r == 10 ); 80 | } 81 | 82 | 83 | TEST_CASE( "Transforming range is invalid when before begin", "[narl][transforming_range][pastbegin]" ) 84 | { 85 | auto r = make_test_range< transforming_range >( from( { 1, 2 } ), []( int i ) { return i * 10; } ); 86 | --r; 87 | REQUIRE( !r ); 88 | ++r; 89 | REQUIRE( !!r ); 90 | REQUIRE( *r == 10 ); 91 | } 92 | 93 | 94 | TEST_CASE( "Transforming range can be moved to the end", "[narl][transforming_range][goto_end]" ) 95 | { 96 | auto r = make_test_range< transforming_range >( from( { 1, 2 } ), []( int i ) { return i * 10; } ); 97 | r.goto_end(); 98 | REQUIRE( !r ); 99 | --r; 100 | REQUIRE( !!r ); 101 | } 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /src/tests/testnarl/test_zipped_range.cpp: -------------------------------------------------------------------------------- 1 | #include "testnarl.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | 9 | using namespace narl; 10 | 11 | 12 | TEST_CASE( "Zipping range of 2 is evaluated lazily", "[narl][zipped][lazy][2]" ) 13 | { 14 | auto r = make_test_range< zipping_range >( throwing_range< int >{}, from( { 1 } ) ); 15 | 16 | REQUIRE_THROWS_AS( ++r, range_access_exception ); 17 | REQUIRE_THROWS_AS( r++, range_access_exception ); 18 | REQUIRE_THROWS_AS( *r, range_access_exception ); 19 | REQUIRE_THROWS_AS( r && true, range_access_exception ); 20 | } 21 | 22 | #ifndef _MSC_VER 23 | 24 | TEST_CASE( "Zipping range of 3 is evaluated lazily", "[narl][zipped][lazy][3]" ) 25 | { 26 | auto r = make_test_range< zipping_range >( throwing_range< int >{}, from( { 2 } ), from( { 1 } ) ); 27 | 28 | REQUIRE_THROWS_AS( ++r, range_access_exception ); 29 | REQUIRE_THROWS_AS( r++, range_access_exception ); 30 | REQUIRE_THROWS_AS( *r, range_access_exception ); 31 | REQUIRE_THROWS_AS( r && true, range_access_exception ); 32 | } 33 | 34 | 35 | TEST_CASE( "Zipping range of 4 is evaluated lazily", "[narl][zipped][lazy][4]" ) 36 | { 37 | auto r = make_test_range< zipping_range >( throwing_range< int >{}, from( { 2 } ), from( { 1 } ), from( { 1 } ) ); 38 | 39 | REQUIRE_THROWS_AS( ++r, range_access_exception ); 40 | REQUIRE_THROWS_AS( r++, range_access_exception ); 41 | REQUIRE_THROWS_AS( *r, range_access_exception ); 42 | REQUIRE_THROWS_AS( r && true, range_access_exception ); 43 | } 44 | 45 | #endif 46 | 47 | TEST_CASE( "Zipping range of 2 produces tuple of each element in turn", "[narl][zipped][2]" ) 48 | { 49 | auto r = make_test_range< zipping_range >( from( { 1, 2, 3 } ), from( { 10, 20, 30 } ) ); 50 | 51 | REQUIRE( *r++ == std::make_tuple( 1, 10 ) ); 52 | REQUIRE( *r++ == std::make_tuple( 2, 20 ) ); 53 | REQUIRE( *r++ == std::make_tuple( 3, 30 ) ); 54 | 55 | REQUIRE( !r ); 56 | } 57 | 58 | 59 | TEST_CASE( "Zipping range of 2 can be decremented", "[narl][zipped][2][decrement]" ) 60 | { 61 | auto r = make_test_range< zipping_range >( from( { 1, 2, 3 } ), from( { 10, 20, 30 } ) ); 62 | 63 | ++r; 64 | REQUIRE( *r-- == std::make_tuple( 2, 20 ) ); 65 | REQUIRE( *r-- == std::make_tuple( 1, 10 ) ); 66 | 67 | REQUIRE( !r ); 68 | } 69 | 70 | 71 | TEST_CASE( "Zipping range of 2 can be pre-decremented", "[narl][zipped][2][predecrement]" ) 72 | { 73 | auto r = make_test_range< zipping_range >( from( { 1, 2, 3 } ), from( { 10, 20, 30 } ) ); 74 | 75 | ++r; 76 | --r; 77 | REQUIRE( *r == std::make_tuple( 1, 10 ) ); 78 | 79 | --r; 80 | REQUIRE( !r ); 81 | 82 | ++r; 83 | REQUIRE( !!r ); 84 | } 85 | 86 | 87 | TEST_CASE( "Zipping range of 2 can be moved to end and decremented", "[narl][zipped][2][goto_end][decrement]" ) 88 | { 89 | auto r = make_test_range< zipping_range >( from( { 1, 2, 3 } ), from( { 10, 20, 30 } ) ); 90 | 91 | r.goto_end(); 92 | REQUIRE( !r-- ); 93 | 94 | REQUIRE( *r == std::make_tuple( 3, 30 ) ); 95 | } 96 | 97 | 98 | TEST_CASE( "Zipping range of 2 with different lengths is invalid at end of shortest", "[narl][zipped][2][shorteest]" ) 99 | { 100 | auto r = make_test_range< zipping_range >( from( { 1, 2, 3 } ), from( { 10, 30 } ) ); 101 | 102 | ++r; 103 | ++r; 104 | REQUIRE( !r ); 105 | } 106 | 107 | 108 | TEST_CASE( "Zipping range of 2 with different lengths is invalid at end of shortest in 1st", "[narl][zipped][2][shorteest][first]" ) 109 | { 110 | auto r = make_test_range< zipping_range >( from( { 1, 3 } ), from( { 10, 20, 30 } ) ); 111 | 112 | ++r; 113 | ++r; 114 | REQUIRE( !r ); 115 | } 116 | 117 | #ifndef _MSC_VER 118 | 119 | TEST_CASE( "Zipping range of 3 produces tuple of each element in turn", "[narl][zipped][3]" ) 120 | { 121 | auto r = make_test_range< zipping_range >( from( { 1, 2, 3 } ), from( { 10, 20, 30 } ), from( { 100, 200, 300 } ) ); 122 | 123 | REQUIRE( *r++ == std::make_tuple( 1, 10, 100 ) ); 124 | REQUIRE( *r++ == std::make_tuple( 2, 20, 200 ) ); 125 | REQUIRE( *r++ == std::make_tuple( 3, 30, 300 ) ); 126 | 127 | REQUIRE( !r ); 128 | } 129 | 130 | 131 | TEST_CASE( "Zipping range of 3 can be decremented", "[narl][zipped][3][decrement]" ) 132 | { 133 | auto r = make_test_range< zipping_range >( from( { 1, 2, 3 } ), from( { 10, 20, 30 } ), from( { 100, 200, 300 } ) ); 134 | 135 | ++r; 136 | REQUIRE( *r-- == std::make_tuple( 2, 20, 200 ) ); 137 | REQUIRE( *r-- == std::make_tuple( 1, 10, 100 ) ); 138 | 139 | REQUIRE( !r ); 140 | } 141 | 142 | 143 | TEST_CASE( "Zipping range of 3 can be pre-decremented", "[narl][zipped][3][predecrement]" ) 144 | { 145 | auto r = make_test_range< zipping_range >( from( { 1, 2, 3 } ), from( { 10, 20, 30 } ), from( { 100, 200, 300 } ) ); 146 | 147 | ++r; 148 | REQUIRE( *r == std::make_tuple( 2, 20, 200 ) ); 149 | --r; 150 | REQUIRE( *r == std::make_tuple( 1, 10, 100 ) ); 151 | 152 | --r; 153 | REQUIRE( !r ); 154 | 155 | ++r; 156 | REQUIRE( !!r ); 157 | } 158 | 159 | 160 | TEST_CASE( "Zipping range of 3 can be moved to end and decremented", "[narl][zipped][3][goto_end][decrement]" ) 161 | { 162 | auto r = make_test_range< zipping_range >( from( { 1, 2, 3 } ), from( { 10, 20, 30 } ), from( { 100, 200, 300 } ) ); 163 | 164 | r.goto_end(); 165 | REQUIRE( !r-- ); 166 | 167 | REQUIRE( *r == std::make_tuple( 3, 30, 300 ) ); 168 | } 169 | 170 | 171 | TEST_CASE( "Zipping range of 3 with different lengths is invalid at end of shortest in 1st", "[narl][zipped][3][shorteest][first]" ) 172 | { 173 | auto r = make_test_range< zipping_range >( from( { 1, 2 } ), from( { 10, 20, 30 } ), from( { 100, 200, 300 } ) ); 174 | 175 | ++r; 176 | ++r; 177 | REQUIRE( !r ); 178 | } 179 | 180 | 181 | 182 | TEST_CASE( "Zipping range of 3 with different lengths is invalid at end of shortest in 2nd", "[narl][zipped][3][shorteest][second]" ) 183 | { 184 | auto r = make_test_range< zipping_range >( from( { 1, 2, 3 } ), from( { 10, 30 } ), from( { 100, 200, 300 } ) ); 185 | 186 | ++r; 187 | ++r; 188 | REQUIRE( !r ); 189 | } 190 | 191 | 192 | 193 | TEST_CASE( "Zipping range of 3 with different lengths is invalid at end of shortest in last", "[narl][zipped][3][shorteest][last]" ) 194 | { 195 | auto r = make_test_range< zipping_range >( from( { 1, 2, 3 } ), from( { 10, 20, 30 } ), from( { 100, 200 } ) ); 196 | 197 | ++r; 198 | ++r; 199 | REQUIRE( !r ); 200 | } 201 | 202 | #endif 203 | 204 | -------------------------------------------------------------------------------- /src/tests/testnarl/testnarl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include "throwing_range.h" 5 | 6 | 7 | template< template< typename > class range_type, typename under_range_type > 8 | auto make_test_range( under_range_type r ) -> range_type< under_range_type > 9 | { 10 | return range_type< under_range_type >{ r }; 11 | } 12 | 13 | 14 | template< template< typename... > class range_type, typename under_range_type, typename... predicate > 15 | auto make_test_range( under_range_type r, predicate... filter ) -> range_type< under_range_type, predicate... > 16 | { 17 | return range_type< under_range_type, predicate... >{ r, filter... }; 18 | } 19 | 20 | 21 | #ifdef _MSC_VER 22 | 23 | template< template< typename, typename, typename > class range_type, typename under_range_type, typename other_range_type, typename comparer > 24 | auto make_test_range( under_range_type r, other_range_type o, comparer cmp ) -> range_type< under_range_type, other_range_type, comparer > 25 | { 26 | return range_type< under_range_type, other_range_type, comparer >{ r, o, cmp }; 27 | } 28 | 29 | template< template< typename, typename, typename, typename, typename > class range_type, typename under_range_type, typename other_range_type, typename inner_key, typename outer_key, typename selector > 30 | auto make_test_range( under_range_type r, other_range_type o, inner_key inner, outer_key outer, selector trans ) -> range_type< under_range_type, other_range_type, inner_key, outer_key, selector > 31 | { 32 | return range_type< under_range_type, other_range_type, inner_key, outer_key, selector >{ r, o, inner, outer, trans }; 33 | } 34 | 35 | template< template< typename, typename, typename, typename, typename, typename > class range_type, typename under_range_type, typename other_range_type, typename inner_key, typename outer_key, typename selector, typename comparer > 36 | auto make_test_range( under_range_type r, other_range_type o, inner_key inner, outer_key outer, selector trans, comparer cmp ) -> range_type< under_range_type, other_range_type, inner_key, outer_key, selector, comparer > 37 | { 38 | return range_type< under_range_type, other_range_type, inner_key, outer_key, selector, comparer >{ r, o, inner, outer, trans, cmp }; 39 | } 40 | 41 | #endif -------------------------------------------------------------------------------- /src/tests/testnarl/testnarlspeed.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace boost::adaptors; 10 | 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | 24 | const int N = 1000000; 25 | const size_t tries_for_avg = 3; 26 | 27 | 28 | template< template< typename... > class container_type, typename left_range_type, typename right_range_type > 29 | size_t std_intersect_full( left_range_type left, right_range_type right ) 30 | { 31 | container_type< int > output; 32 | std::set_intersection( begin( left ), end( left ), begin( right ), end( right ), 33 | std::inserter( output, output.end() ) ); 34 | return output.size(); 35 | } 36 | 37 | template< template< typename... > class container_type, typename item_type > 38 | size_t std_intersect_full( const container_type< item_type > & left, const container_type< item_type > & right ) 39 | { 40 | container_type< int > output; 41 | std::set_intersection( left.begin() , left.end(), right.begin(), right.end(), 42 | std::inserter( output, output.end() ) ); 43 | return output.size(); 44 | } 45 | 46 | 47 | template< template< typename... > class container_type, typename item_type > 48 | size_t boost_intersect_full( const container_type< item_type > & left, const container_type< item_type > & right ) 49 | { 50 | container_type< int > output; 51 | boost::set_intersection( left, right, 52 | std::inserter( output, output.end() ) ); 53 | return output.size(); 54 | } 55 | 56 | 57 | template< template< typename... > class container_type, typename left_range_type, typename right_range_type > 58 | size_t std_union_full( left_range_type left, right_range_type right ) 59 | { 60 | container_type< int > output; 61 | std::set_union( begin( left ), end( left ), begin( right ), end( right ), 62 | std::inserter( output, output.end() ) ); 63 | return output.size(); 64 | } 65 | 66 | template< template< typename... > class container_type, typename item_type > 67 | size_t std_union_full( const container_type< item_type > & left, const container_type< item_type > & right ) 68 | { 69 | container_type< int > output; 70 | std::set_union( left.begin() , left.end(), right.begin(), right.end(), 71 | std::inserter( output, output.end() ) ); 72 | return output.size(); 73 | } 74 | 75 | template< template< typename... > class container_type, typename left_range_type, typename right_range_type > 76 | size_t std_diff_full( left_range_type left, right_range_type right ) 77 | { 78 | container_type< int > output; 79 | std::set_difference( begin( left ), end( left ), begin( right ), end( right ), 80 | std::inserter( output, output.end() ) ); 81 | return output.size(); 82 | } 83 | 84 | template< template< typename... > class container_type, typename item_type > 85 | size_t std_diff_full( const container_type< item_type > & left, const container_type< item_type > & right ) 86 | { 87 | container_type< int > output; 88 | std::set_difference( left.begin() , left.end(), right.begin(), right.end(), 89 | std::inserter( output, output.end() ) ); 90 | return output.size(); 91 | } 92 | 93 | 94 | template< template< typename... > class container_type, typename item_type > 95 | size_t std_search_replace( container_type< item_type > items ) 96 | { 97 | std::vector< double > result; 98 | 99 | std::transform( items.begin(), std::partition( items.begin(), items.end(), 100 | []( const item_type & v ) { return v > 0.0; } ), 101 | std::inserter( result, result.end() ), 102 | []( const item_type & v ) { return v + v * 0.175; } ); 103 | 104 | return result.size(); 105 | } 106 | 107 | template< template< typename... > class container_type, typename item_type > 108 | size_t boost_search_replace( const container_type< item_type > & items ) 109 | { 110 | std::vector< double > result; 111 | boost::push_back( result, items 112 | | filtered( []( const item_type & v ) { return v > 0.0; } ) 113 | | transformed( []( const item_type & v ) { return v + v * 0.175; } ) 114 | ); 115 | return result.size(); 116 | } 117 | 118 | 119 | template< typename fn > 120 | auto time_avg( fn f, size_t tries ) -> std::tuple< size_t, std::chrono::milliseconds > 121 | { 122 | size_t result; 123 | 124 | std::chrono::milliseconds cumulation { 0 }; 125 | for( auto i : narl::make_range< int >() | narl::take( tries ) ) 126 | { 127 | auto start = std::chrono::high_resolution_clock::now(); 128 | result = f(); 129 | auto end = std::chrono::high_resolution_clock::now(); 130 | auto res = std::chrono::duration_cast< std::chrono::milliseconds >( end - start ); 131 | 132 | cumulation = ( cumulation * i + res ) / ( i + 1 ); 133 | } 134 | 135 | return std::make_tuple( result, cumulation ); 136 | } 137 | 138 | template< typename range > 139 | void print_tests( const char * const testname, const range & items ) 140 | { 141 | std::cout << testname << " : " << N << " items" << std::endl; 142 | for( auto test : items ) 143 | { 144 | auto name = std::get< 0 >( test ); 145 | auto fn = std::get< 1 >( test ); 146 | 147 | std::cout << " " << std::setw( 35 ) << std::left << name << ":" << std::right; 148 | auto result = time_avg( fn, tries_for_avg ); 149 | 150 | auto count = std::get< 0 >( result ); 151 | auto ms = std::get< 1 >( result ); 152 | std::cout << std::setw( 10 ) << count << " items in " << std::setw( 6 ) << ms.count() << " ms" << std::endl; 153 | } 154 | std::cout << std::endl; 155 | } 156 | 157 | 158 | template< template< typename... > class container_type > 159 | void run_select_tests( const char * const testname ) 160 | { 161 | using namespace narl; 162 | 163 | auto srv = make_range< int >() | select( []( int i ) { return i % 4 != 0 ? i * 2.3 : -( i * 3.2 ); } ) | take( N ); 164 | auto srv_c = srv | to< container_type >(); 165 | 166 | auto set_names = { 167 | "std search/replace", 168 | "boost search/replace", 169 | "narl search/replace", 170 | "narl search/replace range", 171 | }; 172 | std::initializer_list< std::function< size_t() > > set_tests = { 173 | [&] { return std_search_replace( srv_c ); }, 174 | [&] { return boost_search_replace( srv_c ); }, 175 | [&] { return from( srv_c ) | where( []( double v ) { return v > 0.0; } ) | select( []( double v ) { return v + v * 0.175; } ) | count(); }, 176 | [&] { return srv | where( []( double v ) { return v > 0.0; } ) | select( []( double v ) { return v + v * 0.175; } ) | count(); }, 177 | }; 178 | 179 | print_tests( testname, from( set_names ) | zipwith( from( set_tests ) ) ); 180 | } 181 | 182 | 183 | template< template< typename ... > class container_type > 184 | void run_set_tests( const char * const testname ) 185 | { 186 | using namespace narl; 187 | 188 | auto s = make_range< int > () | where( []( int i ) { return i % 3 == 0; } ) | take( N ); 189 | auto o = make_range< int > () | where( []( int i ) { return i % 5 == 0; } ) | take( N ); 190 | 191 | auto left_c = s | to< container_type >(); 192 | auto right_c = o | to< container_type >(); 193 | 194 | auto set_test_names = { 195 | "std diff extract", 196 | "nrl diff extract", 197 | "nrl diff count", 198 | "std diff collection", 199 | "nrl diff collection", 200 | "nrl diff collection count", 201 | "std intersect extract", 202 | "nrl intersect extract", 203 | "nrl intersect count", 204 | "std intersect collection", 205 | "nrl intersect collection", 206 | "nrl intersect collection count", 207 | "std union extract", 208 | "nrl union extract", 209 | "nrl union count", 210 | "std union collection", 211 | "nrl union collection", 212 | "nrl union collection count", 213 | }; 214 | 215 | typedef std::function< size_t() > test_fn; 216 | std::initializer_list< test_fn > set_tests = { 217 | [&]{ return std_diff_full< container_type >( s, o ); }, 218 | //[&]{ return ( s | except( o ) | to< container_type >() ).size(); }, 219 | [&]{ auto r = s | except( o ); size_t count = 0; for( auto i : r ) { ++count; }; return count; }, 220 | [&]{ return s | except( o ) | narl::count(); }, 221 | [&]{ return std_diff_full< container_type, int >( left_c, right_c ); }, 222 | [&]{ return ( from( left_c ) | except( from( right_c ) ) | to< container_type >() ).size(); }, 223 | [&]{ return from( left_c ) | except( from( right_c ) ) | narl::count(); }, 224 | [&]{ return std_intersect_full< container_type >( s, o ); }, 225 | [&]{ return ( s | intersect_with( o ) | to< container_type >() ).size(); }, 226 | [&]{ return s | intersect_with( o ) | narl::count(); }, 227 | [&]{ return std_intersect_full< container_type, int >( left_c, right_c ); }, 228 | [&]{ return ( from( left_c ) | intersect_with( from( right_c ) ) | to< container_type >() ).size(); }, 229 | [&]{ return from( left_c ) | intersect_with( from( right_c ) ) | count(); }, 230 | [&]{ return std_union_full< container_type >( s, o ); }, 231 | [&]{ return ( s | union_with( o ) | to< container_type >() ).size(); }, 232 | [&]{ return s | union_with( o ) | count(); }, 233 | [&]{ return std_union_full< container_type, int >( left_c, right_c ); }, 234 | [&]{ return ( from( left_c ) | union_with( from( right_c ) ) | to< container_type >() ).size(); }, 235 | [&]{ return from( left_c ) | union_with( from( right_c ) ) | count(); }, 236 | }; 237 | 238 | print_tests( testname, from( set_test_names ) | zipwith( from( set_tests ) ) ); 239 | } 240 | 241 | int main() 242 | { 243 | #ifndef _MSC_VER 244 | run_set_tests< std::set > ( "std::set" ); 245 | #endif 246 | run_set_tests< std::vector >( "std::vector" ); 247 | run_select_tests< std::list >( "std::list" ); 248 | run_select_tests< std::vector >( "std::vector" ); 249 | run_select_tests< std::deque >( "std::deque" ); 250 | 251 | return 0; 252 | } 253 | -------------------------------------------------------------------------------- /src/tests/testnarl/throwing_range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | 7 | class range_access_exception : public std::logic_error 8 | { 9 | public: 10 | range_access_exception( const std::string & what ) : std::logic_error{ what } { } 11 | }; 12 | 13 | 14 | template< typename T > 15 | struct throwing_range 16 | { 17 | throwing_range() { } 18 | throwing_range( const throwing_range & ) { } 19 | 20 | auto operator++() -> throwing_range & { throw range_access_exception( "Preincrement" ); } 21 | auto operator++( int ) -> throwing_range { throw range_access_exception( "Postincrement" ); } 22 | auto operator--() -> throwing_range & { throw range_access_exception( "Predecrement" ); } 23 | auto operator--( int ) -> throwing_range { throw range_access_exception( "Postdecrement" ); } 24 | auto operator*() const -> T { throw range_access_exception( "Expression evaluation" ); } 25 | explicit operator bool() const { throw range_access_exception( "Validity" ); } 26 | void goto_end() { throw range_access_exception( "GotoEnd" ); } 27 | }; 28 | 29 | --------------------------------------------------------------------------------