An open API service indexing awesome lists of open source software.

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

Awesome Lists containing this project

README

        

LINQ++ logo

## 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
#include

using 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_list

for(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++
#include

using 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
```