https://github.com/voltra/linq
A LINQ alike library for C++11
https://github.com/voltra/linq
c-plus-plus c-plus-plus-11 c-plus-plus-library linq
Last synced: 3 months ago
JSON representation
A LINQ alike library for C++11
- Host: GitHub
- URL: https://github.com/voltra/linq
- Owner: Voltra
- License: mit
- Created: 2018-02-11T11:58:38.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2020-07-25T12:58:21.000Z (almost 5 years ago)
- Last Synced: 2025-03-02T01:34:40.713Z (3 months ago)
- Topics: c-plus-plus, c-plus-plus-11, c-plus-plus-library, linq
- Language: C++
- Size: 367 KB
- Stars: 0
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
## Quick introduction
LINQ++ is a (headers only) C++11 library that aims to emulate the behavior of LINQ in other languages such as C#.
Collection manipulation in C++ is often painful, LINQ++ makes it way easier.
## Features
These are the features that are currently supported :
### Types declarations
* `linq::Linqable::value_type` : The type of the elements of this `Linqable`
* `linq::Linqable::reference` : Equivalent to `T&`
* `linq::Linqable::ref` : Alias for the above
* `linq::Linqable::const_reference` : Equivalent to `const T&`
* `linq::Linqable::const_ref` : Equivalent to the above
* `linq::Linqable::pointer` : Equivalent to `T*`
* `linq::Linqable::ptr` : An alias for `linq::Linqable::pointer`
* `linq::Linqable::const_pointr` : Equivalent to `const T*`
* `linq::Linqable::const_ptr` : An alias for `linq::Linqable::const_ptr`
* `linq::Linqable::container` : The type of container used by the `Linqable`
* `linq::Linqable::iterator` : The type of iterators to a `Linqable`
* `linq::Linqable::const_iterator` : The type of iterators (const-aware) to a `Linqable`
* `linq::Linqable::Predicate` : A predicate that takes a `T` as argument
* `linq::Linqable::WhereBuilder` : A function that takes a `linq::Linqable` and returns a `linq::Linqable`
* `linq::Linqable::SelfMapper` : A function that takes a `T` and returns a `T`
### Construction (FROM operations)
- `linq::Linqable linq::Linqable::from(It begin, It end)` : A static method of the class `Linqable` that uses two iterators in order to build the `Linqable` object
- `linq::Linqable linq::from(It begin, It end)` : A utilitary function that calls the above, it is basically syntactic sugar### Selection/Filtering (WHERE operations)
* `linq::Linqable linq::Linqable::where(Predicate p)` : The method usually used to start the selection sequence (chaining WHERE operations), only the elements that match the predicate `p` (`T => bool`) will be kept
* `linq::Linqable linq::Linqable::orWhere(linq::Linqable::Predicate p)` : Adds elements from the previous selection that match the given predicate
* `linq::Linqable linq::Linqable::andWhere(Predicate p)` : An alias to `where` usually used after the first (and supposedly only) `where` in order to add an additionnal filter to the current selection
* `linq::Linqable linq::Linqable::andComplexWhere(WhereBuilder wb)` : Used to make selection sub-operations (for instance, in `WHERE a AND (b OR C)`, `(b OR C)` would usually require a sub-operation). `wb` is a function that is `Linqable => Linqable`### "Special" operations
* `linq::Linqable linq::Linqable::limit(unsigned int n)` : Restricts the current selection to a maximal amount of `n` elements (selects them in their order)
* `linq::Linqable linq::Linqable::unique()` : Removes duplicates from the current selection (packs to set and goes back to `Linqable`)### Ordering (ORDER BY operations)
* `linq::Linqable linq::Linqable::orderDesc()` : Sorts the currently selected elements in descending order using the `operator>`
* `linq::Linqable linq::Linqable::orderAsc()` : Sorts the currently selected elements in ascending order using the `operator<`
* `linq::Linqable linq::Linqable::orderDescBy(Transformer f)` : Sorts the currently selected elements in ascending order using the transformed elements's (via `f`, `T => E`) `operator>`
* `linq::Linqable linq::Linqable::orderAscBy(Transformer f)` : Sorts the currently selected elements in ascending order using the transformed elements's (via `f`, `T => E`) `operator<`### Projection (SELECT operations)
* `linq::Linqable linq::Linqable::select()` : Returns `*this`, only used for semantic coherence purposes
* `linq::Linqable linq::Linqable::select(Mapper mapper)` : Maps the currently selected elements using the given mapper function `mapper` (`T => ReturnType`) and render them available as the current selection
* `linq::Linqable linq::Linqable::selet(Mapper mapper)` : Maps the currently selected elements to elements of the same type and render them available as the current selection
* `ReturnType linq::Linqable::selectReduced(Reducer red, ReturnType acc)` : Reduces the currently selected elements to a single value of the type `ReturnType` based upon the reducer function `red` (`(ReturnType, T) => ReturnType`) and the inital value of the accumulator `acc`### Packing
I would describe the *packing* operation as the operation of getting to a usual C++ Container (or pointer) from a `Linqable` object : `Linqable` serving only as a way to manipulate your base Container easily.
* `T* linq::Linqable::packToPointer()` : Allocates a pointer of `T` elements from a `Linqable`
* `std::vector linq::Linqable::packToVector()` : Creates a `std::vector` from the currently selected elements of the `Linqable` object
* `std::list linq::Linqable::packToList()` : Creates a `std::list` from the currently selected elements of the `Linqable` object
* `std::set linq::Linqable::packToSet()` : Creates a `std::set` from the currently selected elements of the `Linqable` object
* `std::deque linq::Linqable::packToDeque()` : Creates a `std::deque` from the currently selected elements of the `Linqable` object
* `std::forward_list linq::Linqable::packToForwardList()` : Creates a `std::forward_list` from the currently selected elements of the `Linqable` object. Note that this operation has a bit more overhead than the others due to the fact that insertion in `std::forward_list` is done to the front, so we have to reverse the list to keep the original order### Utilitaries
LINQ++ comes with a bit of utilitaries function that makes it easier to use (even though some may only be used for the development of this library, eg. `TransformerGreaterThanComparator`).
The base namespace for those is `linq::utils`.
#### Basics
* `Identity` : A struct that is used as a functor for the identity function (`(T a) => a`)
* `identityOf()` : A function that returns the identity function of the given type `T`#### Helper Functions
Most of those functions are meant to ease the use of WHERE operations by giving support to recurrent operations (With x being the element : `x==n`,`x bool` and let's have `T` be the type of the elements in the `Linqable` object.
##### Comparison
* `PREDICATE is(T ref)` : Returns a predicate that is true only when a given `T x` is equal to `ref` using `operator==`
* `PREDICATE isNot(T ref)` : Returns a predicate that is true only when a given `T x` is not equal to `ref` using `operator!=`
* `PREDICATE isGreaterThan(T ref)` : Returns a predicate that is true only when a given `T x` is greater than `ref` using `operator>`
* `PREDICATE isLessThan(T ref)` : Returns a predicate that is true only when a given `T x` is less than `ref` using `operator<`
* `PREDICATE isGreaterThanOrEqualTo(T ref)` : Returns a predicate that is true only when a given `T x` is greater than or equal to `ref` using `operator>=`
* `PREDICATE isLessThanOrEqualTo(T ref)` : Returns a predicate that is true only when a given `T x` is less than or equal to `ref` using `operator<=`##### Comparison (for maximum compatibility, `operator==` and `operator<` only)
* `PREDICATE e(T ref)` : Alias of `is` (added solely for consistency)
* `PREDICATE ne(T ref)` : Equivalent to `isNot` but using `operator==`
* `PREDICATE lt(T ref)` : Alias of `isLessThan` (added solely for consistency)
* `PREDICATE gt(T ref)` : Equivalent to `isGreaterThan` but using `operator<`
* `PREDICATE le(T ref)` : Equivalent to `isLessThanOrEqualTo` but using `operator<`
* `PREDICATE ge(T ref)` : Equivalent to `isGreaterThanOrEqualTo` but using `operator<`##### Ranges
* `PREDICATE isBetween(T lhs, T rhs)` : Equivalent to $elem \in [lhs ; rhs]$
* `PREDICATE isInRange(T lhs, T rhs)` : Equivalent to $elem \in [lhs ; rhs[ $
* `PREDICATE isWithin(T lhs, T rhs)` : Equivalent to $elem \in \space]lhs;rhs[ $
* `PREDICATE isInExclusiveRange(T lhs, T rhs)` : Equivalent to $elem \in \space]lhs ; rhs] $##### Number specifics
* `bool isOdd(T elem)`
* `bool isEven(T elem)`## General use cases
As we already know, collection manipulation in C++ is not exactly as smooth as it can be in other languages.
LINQ++ tends to simplify collection manipulation operation by offering various ways to operate on a [container](http://www.cplusplus.com/reference/stl/).
The way you would usually process is to pass the `begin` and `end` iterator of your C++ Container as the parameters of `linq::from` (do not forget to specify the type of elements, eg. `linq::from(arr.begin(), arr.end())`) and then chain operations until you are willing to `pack ` them back to a C++ Container.
Let's have an example, shall we ?
```c++
#include "linq/linq.hpp"
#include
#includeusing namespace std;
using namespace linq::utils::helperFunctions;set arr = {0,1,2,3,4,5,6,7,8,9};
forward_list linqed = linq::from(arr.begin(), arr.end())
->where(isEven) //I want even numbers only
->orWhere(is(1)) //But if there are any 1s, keep them
->andWhere([](const int& elem)->bool{ return true; }) //Then keep everything from that
->orderDesc() //Order them in descending order
->select() //Optional
->packToForwardList(); //Pack them into a forward_listfor(int elem : linqed)
cout << elem << " ";
//prints: 8 6 4 2 1 0
```In SQL, that would roughly be equivalent to (if we have a table `arr` that has `elem` as a column) :
```sql
SELECT elem
FROM arr
WHERE ((MOD(elem, 2)=0 OR elem=1) AND TRUE)
ORDER BY elem DESC
```Or in C# :
```c#
from elem in arr
where (elem%2==0 || elem==1) && true
orderby elem descending
select elem
```As of v1.0.2, you can use member functions in order to ease your job at manipulating collections of objects :
```c++
#includeusing namespace std;
using namespace linq::utils::helperFunctions;class RandomPelo{
protected:
string name;
bool lives;public:
Employe(string name, bool lives = true) : name{name}, lives{lives}{}bool isAlive(){ return this->lives; }
string getName(){ return this->name; }
};vector vect = {};
bool isAlive = true;
for(char c='a' ; c <= 'z' ; c+=1) {
vect.push_back( RandomPelo{string{c}, isAlive} );
isAlive = !isAlive;
}string names = linq::from(vect.begin(), vect.end())
->where(&RandomPelo::isAlive) //I only want to keep those who are alive
->select(&RandomPelo::getName) //I want to retrieve their name
->select([](string s){ return s + " "; }) //I want to add a blank space after their name
->selectReduced(reducers::strings::concat, string{}); //I want to concatenate their name
```