├── .github └── workflows │ └── boolinq-test.yml ├── .gitignore ├── .gitmodules ├── .travis.yml ├── CMakeLists.txt ├── LICENSE ├── README.md ├── bench ├── CMakeLists.txt └── SpeedTest.cpp ├── include └── boolinq │ └── boolinq.h └── test ├── AllTest.cpp ├── AnyTest.cpp ├── AppendTest.cpp ├── AvgTest.cpp ├── BitsTest.cpp ├── BytesTest.cpp ├── CMakeLists.txt ├── CommonTests.h ├── ConcatTest.cpp ├── ContainsTest.cpp ├── CountTest.cpp ├── CtorTest.cpp ├── DistinctTest.cpp ├── DotCallTest.cpp ├── ElementAtTest.cpp ├── FirstTest.cpp ├── ForEachTest.cpp ├── GroupByTest.cpp ├── GroupByTestComplex.cpp ├── LastTest.cpp ├── LinqTest.cpp ├── MaxTest.cpp ├── MinTest.cpp ├── OrderByTest.cpp ├── PrependTest.cpp ├── RangeTest.cpp ├── ReverseTest.cpp ├── SelectManyTest.cpp ├── SelectTest.cpp ├── SkipTest.cpp ├── SkipWhileTest.cpp ├── SumTest.cpp ├── TakeTest.cpp ├── TakeWhileTest.cpp ├── ToStdDequeTest.cpp ├── ToStdListTest.cpp ├── ToStdSetTest.cpp ├── ToStdVectorTest.cpp ├── UnbitsTest.cpp ├── UnbytesTest.cpp ├── WhereTest.cpp └── main.cpp /.github/workflows/boolinq-test.yml: -------------------------------------------------------------------------------- 1 | name: 'Boolinq Test: All' 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | 8 | jobs: 9 | boolinq-test: 10 | strategy: 11 | matrix: 12 | cpp_version: [11, 14, 17, 20] 13 | compiler: [ {cpp: g++-9, c: gcc-9}, {cpp: g++-10, c: gcc-10}, {cpp: clang++-10, c: clang-10}, {cpp: clang++-11, c: clang-11}, {cpp: clang++-12, c: clang-12} ] 14 | runs-on: "ubuntu-20.04" 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v3 18 | with: 19 | submodules: true 20 | 21 | - name: Compilation 22 | env: 23 | CC: ${{ matrix.compiler.c }} 24 | CXX: ${{ matrix.compiler.cpp }} 25 | run: | 26 | mkdir build && cd build 27 | cmake .. -DWITH_CXX_STANDARD=${{ matrix.cpp_version }} 28 | make 29 | 30 | - name: Boolinq-test 31 | run: | 32 | cd build 33 | ./test/boolinq-test 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Debug 2 | Release 3 | ipch 4 | *.opensdf 5 | *.sdf 6 | *.user 7 | *.suo 8 | [Bb]uild* 9 | nbproject 10 | .idea 11 | cmake-build-debug 12 | CMakeCache.txt 13 | CMakeFiles/ 14 | DartConfiguration.tcl 15 | CTestTestfile.cmake 16 | Makefile 17 | Testing/ 18 | cmake_install.cmake 19 | boolinq-bench 20 | boolinq-test 21 | /externals/benchmark/* 22 | /externals/googletest/* 23 | cppcheck.report 24 | coverage/ 25 | coverage.info 26 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "externals/googletest"] 2 | path = externals/googletest 3 | url = https://github.com/google/googletest.git 4 | [submodule "externals/benchmark"] 5 | path = externals/benchmark 6 | url = https://github.com/google/benchmark.git 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: none 2 | sudo: false 3 | 4 | cache: 5 | apt: true 6 | directories: 7 | - /tmp/tools 8 | 9 | env: 10 | global: 11 | - PATH="$HOME/bin:$PATH" 12 | - CMAKE_VERSION_PREFIX=3.22 13 | - CMAKE_VERSION_FULL=3.22.1 14 | 15 | matrix: 16 | include: 17 | - env: CXX=g++-5 CC=gcc-5 GCOV=gcov-5 18 | addons: 19 | apt: 20 | packages: 21 | - g++-5 22 | sources: &sources 23 | - ubuntu-toolchain-r-test 24 | - llvm-toolchain-precise-3.8 25 | - env: CXX=g++-6 CC=gcc-6 GCOV=gcov-6 26 | addons: 27 | apt: 28 | packages: 29 | - g++-6 30 | sources: &sources 31 | - ubuntu-toolchain-r-test 32 | - llvm-toolchain-precise-3.8 33 | - env: CXX=g++-7 CC=gcc-7 GCOV=gcov-7 34 | addons: 35 | apt: 36 | packages: 37 | - g++-7 38 | sources: &sources 39 | - ubuntu-toolchain-r-test 40 | - llvm-toolchain-precise-3.8 41 | - env: CXX=g++-8 CC=gcc-8 GCOV=gcov-8 42 | addons: 43 | apt: 44 | packages: 45 | - g++-8 46 | sources: &sources 47 | - ubuntu-toolchain-r-test 48 | - llvm-toolchain-precise-3.8 49 | - env: CXX=g++-9 CC=gcc-9 GCOV=gcov-9 50 | addons: 51 | apt: 52 | packages: 53 | - g++-9 54 | sources: &sources 55 | - ubuntu-toolchain-r-test 56 | - llvm-toolchain-precise-3.8 57 | - env: CXX=clang++-3.8 CC=clang-3.8 GCOV=gcov 58 | addons: 59 | apt: 60 | packages: 61 | - clang-3.8 62 | sources: *sources 63 | 64 | before_install: 65 | - pip install --user cpp-coveralls 66 | 67 | install: 68 | - mkdir -p /tmp/tools 69 | - pushd /tmp/tools 70 | - if [[ ! -f "cmake-$CMAKE_VERSION_FULL-linux-x86_64.sh" ]]; then 71 | curl -SOL "https://github.com/Kitware/CMake/releases/download/v$CMAKE_VERSION_FULL/cmake-$CMAKE_VERSION_FULL-linux-x86_64.sh"; 72 | chmod +x "cmake-$CMAKE_VERSION_FULL-linux-x86_64.sh"; 73 | fi 74 | - ./"cmake-$CMAKE_VERSION_FULL-linux-x86_64.sh" --prefix="$HOME" --exclude-subdir --skip-license 75 | - popd 76 | 77 | script: 78 | - mkdir build 79 | - cd build 80 | - cmake .. && make 81 | - ./test/boolinq-test 82 | - ./test/boolinq-test14 83 | - ./bench/boolinq-bench 84 | 85 | after_success: 86 | - case "$CC" in 87 | clang-*) 88 | echo "Processing llvm coverage with llvm-cov, bypass gcov in cpp-coveralls and submitting"; 89 | find test/CMakeFiles/boolinq-test.dir/ -name '*.cpp.o' | xargs llvm-cov gcov -lp ; 90 | coveralls --root .. --include include --no-gcov --verbose 91 | ;; 92 | *) 93 | echo "Processing with gcov in cpp-coveralls and submitting"; 94 | coveralls --root .. --include include --gcov-options '\-lp' --gcov $GCOV --verbose 95 | ;; 96 | esac 97 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Common variables. 2 | CMAKE_MINIMUM_REQUIRED (VERSION 3.0) 3 | PROJECT (boolinq VERSION 3.0.0 LANGUAGES CXX) 4 | INCLUDE(Dart) 5 | 6 | SET (WITH_CXX_STANDARD 11 CACHE STRING "Version of the C++ Standard For Boolinq") 7 | 8 | SET (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -O0 -ggdb3 -DDEBUG") 9 | SET (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -O3") 10 | 11 | 12 | # Static code analyse. 13 | SET (CppCheck_REPORT ${PROJECT_BINARY_DIR}/cppcheck.report) 14 | ADD_CUSTOM_COMMAND ( 15 | OUTPUT ${CppCheck_REPORT} 16 | COMMAND cppcheck ${PROJECT_SOURCE_DIR}/imclude/boolinq/boolinq.h --enable=all --force --inconclusive &>cppcheck.report 17 | ) 18 | ADD_CUSTOM_TARGET (cppcheck DEPENDS ${CppCheck_REPORT}) 19 | SET_DIRECTORY_PROPERTIES (PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES ${CppCheck_REPORT}) 20 | 21 | 22 | # Testing. 23 | ADD_SUBDIRECTORY (externals/googletest) 24 | ADD_SUBDIRECTORY (externals/benchmark) 25 | ADD_SUBDIRECTORY (test) 26 | ADD_SUBDIRECTORY (bench) 27 | ADD_DEPENDENCIES ("${PROJECT_NAME}-test" gtest) 28 | ADD_DEPENDENCIES ("${PROJECT_NAME}-test14" gtest) 29 | ADD_DEPENDENCIES ("${PROJECT_NAME}-bench" benchmark) 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2019 by Anton Bukov (k06aaa@gmail.com) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # boolinq 3.0 2 | 3 | [![CI Status](https://travis-ci.com/k06a/boolinq.svg?branch=master)](https://app.travis-ci.com/github/k06a/boolinq) 4 | [![Coverage Status](https://coveralls.io/repos/github/k06a/boolinq/badge.svg?branch=master)](https://coveralls.io/github/k06a/boolinq?branch=master) 5 | 6 | Super tiny C++11 single-file header-only LINQ template library 7 | 8 | Just imagine .NET Framework LINQ support for STL/Qt collections :) 9 | 10 | Get source code here: **[boolinq.h](/include/boolinq/boolinq.h)** 11 | 12 | ## Wanna demo? 13 | 14 | #### Example with integers 15 | 16 | ```C++ 17 | int src[] = {1,2,3,4,5,6,7,8}; 18 | auto dst = from(src).where( [](int a) { return a % 2 == 1; }) // 1,3,5,7 19 | .select([](int a) { return a * 2; }) // 2,6,10,14 20 | .where( [](int a) { return a > 2 && a < 12; }) // 6,10 21 | .toStdVector(); 22 | 23 | // dst type: std::vector 24 | // dst items: 6,10 25 | ``` 26 | 27 | #### Example with structs 28 | 29 | ```C++ 30 | struct Man { 31 | std::string name; 32 | int age; 33 | }; 34 | 35 | Man src[] = { 36 | {"Kevin",14}, 37 | {"Anton",18}, 38 | {"Agata",17}, 39 | {"Terra",20}, 40 | {"Layer",15}, 41 | }; 42 | 43 | auto dst = from(src).where( [](const Man & man) { return man.age < 18; }) 44 | .orderBy([](const Man & man) { return man.age; }) 45 | .select( [](const Man & man) { return man.name; }) 46 | .toStdVector(); 47 | 48 | // dst type: std::vector 49 | // dst items: "Kevin", "Layer", "Agata" 50 | ``` 51 | 52 | #### Interesting example 53 | 54 | ```C++ 55 | struct Message { 56 | std::string PhoneA; 57 | std::string PhoneB; 58 | std::string Text; 59 | }; 60 | 61 | Message messages[] = { 62 | {"Anton","Troll","Hello, friend!"}, 63 | {"Denis","Wride","OLOLO"}, 64 | {"Anton","Papay","WTF?"}, 65 | {"Denis","Maloy","How r u?"}, 66 | {"Denis","Wride","Param-pareram!"}, 67 | }; 68 | 69 | int DenisUniqueContactCount = 70 | from(messages).where( [](const Message & msg) { return msg.PhoneA == "Denis"; }) 71 | .distinct([](const Message & msg) { return msg.PhoneB; }) 72 | .count(); 73 | 74 | // DenisUniqueContactCount == 2 75 | ``` 76 | ## Test in C++14 using auto 77 | The following test requires C++14 **[GroupByTestComplex.cpp](/include/boolinq/test.GroupByTestComplex.cpp)** It uses auto in order to avoid a very long lambda argument type. 78 | The return type of a function or lambda expression can be deduced by its operand since C++14. The CMake file is changed so that this test runs with C++14. 79 | ```C++ 80 | TEST(GroupBy, CountTaxes) 81 | { 82 | struct Tax { 83 | std::string name; 84 | int amount_1; 85 | int amount_2; 86 | 87 | bool operator ==(const Tax & tax) const { 88 | return name == tax.name 89 | && amount_1 == tax.amount_1 90 | && amount_2 == tax.amount_2; 91 | } 92 | }; 93 | 94 | std::vector taxes = { 95 | {"tax 1", 1, 1}, 96 | {"tax 2", 1, 1}, 97 | {"tax 1", 2, 2}, 98 | {"tax 3", 3, 3}, 99 | {"tax 1", 4, 4}, 100 | }; 101 | 102 | Tax ans[] = { 103 | {"tax 1", 7, 7}, 104 | {"tax 2", 1, 1}, 105 | {"tax 3", 3, 3}, 106 | }; 107 | 108 | auto dst = from(taxes) 109 | .groupBy([](const Tax & a){return a.name;}) 110 | .select([](const auto & pair){ // use of auto here needs c++14 111 | return Tax { 112 | pair.first, 113 | pair.second.sum([](const Tax & a){return a.amount_1;}), 114 | pair.second.sum([](const Tax & a){return a.amount_2;}) 115 | }; 116 | }); 117 | 118 | CheckRangeEqArray(dst, ans); 119 | } 120 | ``` 121 | 122 | ## Containers supported? 123 | 124 | - C++: Native arrays, pairs of pointers 125 | - STL: list, stack, queue, vector, deque, set, map, any compatible .... 126 | - Qt: QList, QVector, QSet, QMap. 127 | 128 | ## Operators supported? 129 | 130 | #### Filters and reorders: 131 | 132 | - `where(predicate)`, `where_i(predicate)` 133 | - `take(count)`, `takeWhile(predicate)`, `takeWhile_i(predicate)` 134 | - `skip(count)`, `skipWhile(predicate)`, `skipWhile_i(predicate)` 135 | - `orderBy()`, `orderBy(transform)` 136 | - `distinct()`, `distinct(transform)` 137 | - `append(items)`, `prepend(items)` 138 | - `concat(linq)` 139 | - `reverse()` 140 | - `cast()` 141 | 142 | #### Transformers: 143 | 144 | - `select(transform)`, `select_i(transform)` 145 | - `groupBy(transform)` 146 | - `selectMany(transfom)` 147 | 148 | #### Aggregators: 149 | 150 | - `all()`, `all(predicate)` 151 | - `any()`, `any(lambda)` 152 | - `sum()`, `sum()`, `sum(lambda)` 153 | - `avg()`, `avg()`, `avg(lambda)` 154 | - `min()`, `min(lambda)` 155 | - `max()`, `max(lambda)` 156 | - `count()`, `count(value)`, `count(predicate)` 157 | - `contains(value)` 158 | - `elementAt(index)` 159 | - `first()`, `first(filter)`, `firstOrDefault()`, `firstOrDefault(filter)` 160 | - `last()`, `last(filter)`, `lastOrDefault()`, `lastOrDefault(filter)` 161 | - `toStdSet()`, `toStdList()`, `toStdDeque()`, `toStdVector()` 162 | 163 | #### Bits and Bytes: 164 | 165 | - `bytes(ByteDirection?)` 166 | - `unbytes(ByteDirection?)` 167 | - `bits(BitsDirection?, BytesDirection?)` 168 | - `unbits(BitsDirection?, BytesDirection?)` 169 | 170 | #### Coming soon: 171 | 172 | - gz() 173 | - ungz() 174 | - leftJoin 175 | - rightJoin 176 | - crossJoin 177 | - fullJoin 178 | -------------------------------------------------------------------------------- /bench/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Common variables. 2 | #SET (CMAKE_BUILD_TYPE Release) 3 | SET (CMAKE_CXX_STANDARD ${WITH_CXX_STANDARD}) 4 | SET (CMAKE_CXX_STANDARD_REQUIRED ON) 5 | SET (TARGET "${PROJECT_NAME}-bench" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wmissing-include-dirs -Wfloat-equal -Wshadow") 6 | SET (TARGET "${PROJECT_NAME}-bench" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wdouble-promotion -Weffc++ -Woverloaded-virtual -Wsign-promo") 7 | SET (TARGET "${PROJECT_NAME}-bench" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wvla -Winvalid-pch -Winline -Wredundant-decls -Wcast-align") 8 | SET (TARGET "${PROJECT_NAME}-bench" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wcast-qual -Wpointer-arith -Wold-style-cast") 9 | 10 | 11 | INCLUDE_DIRECTORIES (${PROJECT_SOURCE_DIR}/include/boolinq) 12 | INCLUDE_DIRECTORIES (${CMAKE_BINARY_DIR}/benchmark-src/include) 13 | INCLUDE_DIRECTORIES (${CMAKE_BINARY_DIR}/googletest-src/googletest/include) 14 | 15 | 16 | # Benchmarks. 17 | ADD_EXECUTABLE ( 18 | "${PROJECT_NAME}-bench" 19 | ${PROJECT_SOURCE_DIR}/bench/SpeedTest.cpp 20 | ) 21 | TARGET_LINK_LIBRARIES ( 22 | "${PROJECT_NAME}-bench" 23 | benchmark 24 | gtest 25 | ) 26 | -------------------------------------------------------------------------------- /bench/SpeedTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | #include "boolinq.h" 8 | 9 | 10 | using namespace boolinq; 11 | 12 | 13 | constexpr std::size_t benchmarkVectorSize {1000000}; 14 | std::vector vecBoolinq (benchmarkVectorSize, 0); 15 | std::vector vecCpp (benchmarkVectorSize, 0); 16 | std::vector vecCppIter (benchmarkVectorSize, 0); 17 | 18 | 19 | 20 | int main (int argc, char ** argv) 21 | { 22 | // Preparing input benchmark data (the same data sets for all tests). 23 | srand(0xDEADBEEF); 24 | for (unsigned i = 0; i < benchmarkVectorSize; i++) { 25 | const auto x = rand(); 26 | vecBoolinq[i] = x; 27 | vecCpp[i] = x; 28 | vecCppIter[i] = x; 29 | } 30 | 31 | // Launch benchmark. 32 | benchmark::Initialize (&argc, argv); 33 | benchmark::RunSpecifiedBenchmarks (); 34 | 35 | return EXIT_SUCCESS; 36 | } 37 | 38 | 39 | 40 | static void BM_BoolinqCode (benchmark::State& state) 41 | { 42 | while (state.KeepRunning () ) { 43 | double avgValue = from(vecBoolinq).where([](int a){return a%2 == 1;}) 44 | .avg(); 45 | 46 | double stdValue = from(vecBoolinq).where([](int a){return a%2 == 1;}) 47 | .avg([=](int a){return (a - avgValue)*(a - avgValue);}); 48 | 49 | // It's no test, instead it's avoiding skip of calculation through optimization. 50 | state.PauseTiming (); 51 | EXPECT_TRUE(avgValue); 52 | EXPECT_TRUE(stdValue); 53 | state.ResumeTiming(); 54 | } 55 | } 56 | BENCHMARK(BM_BoolinqCode); 57 | 58 | 59 | 60 | static void BM_CppCode (benchmark::State& state) 61 | { 62 | while (state.KeepRunning () ) { 63 | double sum = 0; 64 | int count = 0; 65 | for (unsigned i = 0; i < vecCpp.size(); i++) { 66 | if (vecCpp[i] % 2 == 1) { 67 | sum += vecCpp[i]; 68 | count++; 69 | } 70 | } 71 | double avgValue = sum / count; 72 | 73 | double stdSum = 0; 74 | for (unsigned i = 0; i < vecCpp.size(); i++) { 75 | if (vecCpp[i] % 2 == 1) { 76 | stdSum += (vecCpp[i] - avgValue) * (vecCpp[i] - avgValue); 77 | } 78 | } 79 | double stdValue = stdSum / count; 80 | 81 | // It's no test, instead it's avoiding skip of calculation through optimization. 82 | state.PauseTiming (); 83 | EXPECT_TRUE(avgValue); 84 | EXPECT_TRUE(stdValue); 85 | state.ResumeTiming (); 86 | } 87 | } 88 | BENCHMARK(BM_CppCode); 89 | 90 | 91 | 92 | static void BM_CppIterCode (benchmark::State& state) 93 | { 94 | while (state.KeepRunning () ) { 95 | double sum = 0; 96 | int count = 0; 97 | for (auto it = vecCppIter.begin(); it != vecCppIter.end(); ++it) { 98 | if (*it % 2 == 1) { 99 | sum += *it; 100 | count++; 101 | } 102 | } 103 | double avgValue = sum / count; 104 | 105 | double stdSum = 0; 106 | for (auto it = vecCppIter.begin(); it != vecCppIter.end(); ++it) { 107 | if (*it % 2 == 1) { 108 | stdSum += (*it - avgValue) * (*it - avgValue); 109 | } 110 | } 111 | double stdValue = stdSum / count; 112 | 113 | // It's no test, instead it's avoiding skip of calculation through optimization. 114 | state.PauseTiming (); 115 | EXPECT_TRUE(avgValue); 116 | EXPECT_TRUE(stdValue); 117 | state.ResumeTiming (); 118 | } 119 | } 120 | BENCHMARK(BM_CppIterCode); 121 | -------------------------------------------------------------------------------- /include/boolinq/boolinq.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace boolinq { 18 | 19 | namespace priv { 20 | // The result_of was removed since C++20 by not all but some compilers. 21 | // For the sake of compatibility, use own define but in private subspace 22 | // to avoid collisions with std in case of using both std and boolinq. 23 | template 24 | struct result_of; 25 | 26 | template 27 | struct result_of<_Callable(_Args...)> { 28 | typedef decltype(std::declval<_Callable>()(std::declval<_Args>()...)) type; 29 | }; 30 | } 31 | 32 | // 33 | 34 | struct LinqEndException {}; 35 | 36 | enum BytesDirection { 37 | BytesFirstToLast, 38 | BytesLastToFirst, 39 | }; 40 | 41 | enum BitsDirection { 42 | BitsHighToLow, 43 | BitsLowToHigh, 44 | }; 45 | 46 | template 47 | class Linq { 48 | std::function nextFunc; 49 | S storage; 50 | 51 | public: 52 | typedef T value_type; 53 | 54 | Linq() : nextFunc(), storage() 55 | { 56 | } 57 | 58 | Linq(S storage, std::function nextFunc) : nextFunc(nextFunc), storage(storage) 59 | { 60 | } 61 | 62 | T next() 63 | { 64 | return nextFunc(storage); 65 | } 66 | 67 | void for_each_i(std::function apply) const 68 | { 69 | Linq linq = *this; 70 | try { 71 | for (int i = 0; ; i++) { 72 | apply(linq.next(), i); 73 | } 74 | } 75 | catch (LinqEndException &) {} 76 | } 77 | 78 | void for_each(std::function apply) const 79 | { 80 | return for_each_i([apply](T value, int) { return apply(value); }); 81 | } 82 | 83 | Linq, int>, T> where_i(std::function filter) const 84 | { 85 | return Linq, int>, T>( 86 | std::make_tuple(*this, 0), 87 | [filter](std::tuple, int> &tuple) { 88 | Linq &linq = std::get<0>(tuple); 89 | int &index = std::get<1>(tuple); 90 | 91 | while (true) { 92 | T ret = linq.next(); 93 | if (filter(ret, index++)) { 94 | return ret; 95 | } 96 | } 97 | } 98 | ); 99 | } 100 | 101 | Linq, int>, T> where(std::function filter) const 102 | { 103 | return where_i([filter](T value, int) { return filter(value); }); 104 | } 105 | 106 | Linq, int>, T> take(int count) const 107 | { 108 | return where_i([count](T /*value*/, int i) { 109 | if (i == count) { 110 | throw LinqEndException(); 111 | } 112 | return true; 113 | }); 114 | } 115 | 116 | Linq, int>, T> takeWhile_i(std::function predicate) const 117 | { 118 | return where_i([predicate](T value, int i) { 119 | if (!predicate(value, i)) { 120 | throw LinqEndException(); 121 | } 122 | return true; 123 | }); 124 | } 125 | 126 | Linq, int>, T> takeWhile(std::function predicate) const 127 | { 128 | return takeWhile_i([predicate](T value, int /*i*/) { return predicate(value); }); 129 | } 130 | 131 | Linq, int>, T> skip(int count) const 132 | { 133 | return where_i([count](T /*value*/, int i) { return i >= count; }); 134 | } 135 | 136 | Linq, int, bool>, T> skipWhile_i(std::function predicate) const 137 | { 138 | return Linq, int, bool>, T>( 139 | std::make_tuple(*this, 0, false), 140 | [predicate](std::tuple, int, bool> &tuple) { 141 | Linq &linq = std::get<0>(tuple); 142 | int &index = std::get<1>(tuple); 143 | bool &flag = std::get<2>(tuple); 144 | 145 | if (flag) { 146 | return linq.next(); 147 | } 148 | while (true) { 149 | T ret = linq.next(); 150 | if (!predicate(ret, index++)) { 151 | flag = true; 152 | return ret; 153 | } 154 | } 155 | } 156 | ); 157 | } 158 | 159 | Linq, int, bool>, T> skipWhile(std::function predicate) const 160 | { 161 | return skipWhile_i([predicate](T value, int /*i*/) { return predicate(value); }); 162 | } 163 | 164 | template 165 | Linq, std::vector, int>, T> append(Types ... newValues) const 166 | { 167 | return Linq, std::vector, int>, T>( 168 | std::make_tuple(*this, std::vector{ newValues... }, -1), 169 | [](std::tuple, std::vector, int> &tuple) { 170 | Linq &linq = std::get<0>(tuple); 171 | std::vector &values = std::get<1>(tuple); 172 | int &index = std::get<2>(tuple); 173 | 174 | if (index == -1) { 175 | try { 176 | return linq.next(); 177 | } 178 | catch (LinqEndException &) { 179 | index = 0; 180 | } 181 | } 182 | 183 | if (index < values.size()) { 184 | return values[index++]; 185 | } 186 | 187 | throw LinqEndException(); 188 | } 189 | ); 190 | } 191 | 192 | template 193 | Linq, std::vector, int>, T> prepend(Types ... newValues) const 194 | { 195 | return Linq, std::vector, int>, T>( 196 | std::make_tuple(*this, std::vector{ newValues... }, 0), 197 | [](std::tuple, std::vector, int> &tuple) { 198 | Linq &linq = std::get<0>(tuple); 199 | std::vector &values = std::get<1>(tuple); 200 | int &index = std::get<2>(tuple); 201 | 202 | if (index < values.size()) { 203 | return values[index++]; 204 | } 205 | return linq.next(); 206 | } 207 | ); 208 | } 209 | 210 | template::type> 211 | Linq, int>, _TRet> select_i(F apply) const 212 | { 213 | return Linq, int>, _TRet>( 214 | std::make_tuple(*this, 0), 215 | [apply](std::tuple, int> &tuple) { 216 | Linq &linq = std::get<0>(tuple); 217 | int &index = std::get<1>(tuple); 218 | 219 | return apply(linq.next(), index++); 220 | } 221 | ); 222 | } 223 | 224 | template::type> 225 | Linq, int>, _TRet> select(F apply) const 226 | { 227 | return select_i([apply](T value, int /*index*/) { return apply(value); }); 228 | } 229 | 230 | template 231 | Linq, int>, TRet> cast() const 232 | { 233 | return select_i([](T value, int /*i*/) { return TRet(value); }); 234 | } 235 | 236 | template 237 | Linq, Linq, bool>, T> concat(const Linq & rhs) const 238 | { 239 | return Linq, Linq, bool>, T>( 240 | std::make_tuple(*this, rhs, false), 241 | [](std::tuple, Linq, bool> &tuple){ 242 | Linq &first = std::get<0>(tuple); 243 | Linq &second = std::get<1>(tuple); 244 | bool &flag = std::get<2>(tuple); 245 | 246 | if (!flag) { 247 | try { 248 | return first.next(); 249 | } 250 | catch (LinqEndException &) {} 251 | } 252 | return second.next(); 253 | } 254 | ); 255 | } 256 | 257 | template< 258 | typename F, 259 | typename _TRet = typename priv::result_of::type, 260 | typename _TRetVal = typename _TRet::value_type 261 | > 262 | Linq, _TRet, int, bool>, _TRetVal> selectMany_i(F apply) const 263 | { 264 | return Linq, _TRet, int, bool>, _TRetVal>( 265 | std::make_tuple(*this, _TRet(), 0, true), 266 | [apply](std::tuple, _TRet, int, bool> &tuple) { 267 | Linq &linq = std::get<0>(tuple); 268 | _TRet ¤t = std::get<1>(tuple); 269 | int &index = std::get<2>(tuple); 270 | bool &finished = std::get<3>(tuple); 271 | 272 | while (true) { 273 | if (finished) { 274 | current = apply(linq.next(), index++); 275 | finished = false; 276 | } 277 | try { 278 | return current.next(); 279 | } 280 | catch (LinqEndException &) { 281 | finished = true; 282 | } 283 | } 284 | } 285 | ); 286 | } 287 | 288 | template< 289 | typename F, 290 | typename _TRet = typename priv::result_of::type, 291 | typename _TRetVal = typename _TRet::value_type 292 | > 293 | Linq, _TRet, int, bool>, _TRetVal> selectMany(F apply) const 294 | { 295 | return selectMany_i([apply](T value, int /*index*/) { return apply(value); }); 296 | } 297 | 298 | template< 299 | typename F, 300 | typename _TKey = typename priv::result_of::type, 301 | typename _TValue = Linq, int>, T> // where(predicate) 302 | > 303 | Linq, Linq, std::unordered_set<_TKey> >, std::pair<_TKey, _TValue> > groupBy(F apply) const 304 | { 305 | return Linq, Linq, std::unordered_set<_TKey> >, std::pair<_TKey, _TValue> >( 306 | std::make_tuple(*this, *this, std::unordered_set<_TKey>()), 307 | [apply](std::tuple, Linq, std::unordered_set<_TKey> > &tuple){ 308 | Linq &linq = std::get<0>(tuple); 309 | Linq &linqCopy = std::get<1>(tuple); 310 | std::unordered_set<_TKey> &set = std::get<2>(tuple); 311 | 312 | while (true) { 313 | _TKey key = apply(linq.next()); 314 | if (set.insert(key).second) { 315 | return std::make_pair(key, linqCopy.where([apply, key](T v){ 316 | return apply(v) == key; 317 | })); 318 | } 319 | } 320 | } 321 | ); 322 | } 323 | 324 | template::type> 325 | Linq, std::unordered_set<_TRet> >, T> distinct(F transform) const 326 | { 327 | return Linq, std::unordered_set<_TRet> >, T>( 328 | std::make_tuple(*this, std::unordered_set<_TRet>()), 329 | [transform](std::tuple, std::unordered_set<_TRet> > &tuple) { 330 | Linq &linq = std::get<0>(tuple); 331 | std::unordered_set<_TRet> &set = std::get<1>(tuple); 332 | 333 | while (true) { 334 | T value = linq.next(); 335 | if (set.insert(transform(value)).second) { 336 | return value; 337 | } 338 | } 339 | } 340 | ); 341 | } 342 | 343 | Linq, std::unordered_set >, T> distinct() const 344 | { 345 | return distinct([](T value) { return value; }); 346 | } 347 | 348 | template::const_iterator> 349 | Linq, _TIter, bool>, T> orderBy(F transform) const 350 | { 351 | std::vector items = toStdVector(); 352 | std::sort(items.begin(), items.end(), [transform](const T &a, const T &b) { 353 | return transform(a) < transform(b); 354 | }); 355 | 356 | return Linq, _TIter, bool>, T>( 357 | std::make_tuple(items, _TIter(), false), 358 | [](std::tuple, _TIter, bool> &tuple) { 359 | std::vector &vec = std::get<0>(tuple); 360 | _TIter &it = std::get<1>(tuple); 361 | bool &flag = std::get<2>(tuple); 362 | 363 | if (!flag) { 364 | flag = true; 365 | it = vec.cbegin(); 366 | } 367 | if (it == vec.cend()) { 368 | throw LinqEndException(); 369 | } 370 | return *(it++); 371 | } 372 | ); 373 | } 374 | 375 | Linq, typename std::vector::const_iterator, bool>, T> orderBy() const 376 | { 377 | return orderBy([](T value) { return value; }); 378 | } 379 | 380 | template::const_reverse_iterator> 381 | Linq, _TIter, bool>, T> reverse() const 382 | { 383 | return Linq, _TIter, bool>, T>( 384 | std::make_tuple(toStdList(), _TIter(), false), 385 | [](std::tuple, _TIter, bool> &tuple) { 386 | std::list &list = std::get<0>(tuple); 387 | _TIter &it = std::get<1>(tuple); 388 | bool &flag = std::get<2>(tuple); 389 | 390 | if (!flag) { 391 | flag = true; 392 | it = list.crbegin(); 393 | } 394 | if (it == list.crend()) { 395 | throw LinqEndException(); 396 | } 397 | return *(it++); 398 | } 399 | ); 400 | } 401 | 402 | // Aggregators 403 | 404 | template 405 | TRet aggregate(TRet start, std::function accumulate) const 406 | { 407 | Linq linq = *this; 408 | try { 409 | while (true) { 410 | start = accumulate(start, linq.next()); 411 | } 412 | } 413 | catch (LinqEndException &) {} 414 | return start; 415 | } 416 | 417 | template::type> 418 | _TRet sum(F transform) const 419 | { 420 | return aggregate<_TRet>(_TRet(), [transform](_TRet accumulator, T value) { 421 | return accumulator + transform(value); 422 | }); 423 | } 424 | 425 | template 426 | TRet sum() const 427 | { 428 | return sum([](T value) { return TRet(value); }); 429 | } 430 | 431 | template::type> 432 | _TRet avg(F transform) const 433 | { 434 | int count = 0; 435 | _TRet res = sum([transform, &count](T value) { 436 | count++; 437 | return transform(value); 438 | }); 439 | return res / count; 440 | } 441 | 442 | template 443 | TRet avg() const 444 | { 445 | return avg([](T value) { return TRet(value); }); 446 | } 447 | 448 | int count() const 449 | { 450 | int index = 0; 451 | for_each([&index](T /*a*/) { index++; }); 452 | return index; 453 | } 454 | 455 | int count(std::function predicate) const 456 | { 457 | return where(predicate).count(); 458 | } 459 | 460 | int count(const T &item) const 461 | { 462 | return count([item](T value) { return item == value; }); 463 | } 464 | 465 | // Bool aggregators 466 | 467 | bool any(std::function predicate) const 468 | { 469 | Linq linq = *this; 470 | try { 471 | while (true) { 472 | if (predicate(linq.next())) { 473 | return true; 474 | } 475 | } 476 | } 477 | catch (LinqEndException &) {} 478 | return false; 479 | } 480 | 481 | bool any() const 482 | { 483 | return any([](T value) { return static_cast(value); }); 484 | } 485 | 486 | bool all(std::function predicate) const 487 | { 488 | return !any([predicate](T value) { return !predicate(value); }); 489 | } 490 | 491 | bool all() const 492 | { 493 | return all([](T value) { return static_cast(value); }); 494 | } 495 | 496 | bool contains(const T &item) const 497 | { 498 | return any([&item](T value) { return value == item; }); 499 | } 500 | 501 | // Election aggregators 502 | 503 | T elect(std::function accumulate) const 504 | { 505 | T result; 506 | for_each_i([accumulate, &result](T value, int i) { 507 | if (i == 0) { 508 | result = value; 509 | } else { 510 | result = accumulate(result, value); 511 | } 512 | }); 513 | return result; 514 | } 515 | 516 | template 517 | T max(F transform) const 518 | { 519 | return elect([transform](const T &a, const T &b) { 520 | return (transform(a) < transform(b)) ? b : a; 521 | }); 522 | } 523 | 524 | T max() const 525 | { 526 | return max([](T value) { return value; }); 527 | } 528 | 529 | template 530 | T min(F transform) const 531 | { 532 | return elect([transform](const T &a, const T &b) { 533 | return (transform(a) < transform(b)) ? a : b; 534 | }); 535 | } 536 | 537 | T min() const 538 | { 539 | return min([](T value) { return value; }); 540 | } 541 | 542 | // Single object returners 543 | 544 | T elementAt(int index) const 545 | { 546 | return skip(index).next(); 547 | } 548 | 549 | T first(std::function predicate) const 550 | { 551 | return where(predicate).next(); 552 | } 553 | 554 | T first() const 555 | { 556 | return Linq(*this).next(); 557 | } 558 | 559 | T firstOrDefault(std::function predicate, T const& defaultValue = T()) const 560 | { 561 | try { 562 | return where(predicate).next(); 563 | } 564 | catch (LinqEndException &) {} 565 | return defaultValue; 566 | } 567 | 568 | T firstOrDefault(T const& defaultValue = T()) const 569 | { 570 | try { 571 | return Linq(*this).next(); 572 | } 573 | catch (LinqEndException &) {} 574 | return defaultValue; 575 | } 576 | 577 | T last(std::function predicate) const 578 | { 579 | T res; 580 | int index = -1; 581 | where(predicate).for_each_i([&res, &index](T value, int i) { 582 | res = value; 583 | index = i; 584 | }); 585 | 586 | if (index == -1) { 587 | throw LinqEndException(); 588 | } 589 | return res; 590 | } 591 | 592 | T last() const 593 | { 594 | return last([](T /*value*/) { return true; }); 595 | } 596 | 597 | T lastOrDefault(std::function predicate, T const& defaultValue = T()) const 598 | { 599 | T res = defaultValue; 600 | where(predicate).for_each([&res](T value) { 601 | res = value; 602 | }); 603 | return res; 604 | } 605 | 606 | T lastOrDefault(T const& defaultValue = T()) const 607 | { 608 | return lastOrDefault([](T /*value*/) { return true; }, defaultValue); 609 | } 610 | 611 | // Export to containers 612 | 613 | std::vector toStdVector() const 614 | { 615 | std::vector items; 616 | for_each([&items](T value) { 617 | items.push_back(value); 618 | }); 619 | return items; 620 | } 621 | 622 | std::list toStdList() const 623 | { 624 | std::list items; 625 | for_each([&items](T value) { 626 | items.push_back(value); 627 | }); 628 | return items; 629 | } 630 | 631 | std::deque toStdDeque() const 632 | { 633 | std::deque items; 634 | for_each([&items](T value) { 635 | items.push_back(value); 636 | }); 637 | return items; 638 | } 639 | 640 | std::set toStdSet() const 641 | { 642 | std::set items; 643 | for_each([&items](T value) { 644 | items.insert(value); 645 | }); 646 | return items; 647 | } 648 | 649 | std::unordered_set toStdUnorderedSet() const 650 | { 651 | std::unordered_set items; 652 | for_each([&items](T value) { 653 | items.insert(value); 654 | }); 655 | return items; 656 | } 657 | 658 | // Bits and bytes 659 | 660 | Linq, BytesDirection, T, int>, int> bytes(BytesDirection direction = BytesFirstToLast) const 661 | { 662 | return Linq, BytesDirection, T, int>, int>( 663 | std::make_tuple(*this, direction, T(), sizeof(T)), 664 | [](std::tuple, BytesDirection, T, int> &tuple) { 665 | Linq &linq = std::get<0>(tuple); 666 | BytesDirection &bytesDirection = std::get<1>(tuple); 667 | T &value = std::get<2>(tuple); 668 | int &index = std::get<3>(tuple); 669 | 670 | if (index == sizeof(T)) { 671 | value = linq.next(); 672 | index = 0; 673 | } 674 | 675 | unsigned char *ptr = reinterpret_cast(&value); 676 | 677 | int byteIndex = index; 678 | if (bytesDirection == BytesLastToFirst) { 679 | byteIndex = sizeof(T) - 1 - byteIndex; 680 | } 681 | 682 | index++; 683 | return ptr[byteIndex]; 684 | } 685 | ); 686 | } 687 | 688 | template 689 | Linq, BytesDirection, int>, TRet> unbytes(BytesDirection direction = BytesFirstToLast) const 690 | { 691 | return Linq, BytesDirection, int>, TRet>( 692 | std::make_tuple(*this, direction, 0), 693 | [](std::tuple, BytesDirection, int> &tuple) { 694 | Linq &linq = std::get<0>(tuple); 695 | BytesDirection &bytesDirection = std::get<1>(tuple); 696 | // int &index = std::get<2>(tuple); 697 | 698 | TRet value; 699 | unsigned char *ptr = reinterpret_cast(&value); 700 | 701 | for (int i = 0; i < sizeof(TRet); i++) { 702 | int byteIndex = i; 703 | if (bytesDirection == BytesLastToFirst) { 704 | byteIndex = sizeof(TRet) - 1 - byteIndex; 705 | } 706 | 707 | ptr[byteIndex] = linq.next(); 708 | } 709 | 710 | return value; 711 | } 712 | ); 713 | } 714 | 715 | Linq, BytesDirection, BitsDirection, T, int>, int> bits(BitsDirection bitsDir = BitsHighToLow, BytesDirection bytesDir = BytesFirstToLast) const 716 | { 717 | return Linq, BytesDirection, BitsDirection, T, int>, int>( 718 | std::make_tuple(*this, bytesDir, bitsDir, T(), sizeof(T) * CHAR_BIT), 719 | [](std::tuple, BytesDirection, BitsDirection, T, int> &tuple) { 720 | Linq &linq = std::get<0>(tuple); 721 | BytesDirection &bytesDirection = std::get<1>(tuple); 722 | BitsDirection &bitsDirection = std::get<2>(tuple); 723 | T &value = std::get<3>(tuple); 724 | int &index = std::get<4>(tuple); 725 | 726 | if (index == sizeof(T) * CHAR_BIT) { 727 | value = linq.next(); 728 | index = 0; 729 | } 730 | 731 | unsigned char *ptr = reinterpret_cast(&value); 732 | 733 | int byteIndex = index / CHAR_BIT; 734 | if (bytesDirection == BytesLastToFirst) { 735 | byteIndex = sizeof(T) - 1 - byteIndex; 736 | } 737 | 738 | int bitIndex = index % CHAR_BIT; 739 | if (bitsDirection == BitsHighToLow) { 740 | bitIndex = CHAR_BIT - 1 - bitIndex; 741 | } 742 | 743 | index++; 744 | return (ptr[byteIndex] >> bitIndex) & 1; 745 | } 746 | ); 747 | } 748 | 749 | template 750 | Linq, BytesDirection, BitsDirection, int>, TRet> unbits(BitsDirection bitsDir = BitsHighToLow, BytesDirection bytesDir = BytesFirstToLast) const 751 | { 752 | return Linq, BytesDirection, BitsDirection, int>, TRet>( 753 | std::make_tuple(*this, bytesDir, bitsDir, 0), 754 | [](std::tuple, BytesDirection, BitsDirection, int> &tuple) { 755 | Linq &linq = std::get<0>(tuple); 756 | BytesDirection &bytesDirection = std::get<1>(tuple); 757 | BitsDirection &bitsDirection = std::get<2>(tuple); 758 | // int &index = std::get<3>(tuple); 759 | 760 | TRet value = TRet(); 761 | unsigned char *ptr = reinterpret_cast(&value); 762 | 763 | for (int i = 0; i < sizeof(TRet) * CHAR_BIT; i++) { 764 | int byteIndex = i / CHAR_BIT; 765 | if (bytesDirection == BytesLastToFirst) { 766 | byteIndex = sizeof(TRet) - 1 - byteIndex; 767 | } 768 | 769 | int bitIndex = i % CHAR_BIT; 770 | if (bitsDirection == BitsHighToLow) { 771 | bitIndex = CHAR_BIT - 1 - bitIndex; 772 | } 773 | 774 | ptr[byteIndex] &= ~(1 << bitIndex); 775 | ptr[byteIndex] |= bool(linq.next()) << bitIndex; 776 | } 777 | 778 | return value; 779 | } 780 | ); 781 | } 782 | }; 783 | 784 | template 785 | std::ostream &operator<<(std::ostream &stream, Linq linq) 786 | { 787 | try { 788 | while (true) { 789 | stream << linq.next() << ' '; 790 | } 791 | } 792 | catch (LinqEndException &) {} 793 | return stream; 794 | } 795 | 796 | //////////////////////////////////////////////////////////////// 797 | // Linq Creators 798 | //////////////////////////////////////////////////////////////// 799 | 800 | template 801 | Linq, typename std::iterator_traits::value_type> from(const T & begin, const T & end) 802 | { 803 | return Linq, typename std::iterator_traits::value_type>( 804 | std::make_pair(begin, end), 805 | [](std::pair &pair) { 806 | if (pair.first == pair.second) { 807 | throw LinqEndException(); 808 | } 809 | return *(pair.first++); 810 | } 811 | ); 812 | } 813 | 814 | template 815 | Linq, typename std::iterator_traits::value_type> from(const T & it, int n) 816 | { 817 | return from(it, it + n); 818 | } 819 | 820 | template 821 | Linq, T> from(T (&array)[N]) 822 | { 823 | return from((const T *)(&array), (const T *)(&array) + N); 824 | } 825 | 826 | template class TV, typename TT> 827 | auto from(const TV & container) 828 | -> decltype(from(container.cbegin(), container.cend())) 829 | { 830 | return from(container.cbegin(), container.cend()); 831 | } 832 | 833 | // std::list, std::vector, std::dequeue 834 | template class TV, typename TT, typename TU> 835 | auto from(const TV & container) 836 | -> decltype(from(container.cbegin(), container.cend())) 837 | { 838 | return from(container.cbegin(), container.cend()); 839 | } 840 | 841 | // std::set 842 | template class TV, typename TT, typename TS, typename TU> 843 | auto from(const TV & container) 844 | -> decltype(from(container.cbegin(), container.cend())) 845 | { 846 | return from(container.cbegin(), container.cend()); 847 | } 848 | 849 | // std::map 850 | template class TV, typename TK, typename TT, typename TS, typename TU> 851 | auto from(const TV & container) 852 | -> decltype(from(container.cbegin(), container.cend())) 853 | { 854 | return from(container.cbegin(), container.cend()); 855 | } 856 | 857 | // std::array 858 | template class TV, typename TT, size_t TL> 859 | auto from(const TV & container) 860 | -> decltype(from(container.cbegin(), container.cend())) 861 | { 862 | return from(container.cbegin(), container.cend()); 863 | } 864 | 865 | template 866 | Linq, T> repeat(const T & value, int count) { 867 | return Linq, T>( 868 | std::make_pair(value, count), 869 | [](std::pair &pair) { 870 | if (pair.second > 0) { 871 | pair.second--; 872 | return pair.first; 873 | } 874 | throw LinqEndException(); 875 | } 876 | ); 877 | } 878 | 879 | template 880 | Linq, T> range(const T & start, const T & end, const T & step) { 881 | return Linq, T>( 882 | std::make_tuple(start, end, step), 883 | [](std::tuple &tuple) { 884 | T &start = std::get<0>(tuple); 885 | T &end = std::get<1>(tuple); 886 | T &step = std::get<2>(tuple); 887 | 888 | T value = start; 889 | if (value < end) { 890 | start += step; 891 | return value; 892 | } 893 | throw LinqEndException(); 894 | } 895 | ); 896 | } 897 | } 898 | -------------------------------------------------------------------------------- /test/AllTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include "boolinq.h" 7 | 8 | using namespace boolinq; 9 | 10 | TEST(All, ThreeInts) 11 | { 12 | std::vector src; 13 | src.push_back(1); 14 | src.push_back(2); 15 | src.push_back(3); 16 | 17 | auto rng = from(src); 18 | 19 | EXPECT_TRUE(rng.all()); 20 | 21 | EXPECT_TRUE(rng.all([](int a){return a>0;})); 22 | EXPECT_TRUE(rng.all([](int a){return a<4;})); 23 | EXPECT_TRUE(rng.all([](int a){return a>0 && a<4;})); 24 | 25 | EXPECT_FALSE(rng.all([](int a){return a>2;})); 26 | EXPECT_FALSE(rng.all([](int a){return a==1;})); 27 | EXPECT_FALSE(rng.all([](int a){return a<3;})); 28 | } 29 | 30 | TEST(All, ThreeIntsSecond) 31 | { 32 | std::vector src; 33 | src.push_back(0); 34 | src.push_back(1); 35 | src.push_back(2); 36 | 37 | auto rng = from(src); 38 | 39 | EXPECT_FALSE(rng.all()); 40 | 41 | EXPECT_TRUE(rng.all([](int a){return a>=0;})); 42 | EXPECT_TRUE(rng.all([](int a){return a<=2;})); 43 | EXPECT_TRUE(rng.all([](int a){return a>=0 && a<=2;})); 44 | 45 | EXPECT_FALSE(rng.all([](int a){return a>1;})); 46 | EXPECT_FALSE(rng.all([](int a){return a==1;})); 47 | EXPECT_FALSE(rng.all([](int a){return a<2;})); 48 | } 49 | -------------------------------------------------------------------------------- /test/AnyTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include "boolinq.h" 7 | 8 | using namespace boolinq; 9 | 10 | TEST(Any, ThreeInts) 11 | { 12 | std::vector src; 13 | src.push_back(1); 14 | src.push_back(2); 15 | src.push_back(3); 16 | 17 | auto rng = from(src); 18 | 19 | EXPECT_TRUE(rng.any()); 20 | 21 | EXPECT_TRUE(rng.any([](int a){return a==1;})); 22 | EXPECT_TRUE(rng.any([](int a){return a==2;})); 23 | EXPECT_TRUE(rng.any([](int a){return a==3;})); 24 | EXPECT_TRUE(rng.any([](int a){return a>1;})); 25 | EXPECT_TRUE(rng.any([](int a){return a<3;})); 26 | EXPECT_TRUE(rng.any([](int a){return a!=2;})); 27 | 28 | EXPECT_FALSE(rng.any([](int a){return a==0;})); 29 | EXPECT_FALSE(rng.any([](int a){return a==4;})); 30 | EXPECT_FALSE(rng.any([](int a){return a<1;})); 31 | EXPECT_FALSE(rng.any([](int a){return a>3;})); 32 | } 33 | -------------------------------------------------------------------------------- /test/AppendTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include "CommonTests.h" 6 | 7 | #include "boolinq.h" 8 | 9 | using namespace boolinq; 10 | 11 | TEST(Append, ThreePlusOne) 12 | { 13 | std::vector src = {1,2,3}; 14 | 15 | auto rng = from(src).append(4); 16 | int ans[] = {1,2,3,4}; 17 | 18 | CheckRangeEqArray(rng, ans); 19 | } 20 | 21 | TEST(Append, ThreePlusTwo) 22 | { 23 | std::vector src = {1,2,3}; 24 | 25 | auto rng = from(src).append(4, 5); 26 | int ans[] = {1,2,3,4,5}; 27 | 28 | CheckRangeEqArray(rng, ans); 29 | } 30 | 31 | TEST(Append, ZeroPlusTwo) 32 | { 33 | std::vector src; 34 | 35 | auto rng = from(src).append(7,8); 36 | int ans[] = {7,8}; 37 | 38 | CheckRangeEqArray(rng, ans); 39 | } -------------------------------------------------------------------------------- /test/AvgTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include "boolinq.h" 7 | 8 | using namespace boolinq; 9 | 10 | TEST(Avg, ThreeInts) 11 | { 12 | std::vector src; 13 | src.push_back(1); 14 | src.push_back(2); 15 | src.push_back(3); 16 | 17 | auto rng = from(src); 18 | 19 | EXPECT_NEAR(2.0, rng.avg(), DBL_EPSILON); 20 | } 21 | 22 | TEST(Avg, FiveInts) 23 | { 24 | std::vector src; 25 | src.push_back(1); 26 | src.push_back(2); 27 | src.push_back(3); 28 | src.push_back(4); 29 | src.push_back(5); 30 | 31 | auto rng = from(src); 32 | auto dst0 = rng.where([](int a){return a%2 == 0;}); 33 | auto dst1 = rng.where([](int a){return a%2 == 1;}); 34 | 35 | EXPECT_NEAR(3.0, dst0.avg(), DBL_EPSILON); 36 | EXPECT_NEAR(3.0, dst1.avg(), DBL_EPSILON); 37 | } 38 | 39 | TEST(Avg, FiveStringsLen) 40 | { 41 | std::vector src; 42 | src.push_back("hello"); 43 | src.push_back("apple"); 44 | src.push_back("nokia"); 45 | src.push_back("oracle"); 46 | src.push_back("ponny"); 47 | 48 | auto rng = from(src); 49 | 50 | EXPECT_EQ(5, rng.avg([](const std::string & str){return str.size();})); 51 | } 52 | -------------------------------------------------------------------------------- /test/BitsTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include "CommonTests.h" 6 | 7 | #include "boolinq.h" 8 | 9 | using namespace boolinq; 10 | 11 | ////////////////////////////////////////////////////////////////////////// 12 | 13 | TEST(Bits, OneByteDefault) 14 | { 15 | unsigned char src[] = {0xAA}; 16 | int ans[] = {1,0,1,0,1,0,1,0}; 17 | 18 | auto rng = from(src); 19 | auto dst = rng.bits(); 20 | 21 | CheckRangeEqArray(dst, ans); 22 | } 23 | 24 | TEST(Bits, OneByteHL) 25 | { 26 | unsigned char src[] = {0xAA}; 27 | int ans[] = {1,0,1,0,1,0,1,0}; 28 | 29 | auto rng = from(src); 30 | auto dst = rng.bits(BitsHighToLow); 31 | 32 | CheckRangeEqArray(dst, ans); 33 | } 34 | 35 | TEST(Bits, OneByteLH) 36 | { 37 | unsigned char src[] = {0xAA}; 38 | int ans[] = {0,1,0,1,0,1,0,1}; 39 | 40 | auto rng = from(src); 41 | auto dst = rng.bits(BitsLowToHigh); 42 | 43 | CheckRangeEqArray(dst, ans); 44 | } 45 | 46 | ////////////////////////////////////////////////////////////////////////// 47 | 48 | TEST(Bits, OneIntDefault) 49 | { 50 | unsigned int src[] = {0x12345678}; 51 | int ans[] = 52 | { 53 | 0,1,1,1,1,0,0,0, 54 | 0,1,0,1,0,1,1,0, 55 | 0,0,1,1,0,1,0,0, 56 | 0,0,0,1,0,0,1,0, 57 | }; 58 | 59 | auto rng = from(src); 60 | auto dst = rng.bits(); 61 | 62 | CheckRangeEqArray(dst, ans); 63 | } 64 | 65 | TEST(Bits, OneIntHL) 66 | { 67 | unsigned int src[] = {0x12345678}; 68 | int ans[] = 69 | { 70 | 0,1,1,1,1,0,0,0, 71 | 0,1,0,1,0,1,1,0, 72 | 0,0,1,1,0,1,0,0, 73 | 0,0,0,1,0,0,1,0, 74 | }; 75 | 76 | auto rng = from(src); 77 | auto dst = rng.bits(BitsHighToLow); 78 | 79 | CheckRangeEqArray(dst, ans); 80 | } 81 | 82 | TEST(Bits, OneIntLH) 83 | { 84 | unsigned int src[] = {0x12345678}; 85 | int ans[] = 86 | { 87 | 0,0,0,1,1,1,1,0, 88 | 0,1,1,0,1,0,1,0, 89 | 0,0,1,0,1,1,0,0, 90 | 0,1,0,0,1,0,0,0, 91 | }; 92 | 93 | auto rng = from(src); 94 | auto dst = rng.bits(BitsLowToHigh,BytesFirstToLast); 95 | auto vvv = dst.toStdVector(); 96 | 97 | CheckRangeEqArray(dst, ans); 98 | } 99 | 100 | ////////////////////////////////////////////////////////////////////////// 101 | 102 | TEST(Bits, IntsDefault) 103 | { 104 | unsigned int src[] = {0x12345678,0xAABBCCDD}; 105 | int ans[] = 106 | { 107 | 0,1,1,1,1,0,0,0, // 78 108 | 0,1,0,1,0,1,1,0, // 56 109 | 0,0,1,1,0,1,0,0, // 34 110 | 0,0,0,1,0,0,1,0, // 12 111 | 112 | 1,1,0,1,1,1,0,1, // DD 113 | 1,1,0,0,1,1,0,0, // CC 114 | 1,0,1,1,1,0,1,1, // BB 115 | 1,0,1,0,1,0,1,0, // AA 116 | }; 117 | 118 | auto rng = from(src); 119 | auto dst = rng.bits(); 120 | 121 | CheckRangeEqArray(dst, ans); 122 | } 123 | 124 | TEST(Bits, IntsHL) 125 | { 126 | unsigned int src[] = {0x12345678,0xAABBCCDD}; 127 | int ans[] = 128 | { 129 | 0,1,1,1,1,0,0,0, // 78 130 | 0,1,0,1,0,1,1,0, // 56 131 | 0,0,1,1,0,1,0,0, // 34 132 | 0,0,0,1,0,0,1,0, // 12 133 | 134 | 1,1,0,1,1,1,0,1, // DD 135 | 1,1,0,0,1,1,0,0, // CC 136 | 1,0,1,1,1,0,1,1, // BB 137 | 1,0,1,0,1,0,1,0, // AA 138 | }; 139 | 140 | auto rng = from(src); 141 | auto dst = rng.bits(BitsHighToLow); 142 | 143 | CheckRangeEqArray(dst, ans); 144 | } 145 | 146 | TEST(Bits, IntsLH) 147 | { 148 | unsigned int src[] = {0x12345678,0xAABBCCDD}; 149 | int ans[] = 150 | { 151 | 0,0,0,1,1,1,1,0, // -87 152 | 0,1,1,0,1,0,1,0, // -65 153 | 0,0,1,0,1,1,0,0, // -43 154 | 0,1,0,0,1,0,0,0, // -21 155 | 156 | 1,0,1,1,1,0,1,1, // -DD 157 | 0,0,1,1,0,0,1,1, // -CC 158 | 1,1,0,1,1,1,0,1, // -BB 159 | 0,1,0,1,0,1,0,1, // -AA 160 | }; 161 | 162 | auto rng = from(src); 163 | auto dst = rng.bits(BitsLowToHigh); 164 | 165 | CheckRangeEqArray(dst, ans); 166 | } 167 | -------------------------------------------------------------------------------- /test/BytesTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include "CommonTests.h" 6 | 7 | #include "boolinq.h" 8 | 9 | using namespace boolinq; 10 | 11 | ////////////////////////////////////////////////////////////////////////// 12 | 13 | TEST(Bytes, OneByteDefault) 14 | { 15 | unsigned char src[] = {0xAA}; 16 | int ans[] = {0xAA}; 17 | 18 | auto rng = from(src); 19 | auto dst = rng.bytes(); 20 | 21 | CheckRangeEqArray(dst, ans); 22 | } 23 | 24 | TEST(Bytes, OneByteFL) 25 | { 26 | unsigned char src[] = {0xAA}; 27 | int ans[] = {0xAA}; 28 | 29 | auto rng = from(src); 30 | auto dst = rng.bytes(BytesFirstToLast); 31 | 32 | CheckRangeEqArray(dst, ans); 33 | } 34 | 35 | TEST(Bytes, OneByteLF) 36 | { 37 | unsigned char src[] = {0xAA}; 38 | int ans[] = {0xAA}; 39 | 40 | auto rng = from(src); 41 | auto dst = rng.bytes(BytesLastToFirst); 42 | 43 | CheckRangeEqArray(dst, ans); 44 | } 45 | 46 | ////////////////////////////////////////////////////////////////////////// 47 | 48 | TEST(Bytes, OneIntDefault) 49 | { 50 | int src[] = {0x12345678}; 51 | int ans[] = {0x78,0x56,0x34,0x12}; 52 | 53 | auto rng = from(src); 54 | auto dst = rng.bytes(); 55 | 56 | CheckRangeEqArray(dst, ans); 57 | } 58 | 59 | TEST(Bytes, OneIntFL) 60 | { 61 | int src[] = {0x12345678}; 62 | int ans[] = {0x78,0x56,0x34,0x12}; 63 | 64 | auto rng = from(src); 65 | auto dst = rng.bytes(BytesFirstToLast); 66 | 67 | CheckRangeEqArray(dst, ans); 68 | } 69 | 70 | TEST(Bytes, OneIntLF) 71 | { 72 | int src[] = {0x12345678}; 73 | int ans[] = {0x12,0x34,0x56,0x78}; 74 | 75 | auto rng = from(src); 76 | auto dst = rng.bytes(BytesLastToFirst); 77 | 78 | CheckRangeEqArray(dst, ans); 79 | } 80 | 81 | ////////////////////////////////////////////////////////////////////////// 82 | 83 | TEST(Bytes, IntsDefault) 84 | { 85 | unsigned src[] = {0x12345678, 0xAABBCCDD}; 86 | int ans[] = 87 | { 88 | 0x78,0x56,0x34,0x12, 89 | 0xDD,0xCC,0xBB,0xAA, 90 | }; 91 | 92 | auto rng = from(src); 93 | auto dst = rng.bytes(BytesFirstToLast); 94 | 95 | CheckRangeEqArray(dst, ans); 96 | } 97 | 98 | TEST(Bytes, IntsFL) 99 | { 100 | unsigned src[] = {0x12345678, 0xAABBCCDD}; 101 | int ans[] = 102 | { 103 | 0x78,0x56,0x34,0x12, 104 | 0xDD,0xCC,0xBB,0xAA, 105 | }; 106 | 107 | auto rng = from(src); 108 | auto dst = rng.bytes(BytesFirstToLast); 109 | 110 | CheckRangeEqArray(dst, ans); 111 | } 112 | 113 | TEST(Bytes, IntsLF) 114 | { 115 | unsigned src[] = {0x12345678, 0xAABBCCDD}; 116 | int ans[] = 117 | { 118 | 0x12,0x34,0x56,0x78, 119 | 0xAA,0xBB,0xCC,0xDD, 120 | }; 121 | 122 | auto rng = from(src); 123 | auto dst = rng.bytes(BytesLastToFirst); 124 | 125 | CheckRangeEqArray(dst, ans); 126 | } 127 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Common variables. 2 | SET (CMAKE_CXX_STANDARD ${WITH_CXX_STANDARD}) 3 | SET (CMAKE_CXX_STANDARD_REQUIRED ON) 4 | SET (TARGET "${PROJECT_NAME}-test" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wmissing-include-dirs -Wfloat-equal -Wshadow") 5 | SET (TARGET "${PROJECT_NAME}-test" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wdouble-promotion -Weffc++ -Woverloaded-virtual -Wsign-promo") 6 | SET (TARGET "${PROJECT_NAME}-test" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wvla -Winvalid-pch -Winline -Wredundant-decls -Wcast-align") 7 | SET (TARGET "${PROJECT_NAME}-test" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wcast-qual -Wpointer-arith -Wold-style-cast") 8 | SET (TARGET "${PROJECT_NAME}-test" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") 9 | SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") 10 | 11 | 12 | INCLUDE_DIRECTORIES (${PROJECT_SOURCE_DIR}/include/boolinq) 13 | INCLUDE_DIRECTORIES (${CMAKE_BINARY_DIR}/googletest-src/googletest/include) 14 | 15 | # Unit tests. 16 | SET ( 17 | BoolinqTest_SOURCES 18 | ${PROJECT_SOURCE_DIR}/test/AllTest.cpp 19 | ${PROJECT_SOURCE_DIR}/test/AnyTest.cpp 20 | ${PROJECT_SOURCE_DIR}/test/AvgTest.cpp 21 | ${PROJECT_SOURCE_DIR}/test/AppendTest.cpp 22 | ${PROJECT_SOURCE_DIR}/test/BitsTest.cpp 23 | ${PROJECT_SOURCE_DIR}/test/BytesTest.cpp 24 | ${PROJECT_SOURCE_DIR}/test/ConcatTest.cpp 25 | ${PROJECT_SOURCE_DIR}/test/ContainsTest.cpp 26 | ${PROJECT_SOURCE_DIR}/test/CountTest.cpp 27 | ${PROJECT_SOURCE_DIR}/test/DistinctTest.cpp 28 | ${PROJECT_SOURCE_DIR}/test/DotCallTest.cpp 29 | ${PROJECT_SOURCE_DIR}/test/ElementAtTest.cpp 30 | ${PROJECT_SOURCE_DIR}/test/FirstTest.cpp 31 | ${PROJECT_SOURCE_DIR}/test/ForEachTest.cpp 32 | ${PROJECT_SOURCE_DIR}/test/GroupByTest.cpp 33 | ${PROJECT_SOURCE_DIR}/test/CtorTest.cpp 34 | ${PROJECT_SOURCE_DIR}/test/LastTest.cpp 35 | ${PROJECT_SOURCE_DIR}/test/LinqTest.cpp 36 | ${PROJECT_SOURCE_DIR}/test/MaxTest.cpp 37 | ${PROJECT_SOURCE_DIR}/test/MinTest.cpp 38 | ${PROJECT_SOURCE_DIR}/test/OrderByTest.cpp 39 | ${PROJECT_SOURCE_DIR}/test/PrependTest.cpp 40 | ${PROJECT_SOURCE_DIR}/test/RangeTest.cpp 41 | ${PROJECT_SOURCE_DIR}/test/ReverseTest.cpp 42 | ${PROJECT_SOURCE_DIR}/test/SelectTest.cpp 43 | ${PROJECT_SOURCE_DIR}/test/SelectManyTest.cpp 44 | ${PROJECT_SOURCE_DIR}/test/SkipTest.cpp 45 | ${PROJECT_SOURCE_DIR}/test/SkipWhileTest.cpp 46 | ${PROJECT_SOURCE_DIR}/test/SumTest.cpp 47 | ${PROJECT_SOURCE_DIR}/test/TakeTest.cpp 48 | ${PROJECT_SOURCE_DIR}/test/TakeWhileTest.cpp 49 | ${PROJECT_SOURCE_DIR}/test/ToStdDequeTest.cpp 50 | ${PROJECT_SOURCE_DIR}/test/ToStdListTest.cpp 51 | ${PROJECT_SOURCE_DIR}/test/ToStdSetTest.cpp 52 | ${PROJECT_SOURCE_DIR}/test/ToStdVectorTest.cpp 53 | ${PROJECT_SOURCE_DIR}/test/UnbitsTest.cpp 54 | ${PROJECT_SOURCE_DIR}/test/UnbytesTest.cpp 55 | ${PROJECT_SOURCE_DIR}/test/WhereTest.cpp 56 | ) 57 | ADD_EXECUTABLE ( 58 | "${PROJECT_NAME}-test" 59 | ${BoolinqTest_SOURCES} 60 | ) 61 | 62 | TARGET_LINK_LIBRARIES ( 63 | "${PROJECT_NAME}-test" 64 | gtest_main 65 | gtest 66 | #gcov 67 | ) 68 | 69 | #separate target for the complex group by test requiring C++14 70 | ADD_EXECUTABLE ( 71 | "${PROJECT_NAME}-test14" 72 | ${PROJECT_SOURCE_DIR}/test/GroupByTestComplex.cpp 73 | ) 74 | 75 | TARGET_COMPILE_FEATURES("${PROJECT_NAME}-test14" PRIVATE cxx_std_14) 76 | 77 | TARGET_LINK_LIBRARIES ( 78 | "${PROJECT_NAME}-test14" 79 | gtest_main 80 | gtest 81 | ) 82 | 83 | ENABLE_TESTING () 84 | ADD_TEST (BoolinqTest "${PROJECT_NAME}-test") 85 | ADD_TEST (BoolinqTest14 "${PROJECT_NAME}-test14") 86 | 87 | # Test coverage report. 88 | SET (Coverage_REPORT ${PROJECT_BINARY_DIR}/coverage.info) 89 | SET (Coverage_DIR ${PROJECT_BINARY_DIR}/coverage) 90 | ADD_CUSTOM_COMMAND ( 91 | OUTPUT ${Coverage_REPORT} 92 | COMMAND lcov -q -c -f -b . -d ${PROJECT_BINARY_DIR}/ -o ${Coverage_REPORT} 93 | COMMAND lcov -e ${Coverage_REPORT} '${PROJECT_SOURCE_DIR}/*' -o ${Coverage_REPORT} 94 | COMMAND genhtml ${Coverage_REPORT} --legend --demangle-cpp -f -q -o ${Coverage_DIR} 95 | DEPENDS "${PROJECT_NAME}-test" "${PROJECT_NAME}-test14" 96 | ) 97 | ADD_CUSTOM_TARGET (coverage DEPENDS ${Coverage_REPORT}) 98 | LIST (APPEND Coverage_DATA "${Coverage_REPORT}") 99 | LIST (APPEND Coverage_DATA "${Coverage_DIR}") 100 | LIST (APPEND Coverage_DATA "${PROJECT_BINARY_DIR}/test/CMakeFiles/boolinq-test.dir") 101 | SET_DIRECTORY_PROPERTIES (PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${Coverage_DATA}") 102 | -------------------------------------------------------------------------------- /test/CommonTests.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "boolinq.h" 6 | 7 | using namespace boolinq; 8 | 9 | ////////////////////////////////////////////////////////////////////////// 10 | // Compare Range with array 11 | ////////////////////////////////////////////////////////////////////////// 12 | 13 | template 14 | void CheckRangeEqArray(R dst, T (&ans)[N], F f) 15 | { 16 | for (unsigned i = 0; i < N; i++) 17 | EXPECT_EQ(f(ans[i]), f(dst.next())); 18 | 19 | EXPECT_THROW(dst.next(), LinqEndException); 20 | } 21 | 22 | template 23 | void CheckRangeEqArray(R dst, T (&ans)[N]) 24 | { 25 | for (unsigned i = 0; i < N; i++) 26 | EXPECT_EQ(ans[i], dst.next()); 27 | 28 | EXPECT_THROW(dst.next(), LinqEndException); 29 | } 30 | 31 | template 32 | std::set ArrayToSet(T (&ans)[N]) 33 | { 34 | std::set res; 35 | for(unsigned i = 0; i < N; i++) 36 | res.insert(ans[i]); 37 | 38 | EXPECT_EQ(N, res.size()); 39 | 40 | return res; 41 | } 42 | 43 | template 44 | void CheckRangeEqSet(R dst, T (&ans)[N]) 45 | { 46 | std::set expected = ArrayToSet(ans); 47 | std::set actual = dst.toStdSet(); 48 | 49 | EXPECT_EQ(expected.size(), actual.size()); 50 | 51 | typename std::set::iterator it1 = expected.begin(); 52 | typename std::set::iterator it2 = actual.begin(); 53 | for(; it1 != expected.end() && it2 != actual.end(); it1++, it2++) 54 | { 55 | EXPECT_EQ(*it2, *it1); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /test/ConcatTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "CommonTests.h" 3 | 4 | #include "boolinq.h" 5 | 6 | using namespace boolinq; 7 | 8 | TEST(Concat, ArrayArray) 9 | { 10 | int src1[] = {1,2,3,4,5}; 11 | int src2[] = {6,7,8,9}; 12 | 13 | int ans[] = {1,2,3,4,5,6,7,8,9}; 14 | 15 | auto rng1 = from(src1); 16 | auto rng2 = from(src2); 17 | auto dst = rng1.concat(rng2); 18 | 19 | CheckRangeEqArray(dst, ans); 20 | } 21 | 22 | TEST(Concat, ArrayVector) 23 | { 24 | int src1[] = {1,2,3,4,5}; 25 | std::vector src2; 26 | src2.push_back(6); 27 | src2.push_back(7); 28 | src2.push_back(8); 29 | src2.push_back(9); 30 | 31 | int ans[] = {1,2,3,4,5,6,7,8,9}; 32 | 33 | auto rng1 = from(src1); 34 | auto rng2 = from(src2); 35 | auto dst = rng1.concat(rng2); 36 | 37 | CheckRangeEqArray(dst, ans); 38 | } 39 | 40 | TEST(Concat, ArrayVectorArray) 41 | { 42 | int src1[] = {1,2,3,4,5}; 43 | std::vector src2; 44 | src2.push_back(6); 45 | src2.push_back(7); 46 | src2.push_back(8); 47 | src2.push_back(9); 48 | int src3[] = {10,11,12,13,14,15}; 49 | 50 | int ans[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; 51 | 52 | auto rng1 = from(src1); 53 | auto rng2 = from(src2); 54 | auto rng3 = from(src3); 55 | auto dst = rng1.concat(rng2).concat(rng3); 56 | 57 | CheckRangeEqArray(dst, ans); 58 | } 59 | -------------------------------------------------------------------------------- /test/ContainsTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include "boolinq.h" 7 | 8 | using namespace boolinq; 9 | 10 | TEST(Contains, ThreeInts) 11 | { 12 | std::vector src; 13 | src.push_back(1); 14 | src.push_back(2); 15 | src.push_back(3); 16 | 17 | auto rng = from(src); 18 | 19 | EXPECT_TRUE(rng.contains(1)); 20 | EXPECT_TRUE(rng.contains(2)); 21 | EXPECT_TRUE(rng.contains(3)); 22 | 23 | EXPECT_FALSE(rng.contains(0)); 24 | EXPECT_FALSE(rng.contains(4)); 25 | } 26 | 27 | TEST(Contains, FiveStrings) 28 | { 29 | std::vector src; 30 | src.push_back("hello"); 31 | src.push_back("apple"); 32 | src.push_back("nokia"); 33 | src.push_back("oracle"); 34 | src.push_back("ponny"); 35 | 36 | auto rng = from(src); 37 | 38 | EXPECT_TRUE(rng.contains("hello")); 39 | EXPECT_TRUE(rng.contains("apple")); 40 | EXPECT_TRUE(rng.contains("nokia")); 41 | EXPECT_TRUE(rng.contains("oracle")); 42 | EXPECT_TRUE(rng.contains("ponny")); 43 | 44 | EXPECT_FALSE(rng.contains("dino")); 45 | EXPECT_FALSE(rng.contains("lord")); 46 | } 47 | -------------------------------------------------------------------------------- /test/CountTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include "boolinq.h" 7 | 8 | using namespace boolinq; 9 | 10 | TEST(Count, ThreeIntsVector) 11 | { 12 | std::vector src; 13 | src.push_back(1); 14 | src.push_back(2); 15 | src.push_back(3); 16 | 17 | auto rng = from(src); 18 | 19 | EXPECT_EQ(3, rng.count()); 20 | } 21 | 22 | TEST(Count, ThreeIntsList) 23 | { 24 | std::list src; 25 | src.push_back(1); 26 | src.push_back(2); 27 | src.push_back(3); 28 | 29 | auto rng = from(src); 30 | 31 | EXPECT_EQ(3, rng.count()); 32 | } 33 | 34 | TEST(Count, FiveInts) 35 | { 36 | std::vector src; 37 | src.push_back(1); 38 | src.push_back(2); 39 | src.push_back(3); 40 | src.push_back(4); 41 | src.push_back(5); 42 | 43 | auto rng = from(src); 44 | auto dst0 = rng.where([](int a){return a%2 == 0;}); 45 | auto dst1 = rng.where([](int a){return a%2 == 1;}); 46 | 47 | EXPECT_EQ(2, dst0.count()); 48 | EXPECT_EQ(3, dst1.count()); 49 | } 50 | 51 | TEST(Count, OddCount) 52 | { 53 | std::vector src; 54 | src.push_back(1); 55 | src.push_back(0); 56 | src.push_back(1); 57 | src.push_back(0); 58 | src.push_back(1); 59 | 60 | auto rng = from(src); 61 | 62 | EXPECT_EQ(2, rng.count(0)); 63 | EXPECT_EQ(3, rng.count(1)); 64 | } 65 | -------------------------------------------------------------------------------- /test/CtorTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include "CommonTests.h" 11 | 12 | #include "boolinq.h" 13 | 14 | using namespace boolinq; 15 | 16 | ////////////////////////////////////////////////////////////////////////// 17 | 18 | TEST(Ctor, ListInt) 19 | { 20 | std::list lst; 21 | lst.push_back(1); 22 | lst.push_back(2); 23 | lst.push_back(3); 24 | lst.push_back(4); 25 | lst.push_back(5); 26 | 27 | int ans[] = {1,2,3,4,5}; 28 | 29 | CheckRangeEqArray(from(lst), ans); 30 | CheckRangeEqArray(from(lst.begin(), lst.end()), ans); 31 | CheckRangeEqArray(from(lst.cbegin(), lst.cend()), ans); 32 | } 33 | 34 | TEST(Ctor, DequeInt) 35 | { 36 | std::deque dck; 37 | dck.push_back(1); 38 | dck.push_back(2); 39 | dck.push_back(3); 40 | dck.push_back(4); 41 | dck.push_back(5); 42 | 43 | int ans[] = {1,2,3,4,5}; 44 | 45 | CheckRangeEqArray(from(dck), ans); 46 | CheckRangeEqArray(from(dck.begin(), dck.end()), ans); 47 | CheckRangeEqArray(from(dck.cbegin(), dck.cend()), ans); 48 | } 49 | 50 | TEST(Ctor, VectorInt) 51 | { 52 | std::vector vec; 53 | vec.push_back(1); 54 | vec.push_back(2); 55 | vec.push_back(3); 56 | vec.push_back(4); 57 | vec.push_back(5); 58 | 59 | int ans[] = {1,2,3,4,5}; 60 | 61 | CheckRangeEqArray(from(vec), ans); 62 | CheckRangeEqArray(from(vec.begin(), vec.end()), ans); 63 | CheckRangeEqArray(from(vec.cbegin(), vec.cend()), ans); 64 | } 65 | 66 | TEST(Ctor, SetInt) 67 | { 68 | std::set set = {1,2,3,4,5}; 69 | int ans[] = {1,2,3,4,5}; 70 | 71 | CheckRangeEqSet(from(set), ans); 72 | CheckRangeEqSet(from(set.begin(), set.end()), ans); 73 | CheckRangeEqSet(from(set.cbegin(), set.cend()), ans); 74 | } 75 | 76 | //TEST(Ctor, MapInt) 77 | //{ 78 | // std::map map = {{5,1},{4,2},{3,3},{2,4},{1,5}}; 79 | // std::pair ans[] = {{5,1},{4,2},{3,3},{2,4},{1,5}}; 80 | // 81 | // CheckRangeEqArray(from(map) 82 | // .orderBy([](std::pair p){ return p.second; }), ans); 83 | // CheckRangeEqArray(from(map.begin(), map.end()) 84 | // .orderBy([](std::pair p){ return p.second; }), ans); 85 | // CheckRangeEqArray(from(map.cbegin(), map.cend()) 86 | // .orderBy([](std::pair p){ return p.second; }), ans); 87 | //} 88 | 89 | TEST(Ctor, StdArrayInt) 90 | { 91 | std::array arr = { {1,2,3,4,5} }; 92 | int ans[] = {1,2,3,4,5}; 93 | 94 | CheckRangeEqArray(from(arr), ans); 95 | CheckRangeEqArray(from(arr.begin(), arr.end()), ans); 96 | CheckRangeEqArray(from(arr.cbegin(), arr.cend()), ans); 97 | } 98 | 99 | TEST(Ctor, ArrayInt) 100 | { 101 | int arr[] = {1,2,3,4,5}; 102 | int * ptr = static_cast(arr); 103 | 104 | int ans[] = {1,2,3,4,5}; 105 | 106 | CheckRangeEqArray(from(arr), ans); 107 | CheckRangeEqArray(from(ptr, 5), ans); 108 | CheckRangeEqArray(from(ptr, ptr + 5), ans); 109 | } 110 | 111 | ////////////////////////////////////////////////////////////////////////// 112 | 113 | TEST(Ctor, OneElement) 114 | { 115 | int src[] = {5}; 116 | int ans[] = {5}; 117 | 118 | auto rng = from(src); 119 | 120 | CheckRangeEqArray(rng, ans); 121 | } 122 | 123 | TEST(Ctor, EmptyVector) 124 | { 125 | std::vector src; 126 | 127 | auto rng = from(src); 128 | 129 | EXPECT_THROW(rng.next(), LinqEndException); 130 | } 131 | -------------------------------------------------------------------------------- /test/DistinctTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include "CommonTests.h" 6 | 7 | #include "boolinq.h" 8 | 9 | using namespace boolinq; 10 | 11 | ////////////////////////////////////////////////////////////////////////// 12 | 13 | TEST(Distinct, Ints1to6) 14 | { 15 | int src[] = {4,5,3,1,4,2,1,4,6}; 16 | int ans[] = {1,2,3,4,5,6}; 17 | 18 | auto rng = from(src); 19 | auto dst = rng.distinct(); 20 | 21 | CheckRangeEqSet(dst, ans); 22 | } 23 | 24 | TEST(Distinct, IntMirrorFront) 25 | { 26 | int src[] = {3,2,1,0,1,2,3}; 27 | int ans[] = {0,1,2,3}; 28 | 29 | auto rng = from(src); 30 | auto dst = rng.distinct(); 31 | 32 | CheckRangeEqSet(dst, ans); 33 | } 34 | 35 | TEST(Distinct, ManyEqualsFront) 36 | { 37 | int src[] = {1,1,1,1}; 38 | int ans[] = {1}; 39 | 40 | auto rng = from(src); 41 | auto dst = rng.distinct(); 42 | 43 | CheckRangeEqSet(dst, ans); 44 | } 45 | 46 | TEST(Distinct, ManyEqualsWithOneFront) 47 | { 48 | int src[] = {1,1,2,1}; 49 | int ans[] = {1,2}; 50 | 51 | auto rng = from(src); 52 | auto dst = rng.distinct(); 53 | 54 | CheckRangeEqSet(dst, ans); 55 | } 56 | 57 | TEST(Distinct, OneFieldFront) 58 | { 59 | struct Man 60 | { 61 | std::string name; 62 | int age; 63 | 64 | bool operator < (const Man & man) const 65 | { 66 | return (name < man.name) 67 | || (name == man.name && age < man.age); 68 | } 69 | 70 | bool operator == (const Man & man) const 71 | { 72 | return (name == man.name); 73 | } 74 | 75 | bool operator == (const std::string & manName) const 76 | { 77 | return (this->name == manName); 78 | } 79 | }; 80 | 81 | Man src[] = 82 | { 83 | {"Anton",1}, 84 | {"Taran",2}, 85 | {"Poker",3}, 86 | {"Agata",4}, 87 | {"Mango",2}, 88 | {"Banan",1}, 89 | }; 90 | 91 | std::string ans[] = 92 | { 93 | "Anton", 94 | "Taran", 95 | "Poker", 96 | "Agata", 97 | }; 98 | 99 | auto rng = from(src); 100 | auto dst = rng.distinct([](const Man & man){return man.age;}); 101 | 102 | CheckRangeEqSet(dst, ans); 103 | } 104 | -------------------------------------------------------------------------------- /test/DotCallTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include "CommonTests.h" 8 | 9 | #include "boolinq.h" 10 | 11 | using namespace boolinq; 12 | 13 | ////////////////////////////////////////////////////////////////////////// 14 | 15 | TEST(DotCall, BytesRange) 16 | { 17 | unsigned src[] = {0x12345678,0xAABBCCDD}; 18 | int ansFL[] = 19 | { 20 | 0x78,0x56,0x34,0x12, 21 | 0xDD,0xCC,0xBB,0xAA, 22 | }; 23 | int ansLF[] = 24 | { 25 | 0x12,0x34,0x56,0x78, 26 | 0xAA,0xBB,0xCC,0xDD, 27 | }; 28 | 29 | auto dstFL1 = from(src).bytes(); 30 | auto dstFL2 = from(src).bytes(BytesFirstToLast); 31 | auto dstLF1 = from(src).bytes(BytesLastToFirst); 32 | 33 | CheckRangeEqArray(dstFL1, ansFL); 34 | CheckRangeEqArray(dstFL2, ansFL); 35 | CheckRangeEqArray(dstLF1, ansLF); 36 | } 37 | 38 | ////////////////////////////////////////////////////////////////////////// 39 | 40 | TEST(DotCall, UnbytesRange) 41 | { 42 | unsigned char src[] = 43 | { 44 | 0x78,0x56,0x34,0x12, 45 | 0xDD,0xCC,0xBB,0xAA, 46 | }; 47 | unsigned ansFL[] = {0x12345678,0xAABBCCDD}; 48 | unsigned ansLF[] = {0x78563412,0xDDCCBBAA}; 49 | 50 | auto dstFL1 = from(src).unbytes(); 51 | auto dstFL2 = from(src).unbytes(BytesFirstToLast); 52 | auto dstLF1 = from(src).unbytes(BytesLastToFirst); 53 | 54 | CheckRangeEqArray(dstFL1, ansFL); 55 | CheckRangeEqArray(dstFL2, ansFL); 56 | CheckRangeEqArray(dstLF1, ansLF); 57 | } 58 | 59 | ////////////////////////////////////////////////////////////////////////// 60 | 61 | TEST(DotCall, BitsRangeHL) 62 | { 63 | unsigned src[] = {0xAABBCCDD}; 64 | int ansFL[] = 65 | { 66 | 1,1,0,1,1,1,0,1, 67 | 1,1,0,0,1,1,0,0, 68 | 1,0,1,1,1,0,1,1, 69 | 1,0,1,0,1,0,1,0, 70 | }; 71 | int ansLF[] = 72 | { 73 | 1,0,1,0,1,0,1,0, 74 | 1,0,1,1,1,0,1,1, 75 | 1,1,0,0,1,1,0,0, 76 | 1,1,0,1,1,1,0,1, 77 | }; 78 | 79 | auto dstFL1 = from(src).bits(); 80 | auto dstFL2 = from(src).bits(BitsHighToLow); 81 | auto dstFL3 = from(src).bits(BitsHighToLow, BytesFirstToLast); 82 | auto dstLF1 = from(src).bits(BitsHighToLow, BytesLastToFirst); 83 | 84 | CheckRangeEqArray(dstFL1, ansFL); 85 | CheckRangeEqArray(dstFL2, ansFL); 86 | CheckRangeEqArray(dstFL3, ansFL); 87 | CheckRangeEqArray(dstLF1, ansLF); 88 | } 89 | 90 | TEST(DotCall, BitsRangeLH) 91 | { 92 | unsigned src[] = {0xAABBCCDD}; 93 | int ansFL[] = 94 | { 95 | 1,0,1,1,1,0,1,1, 96 | 0,0,1,1,0,0,1,1, 97 | 1,1,0,1,1,1,0,1, 98 | 0,1,0,1,0,1,0,1, 99 | }; 100 | int ansLF[] = 101 | { 102 | 0,1,0,1,0,1,0,1, 103 | 1,1,0,1,1,1,0,1, 104 | 0,0,1,1,0,0,1,1, 105 | 1,0,1,1,1,0,1,1, 106 | }; 107 | 108 | auto dstFL1 = from(src).bits(BitsLowToHigh); 109 | auto dstFL2 = from(src).bits(BitsLowToHigh, BytesFirstToLast); 110 | auto dstLF1 = from(src).bits(BitsLowToHigh, BytesLastToFirst); 111 | 112 | CheckRangeEqArray(dstFL1, ansFL); 113 | CheckRangeEqArray(dstFL2, ansFL); 114 | CheckRangeEqArray(dstLF1, ansLF); 115 | } 116 | 117 | ////////////////////////////////////////////////////////////////////////// 118 | 119 | TEST(DotCall, UnbitsRangeHLFL) 120 | { 121 | int src[] = 122 | { 123 | 1,1,0,1,1,1,0,1, 124 | 1,1,0,0,1,1,0,0, 125 | 1,0,1,1,1,0,1,1, 126 | 1,0,1,0,1,0,1,0 127 | }; 128 | int ans_4b[] = {0xDD,0xCC,0xBB,0xAA}; 129 | unsigned ans_1i[] = {0xAABBCCDD}; 130 | unsigned ansLF_1i[] = {0xDDCCBBAA}; 131 | 132 | auto dst1_4b = from(src).unbits(); 133 | auto dst2_4b = from(src).unbits(BitsHighToLow); 134 | auto dst1_1i = from(src).unbits(BitsHighToLow); 135 | auto dst2_1i = from(src).unbits(BitsHighToLow, BytesFirstToLast); 136 | auto dst3_1i = from(src).unbits(BitsHighToLow, BytesLastToFirst); 137 | 138 | CheckRangeEqArray(dst1_4b, ans_4b); 139 | CheckRangeEqArray(dst2_4b, ans_4b); 140 | CheckRangeEqArray(dst1_1i, ans_1i); 141 | CheckRangeEqArray(dst2_1i, ans_1i); 142 | CheckRangeEqArray(dst3_1i, ansLF_1i); 143 | } 144 | 145 | //TEST(DotCall, UnbitsRangeLH) 146 | //{ 147 | // int src[] = {0xAABBCCDD}; 148 | // int ansFL[] = 149 | // { 150 | // 1,0,1,1,1,0,1,1, 151 | // 0,0,1,1,0,0,1,1, 152 | // 1,1,0,1,1,1,0,1, 153 | // 0,1,0,1,0,1,0,1, 154 | // }; 155 | // int ansLF[] = 156 | // { 157 | // 0,1,0,1,0,1,0,1, 158 | // 1,1,0,1,1,1,0,1, 159 | // 0,0,1,1,0,0,1,1, 160 | // 1,0,1,1,1,0,1,1, 161 | // }; 162 | // 163 | // auto dstFL1 = from(src).bits(); 164 | // auto dstFL2 = from(src).bits(); 165 | // auto dstLF1 = from(src).bits(); 166 | // 167 | // CheckRangeEqArray(dstFL1, ansFL); 168 | // CheckRangeEqArray(dstFL2, ansFL); 169 | // CheckRangeEqArray(dstLF1, ansLF); 170 | //} 171 | 172 | -------------------------------------------------------------------------------- /test/ElementAtTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include "boolinq.h" 7 | 8 | using namespace boolinq; 9 | 10 | TEST(ElementAt, ThreeInts) 11 | { 12 | std::vector src; 13 | src.push_back(1); 14 | src.push_back(2); 15 | src.push_back(3); 16 | 17 | auto rng = from(src); 18 | 19 | EXPECT_EQ(1, rng.elementAt(0)); 20 | EXPECT_EQ(2, rng.elementAt(1)); 21 | EXPECT_EQ(3, rng.elementAt(2)); 22 | } 23 | 24 | TEST(ElementAt, FiveStrings) 25 | { 26 | std::vector src; 27 | src.push_back("hello"); 28 | src.push_back("apple"); 29 | src.push_back("nokia"); 30 | src.push_back("oracle"); 31 | src.push_back("ponny"); 32 | 33 | auto rng = from(src); 34 | 35 | EXPECT_EQ("hello", rng.elementAt(0)); 36 | EXPECT_EQ("apple", rng.elementAt(1)); 37 | EXPECT_EQ("nokia", rng.elementAt(2)); 38 | EXPECT_EQ("oracle", rng.elementAt(3)); 39 | EXPECT_EQ("ponny", rng.elementAt(4)); 40 | } 41 | -------------------------------------------------------------------------------- /test/FirstTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include "boolinq.h" 8 | 9 | using namespace boolinq; 10 | 11 | TEST(First, ThreeElements) 12 | { 13 | std::vector src = {1,2,3}; 14 | 15 | EXPECT_EQ(1, from(src).first()); 16 | EXPECT_EQ(2, from(src).first([](int a){return a%2 == 0;})); 17 | EXPECT_EQ(1, from(src).firstOrDefault()); 18 | EXPECT_EQ(2, from(src).firstOrDefault([](int a){return a%2 == 0;})); 19 | } 20 | 21 | TEST(First, OneElement) 22 | { 23 | std::vector src = {1}; 24 | 25 | EXPECT_EQ(1, from(src).first()); 26 | EXPECT_THROW(from(src).first([](int a){return a%2 == 0;}), LinqEndException); 27 | EXPECT_EQ(1, from(src).firstOrDefault()); 28 | EXPECT_EQ(0, from(src).firstOrDefault([](int a){return a%2 == 0;})); 29 | } 30 | 31 | TEST(First, NoneElements) 32 | { 33 | std::vector src = {}; 34 | 35 | EXPECT_THROW(from(src).first(), LinqEndException); 36 | EXPECT_THROW(from(src).first([](int a){return a%2 == 0;}), LinqEndException); 37 | EXPECT_EQ(0, from(src).firstOrDefault()); 38 | EXPECT_EQ(0, from(src).firstOrDefault([](int a){return a%2 == 0;})); 39 | } 40 | 41 | TEST(First, NoneElementsWithArg) 42 | { 43 | std::vector src = {}; 44 | 45 | EXPECT_EQ(2, from(src).firstOrDefault(2)); 46 | EXPECT_EQ(3, from(src).firstOrDefault([](int a){return a%2 == 0;}, 3)); 47 | } 48 | -------------------------------------------------------------------------------- /test/ForEachTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include "boolinq.h" 8 | 9 | using namespace boolinq; 10 | 11 | TEST(ForEach, ThreeCharsSum) 12 | { 13 | std::vector src; 14 | src.push_back('a'); 15 | src.push_back('b'); 16 | src.push_back('c'); 17 | 18 | std::string str = ""; 19 | from(src).for_each([&](char a){str += a;}); 20 | 21 | EXPECT_EQ("abc", str); 22 | } 23 | 24 | TEST(ForEach, ThreeCharsUpperSum) 25 | { 26 | std::vector src; 27 | src.push_back('a'); 28 | src.push_back('b'); 29 | src.push_back('c'); 30 | 31 | std::string str = ""; 32 | from(src).for_each([&](char a){str += a + ('A' - 'a');}); 33 | 34 | EXPECT_EQ("ABC", str); 35 | } 36 | 37 | TEST(ForEach, ThreeIntsSum) 38 | { 39 | std::vector src; 40 | src.push_back(10); 41 | src.push_back(20); 42 | src.push_back(30); 43 | 44 | int sum = 0; 45 | from(src).for_each([&](int a){sum += a;}); 46 | 47 | EXPECT_EQ(60, sum); 48 | } 49 | -------------------------------------------------------------------------------- /test/GroupByTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include "CommonTests.h" 6 | 7 | #include "boolinq.h" 8 | 9 | using namespace boolinq; 10 | 11 | ////////////////////////////////////////////////////////////////////////// 12 | 13 | TEST(GroupBy, Ints) 14 | { 15 | int arr[] = {0,1,2,3,4,5,6,7,8,9}; 16 | 17 | int ans_0[] = {0,3,6,9}; 18 | int ans_1[] = {1,4,7}; 19 | int ans_2[] = {2,5,8}; 20 | 21 | auto dst = from(arr).groupBy([](int a){return a % 3;}); 22 | 23 | EXPECT_EQ(0, dst.elementAt(0).first); 24 | EXPECT_EQ(1, dst.elementAt(1).first); 25 | EXPECT_EQ(2, dst.elementAt(2).first); 26 | CheckRangeEqArray(dst.elementAt(0).second, ans_0); 27 | CheckRangeEqArray(dst.elementAt(1).second, ans_1); 28 | CheckRangeEqArray(dst.elementAt(2).second, ans_2); 29 | 30 | EXPECT_THROW(dst.elementAt(3), LinqEndException); 31 | } 32 | 33 | ////////////////////////////////////////////////////////////////////////// 34 | 35 | TEST(GroupBy, CountChildrenByAge) 36 | { 37 | struct Child 38 | { 39 | std::string name; 40 | int age; 41 | 42 | bool operator == (const Child & rhs) const 43 | { 44 | return (name == rhs.name) && (age == rhs.age); 45 | } 46 | }; 47 | 48 | Child children[] = { 49 | {"Piter", 12}, 50 | {"Bella", 14}, 51 | {"Torry", 15}, 52 | {"Holly", 12}, 53 | {"Zamza", 13}, 54 | }; 55 | 56 | Child ans_false[] = { 57 | {"Bella", 14}, 58 | {"Torry", 15}, 59 | }; 60 | 61 | Child ans_true[] = { 62 | {"Piter", 12}, 63 | {"Holly", 12}, 64 | {"Zamza", 13}, 65 | }; 66 | 67 | auto dst = from(children).groupBy([](const Child & a){return a.age < 14;}); 68 | 69 | EXPECT_EQ(true, dst.elementAt(0).first); 70 | EXPECT_EQ(false, dst.elementAt(1).first); 71 | CheckRangeEqArray(dst.elementAt(0).second, ans_true); 72 | CheckRangeEqArray(dst.elementAt(1).second, ans_false); 73 | 74 | EXPECT_THROW(dst.elementAt(2), LinqEndException); 75 | } 76 | 77 | ////////////////////////////////////////////////////////////////////////// 78 | 79 | TEST(GroupBy, CountChildrenByName) 80 | { 81 | struct Human 82 | { 83 | std::string name; 84 | int age; 85 | 86 | bool operator == (const Human & rhs) const 87 | { 88 | return (name == rhs.name) && (age == rhs.age); 89 | } 90 | }; 91 | 92 | std::vector people = { 93 | {"Kevin", 14}, 94 | {"Kevin", 24}, 95 | {"Kevin", 34}, 96 | {"Kevin", 44}, 97 | {"Anton", 18}, 98 | {"Agata", 17}, 99 | {"Terra", 20}, 100 | {"Terra", 21}, 101 | {"Layer", 15}, 102 | }; 103 | 104 | Human ans_1[] = { 105 | {"Kevin", 14}, 106 | {"Kevin", 24}, 107 | {"Kevin", 34}, 108 | {"Kevin", 44}, 109 | }; 110 | 111 | Human ans_2[] = { 112 | {"Anton", 18}, 113 | }; 114 | 115 | Human ans_3[] = { 116 | {"Agata", 17}, 117 | }; 118 | 119 | Human ans_4[] = { 120 | {"Terra", 20}, 121 | {"Terra", 21}, 122 | }; 123 | 124 | Human ans_5[] = { 125 | {"Layer", 15}, 126 | }; 127 | 128 | auto dst = from(people).groupBy([](const Human & a){return a.name;}); 129 | 130 | EXPECT_EQ("Kevin", dst.elementAt(0).first); 131 | EXPECT_EQ("Anton", dst.elementAt(1).first); 132 | EXPECT_EQ("Agata", dst.elementAt(2).first); 133 | EXPECT_EQ("Terra", dst.elementAt(3).first); 134 | EXPECT_EQ("Layer", dst.elementAt(4).first); 135 | CheckRangeEqArray(dst.elementAt(0).second, ans_1); 136 | CheckRangeEqArray(dst.elementAt(1).second, ans_2); 137 | CheckRangeEqArray(dst.elementAt(2).second, ans_3); 138 | CheckRangeEqArray(dst.elementAt(3).second, ans_4); 139 | CheckRangeEqArray(dst.elementAt(4).second, ans_5); 140 | 141 | EXPECT_THROW(dst.elementAt(5), LinqEndException); 142 | } -------------------------------------------------------------------------------- /test/GroupByTestComplex.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include "CommonTests.h" 6 | 7 | #include "boolinq.h" 8 | 9 | using namespace boolinq; 10 | 11 | ////////////////////////////////////////////////////////////////////////// 12 | 13 | TEST(GroupBy, CountTaxes) 14 | { 15 | struct Tax { 16 | std::string name; 17 | int amount_1; 18 | int amount_2; 19 | 20 | bool operator ==(const Tax & tax) const { 21 | return name == tax.name 22 | && amount_1 == tax.amount_1 23 | && amount_2 == tax.amount_2; 24 | } 25 | }; 26 | 27 | std::vector taxes = { 28 | {"tax 1", 1, 1}, 29 | {"tax 2", 1, 1}, 30 | {"tax 1", 2, 2}, 31 | {"tax 3", 3, 3}, 32 | {"tax 1", 4, 4}, 33 | }; 34 | 35 | Tax ans[] = { 36 | {"tax 1", 7, 7}, 37 | {"tax 2", 1, 1}, 38 | {"tax 3", 3, 3}, 39 | }; 40 | 41 | auto dst = from(taxes) 42 | .groupBy([](const Tax & a){return a.name;}) 43 | .select([](const auto & pair){ // use of auto here needs c++14 44 | return Tax { 45 | pair.first, 46 | pair.second.sum([](const Tax & a){return a.amount_1;}), 47 | pair.second.sum([](const Tax & a){return a.amount_2;}) 48 | }; 49 | }); 50 | 51 | CheckRangeEqArray(dst, ans); 52 | } -------------------------------------------------------------------------------- /test/LastTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include "boolinq.h" 8 | 9 | using namespace boolinq; 10 | 11 | TEST(Last, ThreeElements) 12 | { 13 | std::vector src = {1,2,3}; 14 | 15 | EXPECT_EQ(3, from(src).last()); 16 | EXPECT_EQ(2, from(src).last([](int a){return a%2 == 0;})); 17 | EXPECT_EQ(3, from(src).lastOrDefault()); 18 | EXPECT_EQ(2, from(src).lastOrDefault([](int a){return a%2 == 0;})); 19 | } 20 | 21 | TEST(Last, OneElement) 22 | { 23 | std::vector src = {1}; 24 | 25 | EXPECT_EQ(1, from(src).last()); 26 | EXPECT_THROW(from(src).last([](int a){return a%2 == 0;}), LinqEndException); 27 | EXPECT_EQ(1, from(src).lastOrDefault()); 28 | EXPECT_EQ(0, from(src).lastOrDefault([](int a){return a%2 == 0;})); 29 | } 30 | 31 | TEST(Last, NoneElements) 32 | { 33 | std::vector src = {}; 34 | 35 | EXPECT_THROW(from(src).last(), LinqEndException); 36 | EXPECT_THROW(from(src).last([](int a){return a%2 == 0;}), LinqEndException); 37 | EXPECT_EQ(0, from(src).lastOrDefault()); 38 | EXPECT_EQ(0, from(src).lastOrDefault([](int a){return a%2 == 0;})); 39 | } 40 | 41 | TEST(Last, NoneElementsWithArgument) { 42 | std::vector src = {}; 43 | 44 | EXPECT_EQ(2, from(src).lastOrDefault(2)); 45 | EXPECT_EQ(3, from(src).lastOrDefault([](int a) { return a % 2 == 0; }, 3)); 46 | } 47 | -------------------------------------------------------------------------------- /test/LinqTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include "boolinq.h" 9 | 10 | using namespace boolinq; 11 | 12 | // Where Tests 13 | 14 | TEST(Linq, WhereOdd) 15 | { 16 | std::vector src; 17 | src.push_back(1); 18 | src.push_back(2); 19 | src.push_back(3); 20 | src.push_back(4); 21 | src.push_back(5); 22 | src.push_back(6); 23 | 24 | auto rng = from(src).where([](int a){return a%2 == 1;}); 25 | 26 | for (int i = 1; i <= 5; i+=2) 27 | { 28 | EXPECT_EQ(i, rng.next()); 29 | } 30 | 31 | EXPECT_THROW(rng.next(), LinqEndException); 32 | } 33 | 34 | TEST(Linq, WhereOdd_WhereLess) 35 | { 36 | std::vector src; 37 | src.push_back(1); 38 | src.push_back(2); 39 | src.push_back(3); 40 | src.push_back(4); 41 | src.push_back(5); 42 | src.push_back(6); 43 | src.push_back(7); 44 | src.push_back(8); 45 | 46 | auto rng = from(src).where([](int a){return a%2 == 1;}) 47 | .where([](int a){return a < 4;}); 48 | 49 | for (int i = 1; i <= 3; i+=2) 50 | { 51 | EXPECT_EQ(i, rng.next()); 52 | } 53 | 54 | EXPECT_THROW(rng.next(), LinqEndException); 55 | } 56 | 57 | TEST(Linq, WhereLess_WhereOdd) 58 | { 59 | std::vector src; 60 | src.push_back(1); 61 | src.push_back(2); 62 | src.push_back(3); 63 | src.push_back(4); 64 | src.push_back(5); 65 | src.push_back(6); 66 | src.push_back(7); 67 | src.push_back(8); 68 | 69 | auto rng = from(src).where([](int a){return a < 4;}) 70 | .where([](int a){return a%2 == 1;}) 71 | .toStdVector(); 72 | 73 | std::vector ans; 74 | ans.push_back(1); 75 | ans.push_back(3); 76 | 77 | EXPECT_EQ(ans,rng); 78 | } 79 | 80 | TEST(Linq, WhereLess_WhereOdd_OrderByDesc) 81 | { 82 | std::vector src; 83 | src.push_back(1); 84 | src.push_back(2); 85 | src.push_back(3); 86 | src.push_back(4); 87 | src.push_back(5); 88 | src.push_back(6); 89 | src.push_back(7); 90 | src.push_back(8); 91 | 92 | auto rng = from(src).where([](int a){return a < 6;}) 93 | .where([](int a){return a%2 == 1;}) 94 | .orderBy([](int a){return -a;}) 95 | .toStdVector(); 96 | 97 | std::vector ans; 98 | ans.push_back(5); 99 | ans.push_back(3); 100 | ans.push_back(1); 101 | 102 | EXPECT_EQ(ans,rng); 103 | } 104 | 105 | TEST(Linq, WhereOdd_ToVector) 106 | { 107 | std::vector src; 108 | src.push_back(1); 109 | src.push_back(2); 110 | src.push_back(3); 111 | src.push_back(4); 112 | src.push_back(5); 113 | src.push_back(6); 114 | src.push_back(7); 115 | src.push_back(8); 116 | 117 | auto dst = from(src).where([](int a){return a%2 == 1;}) 118 | .toStdVector(); 119 | 120 | std::vector ans; 121 | ans.push_back(1); 122 | ans.push_back(3); 123 | ans.push_back(5); 124 | ans.push_back(7); 125 | 126 | EXPECT_EQ(ans,dst); 127 | } 128 | 129 | TEST(Linq, WhereOdd_WhereLess_SelectMul2_ToVector) 130 | { 131 | std::vector src; 132 | src.push_back(1); 133 | src.push_back(2); 134 | src.push_back(3); 135 | src.push_back(4); 136 | src.push_back(5); 137 | src.push_back(6); 138 | src.push_back(7); 139 | src.push_back(8); 140 | 141 | auto dst = from(src).where([](int a){return a%2 == 1;}) 142 | .where([](int a){return a < 6;}) 143 | .select([](int a){return a*2;}) 144 | .toStdVector(); 145 | 146 | std::vector ans; 147 | ans.push_back(2); 148 | ans.push_back(6); 149 | ans.push_back(10); 150 | 151 | EXPECT_EQ(ans,dst); 152 | } 153 | 154 | TEST(Linq, WhereOdd_WhereLess_SelectMul2_Reverse_ToVector) 155 | { 156 | std::vector src; 157 | src.push_back(1); 158 | src.push_back(2); 159 | src.push_back(3); 160 | src.push_back(4); 161 | src.push_back(5); 162 | src.push_back(6); 163 | src.push_back(7); 164 | src.push_back(8); 165 | 166 | auto dst = from(src).where([](int a){return a%2 == 1;}) 167 | .where([](int a){return a < 6;}) 168 | .select([](int a){return a*2;}) 169 | .reverse() 170 | .toStdVector(); 171 | 172 | std::vector ans; 173 | ans.push_back(10); 174 | ans.push_back(6); 175 | ans.push_back(2); 176 | 177 | EXPECT_EQ(ans,dst); 178 | } 179 | 180 | TEST(Linq, WhereOdd_Reverse_Reverse) 181 | { 182 | std::vector src; 183 | src.push_back(1); 184 | src.push_back(2); 185 | src.push_back(3); 186 | src.push_back(4); 187 | src.push_back(5); 188 | src.push_back(6); 189 | src.push_back(7); 190 | src.push_back(8); 191 | 192 | auto dst = from(src).where([](int a){return a%2 == 1;}) 193 | .reverse() 194 | .where([](int a){return a < 4;}) 195 | .reverse() 196 | .toStdVector(); 197 | 198 | std::vector ans; 199 | ans.push_back(1); 200 | ans.push_back(3); 201 | 202 | EXPECT_EQ(ans,dst); 203 | } 204 | 205 | ////////////////////////////////////////////////////////////////////////// 206 | 207 | TEST(Linq, Pointer_Front) 208 | { 209 | int src[] = {1,2,3,4,5}; 210 | 211 | auto dst = from(static_cast(src), static_cast(src) + 5); 212 | 213 | for(int i = 1; i <= 5; i++) 214 | { 215 | EXPECT_EQ(i, dst.next()); 216 | } 217 | 218 | EXPECT_THROW(dst.next(), LinqEndException); 219 | } 220 | 221 | 222 | ////////////////////////////////////////////////////////////////////////// 223 | 224 | TEST(Linq, Array_Front) 225 | { 226 | int src[] = {1,2,3,4,5}; 227 | 228 | auto dst = from(src); 229 | 230 | for(int i = 1; i <= 5; i++) 231 | { 232 | EXPECT_EQ(i, dst.next()); 233 | } 234 | 235 | EXPECT_THROW(dst.next(), LinqEndException); 236 | } 237 | 238 | ////////////////////////////////////////////////////////////////////////// 239 | 240 | TEST(Linq, Creations) 241 | { 242 | std::vector vec; 243 | vec.push_back(1); 244 | vec.push_back(2); 245 | vec.push_back(3); 246 | vec.push_back(4); 247 | vec.push_back(5); 248 | int arr[] = {1,2,3,4,5}; 249 | //const int carr[] = {1,2,3,4,5}; 250 | int * ptr = static_cast(arr); 251 | //const int * cptr = const_cast(arr); 252 | 253 | auto dst_vec = from(vec); 254 | auto dst_arr = from(arr); 255 | //auto dst_carr = from(carr); 256 | auto dst_ptr = from(ptr, ptr+5); 257 | //auto dst_cptr = from(cptr, cptr+5); 258 | auto dst_ptr_length = from(ptr, 5); 259 | //auto dst_cptr_length = from(cptr, 5); 260 | auto dst_vec_iter = from(vec.begin(), vec.end()); 261 | //auto dst_vec_citer = from(vec.cbegin(), vec.cend()); 262 | } 263 | 264 | ////////////////////////////////////////////////////////////////////////// 265 | 266 | TEST(Linq, MessagesCountUniqueContacts) 267 | { 268 | struct Message 269 | { 270 | std::string PhoneA; 271 | std::string PhoneB; 272 | std::string Text; 273 | 274 | bool operator < (const Message & rhs) const 275 | { 276 | return (PhoneA < rhs.PhoneA) 277 | || ((PhoneA == rhs.PhoneA) && (PhoneB < rhs.PhoneB)) 278 | || ((PhoneA == rhs.PhoneA) && (PhoneB == rhs.PhoneB) && (Text < rhs.Text)); 279 | } 280 | }; 281 | 282 | Message messages[] = 283 | { 284 | {"Anton","Denis","Hello, friend!"}, 285 | {"Denis","Write","OLOLO"}, 286 | {"Anton","Papay","WTF?"}, 287 | {"Denis","Maloy","How r u?"}, 288 | {"Denis","Write","Param-pareram!"}, 289 | }; 290 | 291 | int DenisUniqueContactCount = from(messages) 292 | .where( [](const Message & msg){return msg.PhoneA == "Denis";}) 293 | .distinct([](const Message & msg){return msg.PhoneB;}) 294 | .count(); 295 | 296 | EXPECT_EQ(2, DenisUniqueContactCount); 297 | } 298 | 299 | ////////////////////////////////////////////////////////////////////////// 300 | 301 | TEST(Linq, ForwardIterating) 302 | { 303 | std::stringstream stream("0123456789"); 304 | auto dst = from(std::istream_iterator(stream), 305 | std::istream_iterator()) 306 | .where( [](char a){return a % 2 == 0;}) 307 | .select([](char a){return std::string(1,a);}) 308 | .sum(); 309 | 310 | EXPECT_EQ("02468", dst); 311 | } 312 | -------------------------------------------------------------------------------- /test/MaxTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include "boolinq.h" 7 | 8 | using namespace boolinq; 9 | 10 | TEST(Max, ThreeInts) 11 | { 12 | std::vector src; 13 | src.push_back(1); 14 | src.push_back(2); 15 | src.push_back(3); 16 | 17 | auto rng = from(src); 18 | 19 | EXPECT_EQ(3, rng.max()); 20 | EXPECT_EQ(1, rng.max([](int a){return -a;})); 21 | } 22 | 23 | TEST(Max, FiveStrings) 24 | { 25 | std::vector src; 26 | src.push_back("hell"); 27 | src.push_back("apple"); 28 | src.push_back("zip"); 29 | 30 | auto rng = from(src); 31 | 32 | EXPECT_EQ("zip", rng.max()); 33 | EXPECT_EQ("apple", rng.max([](std::string s){return s.size();})); 34 | } 35 | -------------------------------------------------------------------------------- /test/MinTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include "boolinq.h" 7 | 8 | using namespace boolinq; 9 | 10 | TEST(Min, ThreeInts) 11 | { 12 | std::vector src; 13 | src.push_back(1); 14 | src.push_back(2); 15 | src.push_back(3); 16 | 17 | auto rng = from(src); 18 | 19 | EXPECT_EQ(1, rng.min()); 20 | EXPECT_EQ(3, rng.min([](int a){return -a;})); 21 | } 22 | 23 | TEST(Min, FiveStrings) 24 | { 25 | std::vector src; 26 | src.push_back("hell"); 27 | src.push_back("apple"); 28 | src.push_back("zip"); 29 | 30 | auto rng = from(src); 31 | 32 | EXPECT_EQ("apple", rng.min()); 33 | EXPECT_EQ("zip", rng.min([](const std::string & s){return s.size();})); 34 | } 35 | -------------------------------------------------------------------------------- /test/OrderByTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include "CommonTests.h" 6 | 7 | #include "boolinq.h" 8 | 9 | using namespace boolinq; 10 | 11 | ////////////////////////////////////////////////////////////////////////// 12 | 13 | TEST(OrderBy, RandomIntsWithDuplicates) 14 | { 15 | int src[] = {4,5,3,1,4,2,1,4,6}; 16 | int ans[] = {1,1,2,3,4,4,4,5,6}; 17 | 18 | auto rng = from(src); 19 | auto dst = rng.orderBy(); 20 | 21 | CheckRangeEqArray(dst, ans); 22 | } 23 | 24 | TEST(OrderBy, ReverseInts) 25 | { 26 | int src[] = {4,3,2,1}; 27 | int ans[] = {1,2,3,4}; 28 | 29 | auto rng = from(src); 30 | auto dst = rng.orderBy(); 31 | 32 | CheckRangeEqArray(dst, ans); 33 | } 34 | 35 | TEST(OrderBy, ThreeElements) 36 | { 37 | int src[] = {1,3,2}; 38 | int ans[] = {1,2,3}; 39 | 40 | auto rng = from(src); 41 | auto dst = rng.orderBy(); 42 | 43 | CheckRangeEqArray(dst, ans); 44 | } 45 | 46 | ////////////////////////////////////////////////////////////////////////// 47 | 48 | TEST(OrderBy, OneElement) 49 | { 50 | int src[] = {5}; 51 | int ans[] = {5}; 52 | 53 | auto rng = from(src); 54 | auto dst = rng.orderBy(); 55 | 56 | CheckRangeEqArray(dst, ans); 57 | } 58 | 59 | TEST(OrderBy, NoElements) 60 | { 61 | std::vector src; 62 | 63 | auto rng = from(src); 64 | auto dst = rng.orderBy(); 65 | 66 | EXPECT_THROW(dst.next(), LinqEndException); 67 | } 68 | 69 | ////////////////////////////////////////////////////////////////////////// 70 | 71 | TEST(OrderBy, RandomStringByContent) 72 | { 73 | std::string src[] = 74 | { 75 | "microsoft", 76 | "intel", 77 | "nokia", 78 | "apple", 79 | "oracle", 80 | "sun", 81 | }; 82 | 83 | std::string ans[] = 84 | { 85 | "apple", 86 | "intel", 87 | "microsoft", 88 | "nokia", 89 | "oracle", 90 | "sun", 91 | }; 92 | 93 | auto rng = from(src); 94 | auto dst = rng.orderBy(); 95 | 96 | CheckRangeEqArray(dst, ans); 97 | } 98 | 99 | TEST(OrderBy, RandomStringByLength) 100 | { 101 | std::string src[] = 102 | { 103 | "microsoft", 104 | "intel", 105 | "nokia", 106 | "apple", 107 | "oracle", 108 | "sun", 109 | }; 110 | 111 | std::string ans[] = 112 | { 113 | "sun", 114 | "intel", 115 | "nokia", 116 | "apple", 117 | "oracle", 118 | "microsoft", 119 | }; 120 | 121 | auto rng = from(src); 122 | auto dst = rng.orderBy([](std::string a){return a.size();}); 123 | 124 | CheckRangeEqArray(dst, ans, [](const std::string & s){return s.size();}); 125 | } 126 | -------------------------------------------------------------------------------- /test/PrependTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include "CommonTests.h" 6 | 7 | #include "boolinq.h" 8 | 9 | using namespace boolinq; 10 | 11 | TEST(Prepend, ThreePlusOne) 12 | { 13 | std::vector src = {1,2,3}; 14 | 15 | auto rng = from(src).prepend(4); 16 | int ans[] = {4,1,2,3}; 17 | 18 | CheckRangeEqArray(rng, ans); 19 | } 20 | 21 | TEST(Prepend, ThreePlusTwo) 22 | { 23 | std::vector src = {1,2,3}; 24 | 25 | auto rng = from(src).prepend(4, 5); 26 | int ans[] = {4,5,1,2,3}; 27 | 28 | CheckRangeEqArray(rng, ans); 29 | } 30 | 31 | TEST(Prepend, ZeroPlusTwo) 32 | { 33 | std::vector src; 34 | 35 | auto rng = from(src).prepend(7,8); 36 | int ans[] = {7,8}; 37 | 38 | CheckRangeEqArray(rng, ans); 39 | } -------------------------------------------------------------------------------- /test/RangeTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include "CommonTests.h" 6 | 7 | #include "boolinq.h" 8 | 9 | using namespace boolinq; 10 | 11 | TEST(Range, OneToFive) 12 | { 13 | int ans[] = {1,2,3,4}; 14 | 15 | CheckRangeEqArray(range(1,5,1), ans); 16 | } 17 | 18 | TEST(Range, OneToFiveStep2) 19 | { 20 | int ans[] = {1,3}; 21 | 22 | CheckRangeEqArray(range(1,5,2), ans); 23 | } -------------------------------------------------------------------------------- /test/ReverseTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include "CommonTests.h" 8 | 9 | #include "boolinq.h" 10 | 11 | using namespace boolinq; 12 | 13 | TEST(Reverse, IntVector) 14 | { 15 | int src[] = {1,2,3,4}; 16 | int ans[] = {4,3,2,1}; 17 | 18 | auto rng = from(src); 19 | auto dst = rng.reverse(); 20 | 21 | CheckRangeEqArray(dst, ans); 22 | } 23 | 24 | TEST(Reverse, DoubleReverse) 25 | { 26 | int src[] = {1,2,3,4}; 27 | int ans[] = {1,2,3,4}; 28 | 29 | auto rng = from(src); 30 | auto dst = rng.reverse().reverse(); 31 | 32 | CheckRangeEqArray(dst, ans); 33 | } 34 | -------------------------------------------------------------------------------- /test/SelectManyTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include "CommonTests.h" 6 | 7 | #include "boolinq.h" 8 | 9 | using namespace boolinq; 10 | 11 | TEST(SelectMany, AxA) 12 | { 13 | int src[] = {1,2,3}; 14 | int ans[] = {1,2,2,3,3,3}; 15 | 16 | auto rng = from(src); 17 | auto dst = rng.selectMany([](int a){return repeat(a, a);}); 18 | 19 | CheckRangeEqArray(dst, ans); 20 | } 21 | 22 | TEST(SelectMany, OneTwoThree) 23 | { 24 | int src[] = {1,2,3}; 25 | int ans[] = {1,2,3,2,4,6,3,6,9}; 26 | 27 | auto rng = from(src); 28 | auto dst = rng.selectMany([&src](int a){ 29 | return from(src).select([a](int v){return a*v;}); 30 | }); 31 | 32 | CheckRangeEqArray(dst, ans); 33 | } -------------------------------------------------------------------------------- /test/SelectTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include "CommonTests.h" 6 | 7 | #include "boolinq.h" 8 | 9 | using namespace boolinq; 10 | 11 | TEST(Select, Mul2) 12 | { 13 | int src[] = {1,2,3,4}; 14 | int ans[] = {2,4,6,8}; 15 | 16 | auto rng = from(src); 17 | auto dst = rng.select([](int a){return a * 2;}); 18 | 19 | CheckRangeEqArray(dst, ans); 20 | } 21 | 22 | TEST(Select, MakeChar) 23 | { 24 | int src[] = {1,2,3,4}; 25 | char ans[] = {'1','2','3','4'}; 26 | 27 | auto rng = from(src); 28 | auto dst = rng.select([](int a){return static_cast('0' + a);}); 29 | 30 | CheckRangeEqArray(dst, ans); 31 | } 32 | 33 | TEST(Select, MakeString) 34 | { 35 | int src[] = {1,2,3,4}; 36 | 37 | static std::string ans[] = 38 | { 39 | "hello", 40 | "world", 41 | "apple", 42 | "intel", 43 | }; 44 | 45 | auto rng = from(src); 46 | auto dst = rng.select([](int a){return ans[a-1];}); 47 | 48 | CheckRangeEqArray(dst, ans); 49 | } 50 | -------------------------------------------------------------------------------- /test/SkipTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include "CommonTests.h" 6 | 7 | #include "boolinq.h" 8 | 9 | using namespace boolinq; 10 | 11 | ////////////////////////////////////////////////////////////////////////// 12 | 13 | TEST(Skip, ManyToMany) 14 | { 15 | int src[] = {1,2,3,4,5,6}; 16 | int ans[] = {1,2,3,4,5,6}; 17 | 18 | auto rng = from(src); 19 | auto dst = rng.skip(0); 20 | 21 | CheckRangeEqArray(dst, ans); 22 | } 23 | 24 | TEST(Skip, ManyToLess) 25 | { 26 | int src[] = {1,2,3,4,5,6}; 27 | int ans[] = {4,5,6}; 28 | 29 | auto rng = from(src); 30 | auto dst = rng.skip(3); 31 | 32 | CheckRangeEqArray(dst, ans); 33 | } 34 | 35 | TEST(Skip, ManyToOne) 36 | { 37 | int src[] = {1,2,3,4,5,6}; 38 | int ans[] = {6}; 39 | 40 | auto rng = from(src); 41 | auto dst = rng.skip(5); 42 | 43 | CheckRangeEqArray(dst, ans); 44 | } 45 | 46 | TEST(Skip, ManyToZero) 47 | { 48 | int src[] = {1,2,3,4,5,6}; 49 | 50 | auto rng = from(src); 51 | auto dst = rng.skip(6); 52 | 53 | EXPECT_THROW(dst.next(), LinqEndException); 54 | } 55 | 56 | TEST(Skip, ManyToZeroLess) 57 | { 58 | int src[] = {1,2,3,4,5,6}; 59 | 60 | auto rng = from(src); 61 | auto dst = rng.skip(10); 62 | 63 | EXPECT_THROW(dst.next(), LinqEndException); 64 | } 65 | 66 | ////////////////////////////////////////////////////////////////////////// 67 | 68 | TEST(Skip, OneToOne) 69 | { 70 | int src[] = {5}; 71 | int ans[] = {5}; 72 | 73 | auto rng = from(src); 74 | auto dst = rng.skip(0); 75 | 76 | CheckRangeEqArray(dst, ans); 77 | } 78 | 79 | TEST(Skip, OneToZero) 80 | { 81 | int src[] = {5}; 82 | 83 | auto rng = from(src); 84 | auto dst = rng.skip(1); 85 | 86 | EXPECT_THROW(dst.next(), LinqEndException); 87 | } 88 | 89 | TEST(Skip, OneToZeroLess) 90 | { 91 | int src[] = {5}; 92 | 93 | auto rng = from(src); 94 | auto dst = rng.skip(2); 95 | 96 | EXPECT_THROW(dst.next(), LinqEndException); 97 | } 98 | 99 | TEST(Skip, ZeroToZero) 100 | { 101 | std::vector src; 102 | 103 | auto rng = from(src); 104 | auto dst = rng.skip(0); 105 | 106 | EXPECT_THROW(rng.next(), LinqEndException); 107 | } 108 | 109 | TEST(Skip, ZeroToZeroLess) 110 | { 111 | std::vector src; 112 | 113 | auto rng = from(src); 114 | auto dst = rng.skip(2); 115 | 116 | EXPECT_THROW(rng.next(), LinqEndException); 117 | } 118 | 119 | ////////////////////////////////////////////////////////////////////////// 120 | -------------------------------------------------------------------------------- /test/SkipWhileTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include "CommonTests.h" 6 | 7 | #include "boolinq.h" 8 | 9 | using namespace boolinq; 10 | 11 | ////////////////////////////////////////////////////////////////////////// 12 | 13 | TEST(SkipWhile, ManyToMore) 14 | { 15 | int src[] = {1,2,3,4,5,6}; 16 | int ans[] = {1,2,3,4,5,6}; 17 | 18 | auto rng = from(src); 19 | auto dst = rng.skipWhile([](int it){return it < 0 || it > 10;}); 20 | 21 | CheckRangeEqArray(dst, ans); 22 | } 23 | 24 | TEST(SkipWhileRange_i, ManyToMoreByIndex) 25 | { 26 | int src[] = {1,2,3,4,5,6}; 27 | int ans[] = {1,2,3,4,5,6}; 28 | 29 | auto rng = from(src); 30 | auto dst = rng.skipWhile_i([](int /*it*/, int idx){return idx > 10;}); 31 | 32 | CheckRangeEqArray(dst, ans); 33 | } 34 | 35 | TEST(SkipWhileRange_i, ManyToMoreByItemValue) 36 | { 37 | int src[] = {1,2,3,4,5,6}; 38 | int ans[] = {1,2,3,4,5,6}; 39 | 40 | auto rng = from(src); 41 | auto dst = rng.skipWhile_i([](int it, int /*idx*/){return it < 0 || it > 10;}); 42 | 43 | CheckRangeEqArray(dst, ans); 44 | } 45 | 46 | TEST(SkipWhileRange_i, ManyToMoreByIndexAndItemValue) 47 | { 48 | int src[] = {1,2,3,4,5,6}; 49 | int ans[] = {1,2,3,4,5,6}; 50 | 51 | auto rng = from(src); 52 | auto dst = rng.skipWhile_i([](int it, int idx){return idx*it > 0;}); 53 | 54 | CheckRangeEqArray(dst, ans); 55 | } 56 | 57 | TEST(SkipWhile, ManyToMany) 58 | { 59 | int src[] = {1,2,3,4,5,6}; 60 | int ans[] = {1,2,3,4,5,6}; 61 | 62 | auto rng = from(src); 63 | auto dst = rng.skipWhile([](int it){return it < 0 && it > 6;}); 64 | 65 | CheckRangeEqArray(dst, ans); 66 | } 67 | 68 | TEST(SkipWhileRange_i, ManyToManyByIndex) 69 | { 70 | int src[] = {1,2,3,4,5,6}; 71 | int ans[] = {1,2,3,4,5,6}; 72 | 73 | auto rng = from(src); 74 | auto dst = rng.skipWhile_i([](int /*it*/, int idx){return idx > 5;}); 75 | 76 | CheckRangeEqArray(dst, ans); 77 | } 78 | 79 | TEST(SkipWhileRange_i, ManyToManyByItemValue) 80 | { 81 | int src[] = {1,2,3,4,5,6}; 82 | int ans[] = {1,2,3,4,5,6}; 83 | 84 | auto rng = from(src); 85 | auto dst = rng.skipWhile_i([](int it, int /*idx*/){return it < 1 || it > 6;}); 86 | 87 | CheckRangeEqArray(dst, ans); 88 | } 89 | 90 | TEST(SkipWhileRange_i, ManyToManyByIndexAndItemValue) 91 | { 92 | int src[] = {1,2,3,4,5,6}; 93 | int ans[] = {1,2,3,4,5,6}; 94 | 95 | auto rng = from(src); 96 | auto dst = rng.skipWhile_i([](int it, int idx){return idx > 5 || it < 0;}); 97 | 98 | CheckRangeEqArray(dst, ans); 99 | } 100 | 101 | 102 | TEST(SkipWhile, ManyToLess) 103 | { 104 | int src[] = {1,2,3,4,5,6}; 105 | int ans[] = {3,4,5,6}; 106 | 107 | auto rng = from(src); 108 | auto dst = rng.skipWhile([](int it){return it < 3 || it > 4;}); 109 | 110 | CheckRangeEqArray(dst, ans); 111 | } 112 | 113 | TEST(SkipWhileRange_i, ManyToLessByIndex) 114 | { 115 | int src[] = {1,2,3,4,5,6}; 116 | int ans[] = {4,5,6}; 117 | 118 | auto rng = from(src); 119 | auto dst = rng.skipWhile_i([](int /*it*/, int idx){return idx < 3 || idx > 3;}); 120 | 121 | CheckRangeEqArray(dst, ans); 122 | } 123 | 124 | TEST(SkipWhileRange_i, ManyToLessByItemValue) 125 | { 126 | int src[] = {1,2,3,4,5,6}; 127 | int ans[] = {3,4,5,6}; 128 | 129 | auto rng = from(src); 130 | auto dst = rng.skipWhile_i([](int it, int /*idx*/){return it < 3 || it > 4;}); 131 | 132 | CheckRangeEqArray(dst, ans); 133 | } 134 | 135 | TEST(SkipWhileRange_i, ManyToLessByIndexAndItemValue) 136 | { 137 | int src[] = {1,2,3,4,5,6}; 138 | int ans[] = {4,5,6}; 139 | 140 | auto rng = from(src); 141 | auto dst = rng.skipWhile_i([](int it, int idx){return idx*it < 7;}); 142 | 143 | CheckRangeEqArray(dst, ans); 144 | } 145 | 146 | TEST(SkipWhile, ManyToOne) 147 | { 148 | int src[] = {1,2,3,4,5,6}; 149 | int ans[] = {6}; 150 | 151 | auto rng = from(src); 152 | auto dst = rng.skipWhile([](int it){return it != 6;}); 153 | 154 | CheckRangeEqArray(dst, ans); 155 | } 156 | 157 | TEST(SkipWhileRange_i, ManyToOneByIndex) 158 | { 159 | int src[] = {1,2,3,4,5,6}; 160 | int ans[] = {6}; 161 | 162 | auto rng = from(src); 163 | auto dst = rng.skipWhile_i([](int /*it*/, int idx){return idx < 5;}); 164 | 165 | CheckRangeEqArray(dst, ans); 166 | } 167 | 168 | TEST(SkipWhileRange_i, ManyToOneByItemValue) 169 | { 170 | int src[] = {1,2,3,4,5,6}; 171 | int ans[] = {6}; 172 | 173 | auto rng = from(src); 174 | auto dst = rng.skipWhile_i([](int it, int /*idx*/){return it < 6;}); 175 | 176 | CheckRangeEqArray(dst, ans); 177 | } 178 | 179 | TEST(SkipWhileRange_i, ManyToOneByIndexAndItemValue) 180 | { 181 | int src[] = {1,2,3,4,5,6}; 182 | int ans[] = {6}; 183 | 184 | auto rng = from(src); 185 | auto dst = rng.skipWhile_i([](int it, int idx){return idx*it < 30;}); 186 | 187 | CheckRangeEqArray(dst, ans); 188 | } 189 | 190 | TEST(SkipWhile, ManyToZero) 191 | { 192 | int src[] = {1,2,3,4,5,6}; 193 | 194 | auto rng = from(src); 195 | auto dst = rng.skipWhile([](int it){return it > 0;}); 196 | 197 | EXPECT_THROW(dst.next(), LinqEndException); 198 | } 199 | 200 | TEST(SkipWhileRange_i, ManyToZeroeByIndex) 201 | { 202 | int src[] = {1,2,3,4,5,6}; 203 | 204 | auto rng = from(src); 205 | auto dst = rng.skipWhile_i([](int /*it*/, int idx){return idx < 6;}); 206 | 207 | EXPECT_THROW(dst.next(), LinqEndException); 208 | } 209 | 210 | TEST(SkipWhileRange_i, ManyToZeroByItemValue) 211 | { 212 | int src[] = {1,2,3,4,5,6}; 213 | 214 | auto rng = from(src); 215 | auto dst = rng.skipWhile_i([](int it, int /*idx*/){return it > 0;}); 216 | 217 | EXPECT_THROW(dst.next(), LinqEndException); 218 | } 219 | 220 | TEST(SkipWhileRange_i, ManyToZeroIndexAndItemValue) 221 | { 222 | int src[] = {1,2,3,4,5,6}; 223 | 224 | auto rng = from(src); 225 | auto dst = rng.skipWhile_i([](int it, int idx){return idx != it;}); 226 | 227 | EXPECT_THROW(dst.next(), LinqEndException); 228 | } 229 | 230 | ////////////////////////////////////////////////////////////////////////// 231 | 232 | TEST(SkipWhile, OneToOne) 233 | { 234 | int src[] = {5}; 235 | int ans[] = {5}; 236 | 237 | auto rng = from(src); 238 | auto dst = rng.skipWhile([](int it){return it != 5;}); 239 | 240 | CheckRangeEqArray(dst, ans); 241 | } 242 | 243 | TEST(SkipWhileRange_i, OneToOneByIndex) 244 | { 245 | int src[] = {6}; 246 | int ans[] = {6}; 247 | 248 | auto rng = from(src); 249 | auto dst = rng.skipWhile_i([](int /*it*/, int idx){return idx > 0;}); 250 | 251 | CheckRangeEqArray(dst, ans); 252 | } 253 | 254 | TEST(SkipWhileRange_i, OneToOneByItemValue) 255 | { 256 | int src[] = {6}; 257 | int ans[] = {6}; 258 | 259 | auto rng = from(src); 260 | auto dst = rng.skipWhile_i([](int it, int /*idx*/){return it != 6;}); 261 | 262 | CheckRangeEqArray(dst, ans); 263 | } 264 | 265 | TEST(SkipWhileRange_i, OneToOneByIndexAndItemValue) 266 | { 267 | int src[] = {6}; 268 | int ans[] = {6}; 269 | 270 | auto rng = from(src); 271 | auto dst = rng.skipWhile_i([](int it, int idx){return idx != 0 || it != 6;}); 272 | 273 | CheckRangeEqArray(dst, ans); 274 | } 275 | 276 | TEST(SkipWhile, OneToZero) 277 | { 278 | int src[] = {5}; 279 | 280 | auto rng = from(src); 281 | auto dst = rng.skipWhile([](int it){return it == 5;}); 282 | 283 | EXPECT_THROW(dst.next(), LinqEndException); 284 | } 285 | 286 | TEST(SkipWhileRange_i, OneToZeroByIndex) 287 | { 288 | int src[] = {6}; 289 | 290 | auto rng = from(src); 291 | auto dst = rng.skipWhile_i([](int /*it*/, int idx){return idx < 6;}); 292 | 293 | EXPECT_THROW(dst.next(), LinqEndException); 294 | } 295 | 296 | TEST(SkipWhileRange_i, OneToZeroByItemValue) 297 | { 298 | int src[] = {6}; 299 | 300 | auto rng = from(src); 301 | auto dst = rng.skipWhile_i([](int it, int /*idx*/){return it > 0;}); 302 | 303 | EXPECT_THROW(dst.next(), LinqEndException); 304 | } 305 | 306 | TEST(SkipWhileRange_i, OneToZeroIndexAndItemValue) 307 | { 308 | int src[] = {6}; 309 | 310 | auto rng = from(src); 311 | auto dst = rng.skipWhile_i([](int it, int idx){return idx != it;}); 312 | 313 | EXPECT_THROW(dst.next(), LinqEndException); 314 | } 315 | 316 | TEST(SkipWhile, ZeroToZero) 317 | { 318 | std::vector src; 319 | 320 | auto rng = from(src); 321 | auto dst = rng.skipWhile([](int){return false;}); 322 | 323 | EXPECT_THROW(rng.next(), LinqEndException); 324 | } 325 | 326 | TEST(SkipWhileRange_i, ZeroToZero) 327 | { 328 | std::vector src; 329 | 330 | auto rng = from(src); 331 | auto dst = rng.skipWhile_i([](int /*it*/, int /*idx*/){return true;}); 332 | 333 | EXPECT_THROW(rng.next(), LinqEndException); 334 | } 335 | 336 | ////////////////////////////////////////////////////////////////////////// 337 | -------------------------------------------------------------------------------- /test/SumTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include "boolinq.h" 7 | 8 | using namespace boolinq; 9 | 10 | TEST(Sum, ThreeInts) 11 | { 12 | std::vector src; 13 | src.push_back(1); 14 | src.push_back(2); 15 | src.push_back(3); 16 | 17 | auto rng = from(src).sum(); 18 | 19 | EXPECT_EQ(6, rng); 20 | } 21 | 22 | TEST(Sum, FiveInts) 23 | { 24 | std::vector src; 25 | src.push_back(1); 26 | src.push_back(2); 27 | src.push_back(3); 28 | src.push_back(4); 29 | src.push_back(5); 30 | 31 | auto rng = from(src); 32 | auto dst0 = rng.where([](int a){return a%2 == 0;}).sum(); 33 | auto dst1 = rng.where([](int a){return a%2 == 1;}).sum(); 34 | 35 | EXPECT_EQ(6, dst0); 36 | EXPECT_EQ(9, dst1); 37 | } 38 | 39 | TEST(Sum, TransformSum) 40 | { 41 | std::vector src; 42 | src.push_back(1); 43 | src.push_back(2); 44 | src.push_back(3); 45 | src.push_back(4); 46 | src.push_back(5); 47 | 48 | auto rng1 = from(src).sum([](int a){return a/2;}); 49 | auto rng2 = from(src).sum([](int a){return a%2;}); 50 | 51 | EXPECT_EQ(6, rng1); 52 | EXPECT_EQ(3, rng2); 53 | } 54 | 55 | TEST(Sum, FiveStringsLen) 56 | { 57 | std::vector src; 58 | src.push_back("hello"); 59 | src.push_back("apple"); 60 | src.push_back("nokia"); 61 | src.push_back("oracle"); 62 | src.push_back("ponny"); 63 | 64 | auto rng = from(src).sum([](const std::string & str){return str.size();}); 65 | 66 | EXPECT_EQ(26U, rng); 67 | } 68 | 69 | TEST(Sum, FiveStringsData) 70 | { 71 | std::vector src; 72 | src.push_back("hello"); 73 | src.push_back("apple"); 74 | src.push_back("nokia"); 75 | src.push_back("oracle"); 76 | src.push_back("ponny"); 77 | 78 | auto rng = from(src).sum(); 79 | 80 | std::string ans = "helloapplenokiaoracleponny"; 81 | 82 | EXPECT_EQ(ans, rng); 83 | } 84 | 85 | TEST(Sum, TransfromStringSum) 86 | { 87 | std::vector src; 88 | src.push_back("hello"); 89 | src.push_back("apple"); 90 | src.push_back("nokia"); 91 | src.push_back("oracle"); 92 | src.push_back("ponny"); 93 | 94 | auto sum = from(src).sum([](std::string s) { return s.size(); }); 95 | 96 | EXPECT_EQ(26, sum); 97 | } 98 | -------------------------------------------------------------------------------- /test/TakeTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include "CommonTests.h" 6 | 7 | #include "boolinq.h" 8 | 9 | using namespace boolinq; 10 | 11 | ////////////////////////////////////////////////////////////////////////// 12 | 13 | TEST(Take, ManyToMore) 14 | { 15 | int src[] = {1,2,3,4,5,6}; 16 | int ans[] = {1,2,3,4,5,6}; 17 | 18 | auto rng = from(src); 19 | auto dst = rng.take(10); 20 | 21 | CheckRangeEqArray(dst, ans); 22 | } 23 | 24 | TEST(Take, ManyToMany) 25 | { 26 | int src[] = {1,2,3,4,5,6}; 27 | int ans[] = {1,2,3,4,5,6}; 28 | 29 | auto rng = from(src); 30 | auto dst = rng.take(6); 31 | 32 | CheckRangeEqArray(dst, ans); 33 | } 34 | 35 | TEST(Take, ManyToLess) 36 | { 37 | int src[] = {1,2,3,4,5,6}; 38 | int ans[] = {1,2,3}; 39 | 40 | auto rng = from(src); 41 | auto dst = rng.take(3); 42 | 43 | CheckRangeEqArray(dst, ans); 44 | } 45 | 46 | TEST(Take, ManyToOne) 47 | { 48 | int src[] = {1,2,3,4,5,6}; 49 | int ans[] = {1}; 50 | 51 | auto rng = from(src); 52 | auto dst = rng.take(1); 53 | 54 | CheckRangeEqArray(dst, ans); 55 | } 56 | 57 | TEST(Take, ManyToZero) 58 | { 59 | int src[] = {1,2,3,4,5,6}; 60 | 61 | auto rng = from(src); 62 | auto dst = rng.take(0); 63 | 64 | EXPECT_THROW(dst.next(), LinqEndException); 65 | } 66 | 67 | ////////////////////////////////////////////////////////////////////////// 68 | 69 | TEST(Take, OneToMore) 70 | { 71 | int src[] = {5}; 72 | int ans[] = {5}; 73 | 74 | auto rng = from(src); 75 | auto dst = rng.take(5); 76 | 77 | CheckRangeEqArray(dst, ans); 78 | } 79 | 80 | TEST(Take, OneToOne) 81 | { 82 | int src[] = {5}; 83 | int ans[] = {5}; 84 | 85 | auto rng = from(src); 86 | auto dst = rng.take(1); 87 | 88 | CheckRangeEqArray(dst, ans); 89 | } 90 | 91 | TEST(Take, OneToZero) 92 | { 93 | int src[] = {5}; 94 | 95 | auto rng = from(src); 96 | auto dst = rng.take(0); 97 | 98 | EXPECT_THROW(dst.next(), LinqEndException); 99 | } 100 | 101 | TEST(Take, ZeroToZero) 102 | { 103 | std::vector src; 104 | 105 | auto rng = from(src); 106 | auto dst = rng.take(0); 107 | 108 | EXPECT_THROW(rng.next(), LinqEndException); 109 | } 110 | 111 | ////////////////////////////////////////////////////////////////////////// 112 | -------------------------------------------------------------------------------- /test/TakeWhileTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include "CommonTests.h" 6 | 7 | #include "boolinq.h" 8 | 9 | using namespace boolinq; 10 | 11 | ////////////////////////////////////////////////////////////////////////// 12 | 13 | TEST(TakeWhile, ManyToMore) 14 | { 15 | int src[] = {1,2,3,4,5,6}; 16 | int ans[] = {1,2,3,4,5,6}; 17 | 18 | auto rng = from(src); 19 | auto dst = rng.takeWhile([](int it){return it >= 0 && it <= 10;}); 20 | 21 | CheckRangeEqArray(dst, ans); 22 | } 23 | 24 | TEST(TakeWhileRange_i, ManyToMoreByIndex) 25 | { 26 | int src[] = {1,3,5,7,9,11}; 27 | int ans[] = {1,3,5,7,9,11}; 28 | 29 | auto rng = from(src); 30 | auto dst = rng.takeWhile_i([](int /*it*/, int idx){return idx >= 0;}); 31 | 32 | CheckRangeEqArray(dst, ans); 33 | } 34 | 35 | TEST(TakeWhileRange_i, ManyToMoreByItemValue) 36 | { 37 | int src[] = {1,3,5,7,9,11}; 38 | int ans[] = {1,3,5,7,9,11}; 39 | 40 | auto rng = from(src); 41 | auto dst = rng.takeWhile_i([](int it, int /*idx*/){return it%2 != 0;}); 42 | 43 | CheckRangeEqArray(dst, ans); 44 | } 45 | 46 | TEST(TakeWhileRange_i, ManyToMoreByIndexAndItemValue) 47 | { 48 | int src[] = {1,3,5,7,9,11}; 49 | int ans[] = {1,3,5,7,9,11}; 50 | 51 | auto rng = from(src); 52 | auto dst = rng.takeWhile_i([](int it, int idx){return idx < 3 || it > 5;}); 53 | 54 | CheckRangeEqArray(dst, ans); 55 | } 56 | 57 | TEST(TakeWhile, ManyToMany) 58 | { 59 | int src[] = {1,2,3,4,5,6}; 60 | int ans[] = {1,2,3,4,5,6}; 61 | 62 | auto rng = from(src); 63 | auto dst = rng.takeWhile([](int it){return it >= 1 && it <= 6;}); 64 | 65 | CheckRangeEqArray(dst, ans); 66 | } 67 | 68 | TEST(TakeWhileRange_i, ManyToManyByIndex) 69 | { 70 | int src[] = {1,3,5,7,9,11}; 71 | int ans[] = {1,3,5,7,9,11}; 72 | 73 | auto rng = from(src); 74 | auto dst = rng.takeWhile_i([](int /*it*/, int idx){return idx >= 0 && idx < 6;}); 75 | 76 | CheckRangeEqArray(dst, ans); 77 | } 78 | 79 | TEST(TakeWhileRange_i, ManyToManyByItemValue) 80 | { 81 | int src[] = {1,3,5,7,9,11}; 82 | int ans[] = {1,3,5,7,9,11}; 83 | 84 | auto rng = from(src); 85 | auto dst = rng.takeWhile_i([](int it, int /*idx*/){return it > 0 && it < 12;}); 86 | 87 | CheckRangeEqArray(dst, ans); 88 | } 89 | 90 | TEST(TakeWhileRange_i, ManyToManyByIndexAndItemValue) 91 | { 92 | int src[] = {1,3,5,7,9,11}; 93 | int ans[] = {1,3,5,7,9,11}; 94 | 95 | auto rng = from(src); 96 | auto dst = rng.takeWhile_i([](int it, int idx){return idx < 3 || (it > 5 && it < 12);}); 97 | 98 | CheckRangeEqArray(dst, ans); 99 | } 100 | 101 | TEST(TakeWhile, ManyToLess) 102 | { 103 | int src[] = {1,2,3,4,5,6}; 104 | int ans[] = {1,2,3}; 105 | 106 | auto rng = from(src); 107 | auto dst = rng.takeWhile([](int it){return it != 4;}); 108 | 109 | CheckRangeEqArray(dst, ans); 110 | } 111 | 112 | TEST(TakeWhileRange_i, ManyToLessByIndex) 113 | { 114 | int src[] = {1,2,3,4,5,6,7,8,9,10,11}; 115 | int ans[] = {1,2,3,4}; 116 | 117 | auto rng = from(src); 118 | auto dst = rng.takeWhile_i([](int /*it*/, int idx){return idx < 4;}); 119 | 120 | CheckRangeEqArray(dst, ans); 121 | } 122 | 123 | TEST(TakeWhileRange_i, ManyToLessByItemValue) 124 | { 125 | int src[] = {1,2,3,4,5,6,7,8,9,10,11}; 126 | int ans[] = {1,2,3,4}; 127 | 128 | auto rng = from(src); 129 | auto dst = rng.takeWhile_i([](int it, int /*idx*/){return it <5;}); 130 | 131 | CheckRangeEqArray(dst, ans); 132 | } 133 | 134 | TEST(TakeWhileRange_i, ManyToLessByIndexAndItemValue) 135 | { 136 | int src[] = {1,2,3,4,5,6,7,8,9,10,11}; 137 | int ans[] = {1,2,3,4}; 138 | 139 | auto rng = from(src); 140 | auto dst = rng.takeWhile_i([](int it, int idx){return idx < 4 && it > 0;}); 141 | 142 | CheckRangeEqArray(dst, ans); 143 | } 144 | 145 | TEST(TakeWhile, ManyToOne) 146 | { 147 | int src[] = {1,2,3,4,5,6}; 148 | int ans[] = {1}; 149 | 150 | auto rng = from(src); 151 | auto dst = rng.takeWhile([](int it){return it%2 != 0;}); 152 | 153 | CheckRangeEqArray(dst, ans); 154 | } 155 | 156 | TEST(TakeWhileRange_i, ManyToOneByIndex) 157 | { 158 | int src[] = {1,2,3,4,5,6,7,8,9,10,11}; 159 | int ans[] = {1}; 160 | 161 | auto rng = from(src); 162 | auto dst = rng.takeWhile_i([](int /*it*/, int idx){return idx == 0;}); 163 | 164 | CheckRangeEqArray(dst, ans); 165 | } 166 | 167 | TEST(TakeWhileRange_i, ManyToOneByItemValue) 168 | { 169 | int src[] = {1,2,3,4,5,6,7,8,9,10,11}; 170 | int ans[] = {1}; 171 | 172 | auto rng = from(src); 173 | auto dst = rng.takeWhile_i([](int it, int /*idx*/){return it == 1;}); 174 | 175 | CheckRangeEqArray(dst, ans); 176 | } 177 | 178 | TEST(TakeWhileRange_i, ManyToOneByIndexAndItemValue) 179 | { 180 | int src[] = {1,2,3,4,5,6,7,8,9,10,11}; 181 | int ans[] = {1}; 182 | 183 | auto rng = from(src); 184 | auto dst = rng.takeWhile_i([](int it, int idx){return idx < 5 && it < 2;}); 185 | 186 | CheckRangeEqArray(dst, ans); 187 | } 188 | 189 | TEST(TakeWhile, ManyToZero) 190 | { 191 | int src[] = {1,2,3,4,5,6}; 192 | 193 | auto rng = from(src); 194 | auto dst = rng.takeWhile([](int it){return it < 0;}); 195 | 196 | EXPECT_THROW(dst.next(), LinqEndException); 197 | } 198 | 199 | TEST(TakeWhileRange_i, ManyToZeroByIndex) 200 | { 201 | int src[] = {1,2,3,4,5,6,7,8,9,10,11}; 202 | 203 | auto rng = from(src); 204 | auto dst = rng.takeWhile_i([](int /*it*/, int idx){return idx > 0;}); 205 | 206 | EXPECT_THROW(dst.next(), LinqEndException); 207 | } 208 | 209 | TEST(TakeWhileRange_i, ManyToZeroByItemValue) 210 | { 211 | int src[] = {1,2,3,4,5,6,7,8,9,10,11}; 212 | 213 | auto rng = from(src); 214 | auto dst = rng.takeWhile_i([](int it, int /*idx*/){return it > 2;}); 215 | 216 | EXPECT_THROW(dst.next(), LinqEndException); 217 | } 218 | 219 | TEST(TakeWhileRange_i, ManyToZeroByIdexAndItemValue) 220 | { 221 | int src[] = {1,2,3,4,5,6,7,8,9,10,11}; 222 | 223 | auto rng = from(src); 224 | auto dst = rng.takeWhile_i([](int it, int idx){return it < 0 || idx > 0;}); 225 | 226 | EXPECT_THROW(dst.next(), LinqEndException); 227 | } 228 | 229 | ////////////////////////////////////////////////////////////////////////// 230 | 231 | TEST(TakeWhile, OneToOne) 232 | { 233 | int src[] = {5}; 234 | int ans[] = {5}; 235 | 236 | auto rng = from(src); 237 | auto dst = rng.takeWhile([](int it){return it > 0;}); 238 | 239 | CheckRangeEqArray(dst, ans); 240 | } 241 | 242 | TEST(TakeWhileRange_i, OneToOneByIndex) 243 | { 244 | int src[] = {5}; 245 | int ans[] = {5}; 246 | 247 | auto rng = from(src); 248 | auto dst = rng.takeWhile_i([](int /*it*/, int idx){return idx < 1;}); 249 | 250 | CheckRangeEqArray(dst, ans); 251 | } 252 | 253 | TEST(TakeWhileRange_i, OneToOneByItemValue) 254 | { 255 | int src[] = {5}; 256 | int ans[] = {5}; 257 | 258 | auto rng = from(src); 259 | auto dst = rng.takeWhile_i([](int it, int /*idx*/){return it > 2;}); 260 | 261 | CheckRangeEqArray(dst, ans); 262 | } 263 | 264 | TEST(TakeWhileRange_i, OneToOneByIndexAndItemValue) 265 | { 266 | int src[] = {5}; 267 | int ans[] = {5}; 268 | 269 | auto rng = from(src); 270 | auto dst = rng.takeWhile_i([](int it, int idx){return idx == 0 && it > 2;}); 271 | 272 | CheckRangeEqArray(dst, ans); 273 | } 274 | 275 | TEST(TakeWhile, OneToZero) 276 | { 277 | int src[] = {5}; 278 | 279 | auto rng = from(src); 280 | auto dst = rng.takeWhile([](int){return false;}); 281 | 282 | EXPECT_THROW(dst.next(), LinqEndException); 283 | } 284 | 285 | TEST(TakeWhileRange_i, OneToZeroByIndex) 286 | { 287 | int src[] = {5}; 288 | 289 | auto rng = from(src); 290 | auto dst = rng.takeWhile_i([](int /*it*/, int idx){return idx > 0;}); 291 | 292 | EXPECT_THROW(dst.next(), LinqEndException); 293 | } 294 | 295 | TEST(TakeWhileRange_i, OneToZeroByItemValue) 296 | { 297 | int src[] = {5}; 298 | 299 | auto rng = from(src); 300 | auto dst = rng.takeWhile_i([](int it, int /*idx*/){return it < 5;}); 301 | 302 | EXPECT_THROW(dst.next(), LinqEndException); 303 | } 304 | 305 | TEST(TakeWhileRange_i, OneToZeroByIndexAndItemValue) 306 | { 307 | int src[] = {5}; 308 | 309 | auto rng = from(src); 310 | auto dst = rng.takeWhile_i([](int it, int idx){return idx == 0 && it > 5;}); 311 | 312 | EXPECT_THROW(dst.next(), LinqEndException); 313 | } 314 | 315 | TEST(TakeWhile, ZeroToZero) 316 | { 317 | std::vector src; 318 | 319 | auto rng = from(src); 320 | auto dst = rng.takeWhile([](int){return false;}); 321 | 322 | EXPECT_THROW(rng.next(), LinqEndException); 323 | } 324 | 325 | TEST(TakeWhileRange_i, ZeroToZero) 326 | { 327 | int src[] = {5}; 328 | 329 | auto rng = from(src); 330 | auto dst = rng.takeWhile_i([](int /*it*/, int /*idx*/){return false;}); 331 | 332 | EXPECT_THROW(dst.next(), LinqEndException); 333 | } 334 | 335 | ////////////////////////////////////////////////////////////////////////// 336 | -------------------------------------------------------------------------------- /test/ToStdDequeTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "boolinq.h" 6 | 7 | using namespace boolinq; 8 | 9 | TEST(ToStdDeque, Deque2Deque) 10 | { 11 | std::deque src; 12 | src.push_back(100); 13 | src.push_back(200); 14 | src.push_back(300); 15 | 16 | auto rng = from(src); 17 | auto dst = rng.toStdDeque(); 18 | 19 | EXPECT_EQ(dst,src); 20 | } 21 | -------------------------------------------------------------------------------- /test/ToStdListTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "boolinq.h" 6 | 7 | using namespace boolinq; 8 | 9 | TEST(ToStdList, List2List) 10 | { 11 | std::list src; 12 | src.push_back(100); 13 | src.push_back(200); 14 | src.push_back(300); 15 | 16 | auto rng = from(src); 17 | auto dst = rng.toStdList(); 18 | 19 | EXPECT_EQ(dst,src); 20 | } 21 | -------------------------------------------------------------------------------- /test/ToStdSetTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "boolinq.h" 6 | 7 | using namespace boolinq; 8 | 9 | TEST(ToStdSet, Vector2Set) 10 | { 11 | std::vector src; 12 | src.push_back(1); 13 | src.push_back(1); 14 | src.push_back(2); 15 | src.push_back(3); 16 | src.push_back(2); 17 | 18 | auto rng = from(src); 19 | auto dst = rng.toStdSet(); 20 | 21 | EXPECT_EQ(3U, dst.size()); 22 | EXPECT_NE(dst.end(), dst.find(1)); 23 | EXPECT_NE(dst.end(), dst.find(2)); 24 | EXPECT_NE(dst.end(), dst.find(3)); 25 | } 26 | -------------------------------------------------------------------------------- /test/ToStdVectorTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "boolinq.h" 6 | 7 | using namespace boolinq; 8 | 9 | TEST(ToStdVector, Vector2Vector) 10 | { 11 | std::vector src; 12 | src.push_back(100); 13 | src.push_back(200); 14 | src.push_back(300); 15 | 16 | auto rng = from(src); 17 | auto dst = rng.toStdVector(); 18 | 19 | EXPECT_EQ(dst,src); 20 | } 21 | -------------------------------------------------------------------------------- /test/UnbitsTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include "CommonTests.h" 6 | 7 | #include "boolinq.h" 8 | 9 | using namespace boolinq; 10 | 11 | ////////////////////////////////////////////////////////////////////////// 12 | 13 | TEST(Unbits, OneByteDefault) 14 | { 15 | int src[] = {1,0,1,0,1,0,1,0}; 16 | int ans[] = {0xAA}; 17 | 18 | auto rng = from(src); 19 | auto dst = rng.unbits(); 20 | 21 | CheckRangeEqArray(dst, ans); 22 | } 23 | 24 | TEST(Unbits, OneByteHL) 25 | { 26 | int src[] = {1,0,1,0,1,0,1,0}; 27 | int ans[] = {0xAA}; 28 | 29 | auto rng = from(src); 30 | auto dst = rng.unbits(BitsHighToLow); 31 | 32 | CheckRangeEqArray(dst, ans); 33 | } 34 | 35 | TEST(Unbits, OneByteLH) 36 | { 37 | int src[] = {0,1,0,1,0,1,0,1}; 38 | int ans[] = {0xAA}; 39 | 40 | auto rng = from(src); 41 | auto dst = rng.unbits(BitsLowToHigh); 42 | 43 | CheckRangeEqArray(dst, ans); 44 | } 45 | -------------------------------------------------------------------------------- /test/UnbytesTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include "CommonTests.h" 6 | 7 | #include "boolinq.h" 8 | 9 | using namespace boolinq; 10 | 11 | ////////////////////////////////////////////////////////////////////////// 12 | 13 | TEST(Unbytes, OneIntDefault) 14 | { 15 | unsigned char src[] = {0xAA,0xBB,0xCC,0xDD}; 16 | unsigned ans[] = {0xDDCCBBAA}; 17 | 18 | auto rng = from(src); 19 | auto dst = rng.unbytes(); 20 | 21 | CheckRangeEqArray(dst, ans); 22 | } 23 | 24 | TEST(Unbytes, OneIntFL) 25 | { 26 | unsigned char src[] = {0xAA,0xBB,0xCC,0xDD}; 27 | unsigned ans[] = {0xDDCCBBAA}; 28 | 29 | auto rng = from(src); 30 | auto dst = rng.unbytes(BytesFirstToLast); 31 | 32 | CheckRangeEqArray(dst, ans); 33 | } 34 | 35 | TEST(Unbytes, OneIntLF) 36 | { 37 | unsigned char src[] = {0xAA,0xBB,0xCC,0xDD}; 38 | unsigned ans[] = {0xAABBCCDD}; 39 | 40 | auto rng = from(src); 41 | auto dst = rng.unbytes(BytesLastToFirst); 42 | 43 | CheckRangeEqArray(dst, ans); 44 | } 45 | 46 | ////////////////////////////////////////////////////////////////////////// 47 | 48 | TEST(Unbytes, TwoIntsDefault) 49 | { 50 | unsigned char src[] = 51 | { 52 | 0x78,0x56,0x34,0x12, 53 | 0xAA,0xBB,0xCC,0xDD, 54 | }; 55 | unsigned ans[] = {0x12345678,0xDDCCBBAA}; 56 | 57 | auto rng = from(src); 58 | auto dst = rng.unbytes(); 59 | 60 | CheckRangeEqArray(dst, ans); 61 | } 62 | 63 | TEST(Unbytes, TwoIntsFL) 64 | { 65 | unsigned char src[] = 66 | { 67 | 0x78,0x56,0x34,0x12, 68 | 0xAA,0xBB,0xCC,0xDD, 69 | }; 70 | unsigned ans[] = {0x12345678,0xDDCCBBAA}; 71 | 72 | auto rng = from(src); 73 | auto dst = rng.unbytes(BytesFirstToLast); 74 | 75 | CheckRangeEqArray(dst, ans); 76 | } 77 | 78 | TEST(Unbytes, TwoIntsLF) 79 | { 80 | unsigned char src[] = 81 | { 82 | 0x78,0x56,0x34,0x12, 83 | 0xAA,0xBB,0xCC,0xDD, 84 | }; 85 | unsigned ans[] = {0x78563412,0xAABBCCDD}; 86 | 87 | auto rng = from(src); 88 | auto dst = rng.unbytes(BytesLastToFirst); 89 | 90 | CheckRangeEqArray(dst, ans); 91 | } 92 | 93 | ////////////////////////////////////////////////////////////////////////// 94 | 95 | TEST(Unbytes, EmptyDefault) 96 | { 97 | std::vector src; 98 | 99 | auto rng = from(src); 100 | auto dst = rng.unbytes(); 101 | 102 | EXPECT_THROW(dst.next(), LinqEndException); 103 | } 104 | -------------------------------------------------------------------------------- /test/WhereTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include "CommonTests.h" 6 | 7 | #include "boolinq.h" 8 | 9 | using namespace boolinq; 10 | 11 | ////////////////////////////////////////////////////////////////////////// 12 | 13 | TEST(Where, IntOdd) 14 | { 15 | int src[] = {1,2,3,4,5,6}; 16 | int ans[] = {1, 3, 5}; 17 | 18 | auto rng = from(src); 19 | auto dst = rng.where([](int a){return a%2 == 1;}); 20 | 21 | CheckRangeEqArray(dst, ans); 22 | } 23 | 24 | ////////////////////////////////////////////////////////////////////////// 25 | 26 | TEST(Where, FirstLetterFront) 27 | { 28 | std::string src[] = 29 | { 30 | "apple", 31 | "blackberry", 32 | "adobe", 33 | "microsoft", 34 | "nokia", 35 | }; 36 | 37 | std::string ans[] = 38 | { 39 | "apple", 40 | "adobe", 41 | }; 42 | 43 | auto rng = from(src); 44 | auto dst = rng.where([](std::string a){return a[0] == 'a';}); 45 | 46 | CheckRangeEqArray(dst, ans); 47 | } 48 | 49 | ////////////////////////////////////////////////////////////////////////// 50 | 51 | TEST(Where, NameAgeLess) 52 | { 53 | struct NameAge 54 | { 55 | std::string name; 56 | int age; 57 | }; 58 | 59 | NameAge src[] = 60 | { 61 | {"man1",20}, 62 | {"man2",15}, 63 | {"man3",30}, 64 | {"man4",14}, 65 | {"man5",18}, 66 | }; 67 | 68 | NameAge ans[] = 69 | { 70 | {"man2",20}, 71 | {"man4",15}, 72 | }; 73 | 74 | auto rng = from(src); 75 | auto dst = rng.where([](const NameAge & a){return a.age < 18;}); 76 | 77 | CheckRangeEqArray(dst, ans, [](const NameAge & a){return a.name;}); 78 | } 79 | 80 | //////////////////////////////////////////////////////////////////////// 81 | 82 | TEST(Where, MayToOne) 83 | { 84 | int src[] = {0,1,2}; 85 | int ans[] = {1}; 86 | 87 | auto rng = from(src); 88 | auto dst = rng.where([](int a){return a == 1;}); 89 | 90 | CheckRangeEqArray(dst, ans); 91 | } 92 | 93 | TEST(Where, OneToOne) 94 | { 95 | int src[] = {5}; 96 | int ans[] = {5}; 97 | 98 | auto rng = from(src); 99 | auto dst = rng.where([](int a){return a>0;}); 100 | 101 | CheckRangeEqArray(dst, ans); 102 | } 103 | 104 | TEST(Where, ManyToZero) 105 | { 106 | int src[] = {0,1,2}; 107 | 108 | auto rng = from(src); 109 | auto dst = rng.where([](int a){return a == 5;}); 110 | 111 | EXPECT_THROW(dst.next(), LinqEndException); 112 | } 113 | 114 | TEST(Where, OneToZero) 115 | { 116 | int src[] = {5}; 117 | 118 | auto rng = from(src); 119 | auto dst = rng.where( [](int a){return a>10;}); 120 | 121 | EXPECT_THROW(dst.next(), LinqEndException); 122 | } 123 | 124 | TEST(Where, ZeroToZero) 125 | { 126 | std::vector src; 127 | 128 | auto rng = from(src); 129 | auto dst = rng.where( [](int a){return a>0;}); 130 | 131 | EXPECT_THROW(rng.next(), LinqEndException); 132 | } 133 | -------------------------------------------------------------------------------- /test/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char * argv[]) 4 | { 5 | ::testing::InitGoogleMock(&argc, argv); 6 | return RUN_ALL_TESTS(); 7 | } 8 | --------------------------------------------------------------------------------