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

https://github.com/jonathanpoelen/jln.mp

C++17 meta programming library for fast compilation speed.
https://github.com/jonathanpoelen/jln.mp

cpp cpp17 metaprogramming mpl template-metaprogramming

Last synced: 19 days ago
JSON representation

C++17 meta programming library for fast compilation speed.

Awesome Lists containing this project

README

          

[![CI](https://github.com/jonathanpoelen/jln.mp/actions/workflows/ci.yml/badge.svg)](https://github.com/jonathanpoelen/jln.mp/actions?query=workflow%3ACI)

# Jln.Mp: A C++17 metaprogramming library

[Jln.mp](https://github.com/jonathanpoelen/jln.mp) is a C++17 metaprogramming library designed for fast compilation speed (strongly inspired by [Kvasir::mpl](https://github.com/kvasir-io/mpl), but generally faster, with more algorithm and a debug mode to have errors with more context).

Licence: MIT

Online documentation: https://jonathanpoelen.github.io/jln.mp/

Online documentation for v1: https://jonathanpoelen.github.io/jln.mp/v1/

Single file version in [standalone branch](https://github.com/jonathanpoelen/jln.mp/tree/standalone).

## Concepts

Functions of jln.mp are used in 2 stages:

- Instantiation, by indicating parameters which describe how it must work.
- Call, by applying sequence to an instantiation.

For example, suppose we want to remove `void` from a sequence. The function to use is `jln::mp::remove`:

```cpp
using remove_void = jln::mp::remove;
```

We can then apply it to our data:

```cpp
using result = jln::mp::call;
// result == jln::mp::list
```

Now suppose that `result` must be a `std::tuple`. Rather than linking with another function, it is possible to combine them in `remove_void` via a continuation (`C` parameter).

```cpp
using remove_void = jln:mp::remove>;

using result = jln::mp::call;
// result == std::tuple
```

The default continuations are `jln::mp::listify` which transforms a sequence into a `jln::mp::list` and `jln::mp::identity` which returns the input value.

Jln.mp also has 2 additional namespaces:

- `smp` a SFINAE compatible version of `mp`.
- `emp` which directly returns a result without going through `jln::mp::call`. According to the function, type sequences are replaced by lists and continuations are not always available.

### Create a function

A function is a type with a `f` template member.

```cpp
struct to_tuple
{
template
using f = std::tuple;
};

jln::mp::call == std::tuple
```

In the mind of the library, functions should at least take a continuation.

```cpp
// equivalent to jln::mp::cfe
template
struct to_tuple
{
template
using f = jln::mp::call>;
};

jln::mp::call, int, double> == std::tuple
```

## Glossary

- Sequence: a value sequence or a type sequence.
- Set: a sequence of unique elements.
- Map: a sequence of lists having at least one element (the key). The keys of the map must be unique.
- Value: a type with a `value` member.
- Typelist: an instance compatible with `template class T`, such as `list<>`.
- Function: a type with a `f` template member. The number and the nature of the parameters depend on the context of use.
- Predicate: a function which takes n argument (usually 1) and returns a boolean.
- Meta-function: a template class `template class M`.
- Lazy meta-function: a meta-function with a `type` member.
- `C`: Continuation function. Represents the function used to chain calls, typically `listify` or `identity`.
- `TC` parameter: True Continuation function. Represents a continuation used when something is found or true.
- `FC` parameter: False Continuation function. Represents a continuation used when something is not found or false.
- `_v` suffix: `C::f` takes values. Usually `C::f` (C++17) or `C::f` (C++20). In the `emp` namespace, with a few exceptions, this corresponds to a variable template (as for the stl).

- `_c` suffix: parameters are number values rather than types. Usually `foo_c = foo>`.

## Example of real life

Implementation of `std::tuple_cat` that works with tuple like.

```cpp
#include "jln/mp/algorithm/make_int_sequence.hpp"
#include "jln/mp/algorithm/transform.hpp"
#include "jln/mp/algorithm/repeat.hpp"
#include "jln/mp/algorithm/repeat_index.hpp"
#include "jln/mp/functional/each.hpp"
#include "jln/mp/functional/continuation.hpp"
#include "jln/mp/list/join.hpp"

#include
#include

namespace mp = jln::mp;
namespace emp = jln::mp::emp;

/*
* tuple_cat() implementation
*/

//@{
template
struct my_tuple_element
{
template
using f = std::tuple_element_t;
};

template
using my_tuple_cat_result_type = mp::call<
// Convert a sequence of mp::list to std::tuple
mp::join>,
// Convert a tuple like to mp::list of tuple element.
// To support tuple-likes, it is necessary to use std::tuple_size and std::tuple_element.
// Otherwise, emp::unpack is sufficient.
emp::make_int_sequence<
std::tuple_size>,
// Convert a sequence of tuple index to a mp::list of tuple element.
mp::transform>>
>...
>;

template
constexpr R my_tuple_cat_impl(
emp::numbers, emp::numbers, Tuple t)
{
// get is looked up by argument-dependent lookup
using std::get;
return R{ get(get(std::move(t)))... };
}

template>
constexpr R my_tuple_cat(Tuples&&... args)
{
// tuple_size_v: 3 2 4
// list< 0, 0, 0, 1, 1, 2, 2, 2, 2 >
using index_by_tuple = mp::repeat_index_v_c>
::f>...>;

// tuple_size_v: 3 2 4
// list< 0, 1, 2, 0, 1, 0, 1, 2, 3 >
using index_by_value = emp::join<
emp::make_int_sequence>>...
>;

return my_tuple_cat_impl(index_by_tuple{}, index_by_value{},
std::tuple(std::forward(args)...));
}

/*
* Tuple like class
*/

//@{
namespace toy
{
// tuple like
struct Vector2D
{
int x, y;
};

template
constexpr int get(Vector2D const& t)
{
return i == 0 ? t.x : t.y;
}
}

template<>
struct std::tuple_size<::toy::Vector2D>
: std::integral_constant
{};

template
struct std::tuple_element
{
using type = int;
};
//@}

/*
* Test
*/

// @{
constexpr std::tuple t0{1, 2, 3};
constexpr std::tuple t1{4, 5};
constexpr std::tuple t2{6};
constexpr std::array a{7, 8, 9, 10};
constexpr toy::Vector2D v {11, 12};

constexpr auto my_tuple = my_tuple_cat(t0, t1, t2, a, v);

using my_tuple_type = std::remove_const_t;
using std_tuple = std::tuple<
int, float, double,
char, unsigned,
long,
short, short, short, short,
int, int>;

static_assert(std::is_same_v);
static_assert(my_tuple == std::tuple{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12});
// @}
```

## FAQ

> Functions are missing in the stacktrace when the compiler displays an error message, how to display them?

Compile with the define `JLN_MP_DEBUG` at `1` to have errors with more context.

> Error: `sorry, unimplemented: mangling record_type` or `sorry, unimplemented: mangling typename_type` with Gcc.

This is a [Gcc bug](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95299) when an algorithm is used in the prototype of a function.

```cpp
template
mp::call foo();

// Must be replaced by

template>
R foo();
```