Skip to content

Functional basics #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: v1
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions NOTES.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
Apparently VC++ 2017 is not quite ready for

```c++
template <auto v> struct value_t {
using eval = value_t;
template <auto v> struct value_c {
using eval = value_c;
using type = decltype(v);
static constexpr auto value = v;
};
Expand Down
80 changes: 80 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,83 @@
Non-strict template metaprogramming primitives for C++.

See [`synopsis.hpp`](provides/include/lax_v1/synopsis.hpp) for the API.

## <a id="contents"></a> [≡](#contents) [Contents](#contents)

- [Legend](#legend)
- [Glossary](#glossary)
- [Currying](#currying)
- [Meta expression](#meta-expression)
- [Meta function](#meta-function)
- [Meta value](#meta-value)
- [Non-strict evaluation](#non-strict-evaluation)
- [Motivation](#motivation)
- [References](#references)

## <a id="legend"></a> [≡](#contents) [Legend](#legend)

- `_m` [meta expression](#meta-expression) template
- `_c` [meta value](#meta-value) or meta value template
- `_p` primitive (internal type alias or meta expression template or class)
- `_t` type alias (from C++11)
- `_v` value constexpr (from C++17)

## <a id="glossary"></a> [≡](#contents) [Glossary](#glossary)

### <a id="currying"></a> [≡](#contents) [Currying](#currying)

### <a id="meta-expression"></a> [≡](#contents) [Meta expression](#meta-expression)

A lax meta expression is a type that is a subtype of a single
[meta value](#meta-value) and includes no other members aside from those defined
by that meta value.

```c++
using a_meta_expression = add_m<auto_c<1>, auto_c<2>>;
struct also_a_meta_expression : a_meta_expression {};
```

Lax meta expression templates are typically [curried](#curried) and produce
[meta functions](#meta-function) when partially applied.

### <a id="meta-function"></a> [≡](#contents) [Meta function](#meta-function)

A lax meta function is a [meta value](#meta-value) that has a static `arity`
constant and an inner type template `template_m` that takes at least `arity`
types as arguments and whose result is a [meta expression](#meta-expression).

```c++
struct a_meta_function_c {
using eval = a_meta_function_c;
static constexpr size_t arity = N;
template <class Actual_1, ..., class Actual_N>
struct template_m : a_meta_expression {};
};
```

Lax higher-order meta functions take meta functions as arguments and use them
via the `apply_m` [meta expression template](#meta-expression-template). Note
that `template_m` need not support [currying](#currying) like
[meta expression templates](#meta-expression-template), because `apply_m` takes
care of that.

### <a id="meta-value"></a> [≡](#contents) [Meta value](#meta-value)

A lax meta value is a [meta expression](#meta-expression) whose inner `eval`
type is an alias for the meta expression itself.

```c++
struct a_meta_value_c {
using eval = a_meta_value_c;
// and additional members depending on value
};
```

Meta values also typically include additional static constants, types, or type
templates.

### <a id="non-strict-evaluation"></a> [≡](#contents) [Non-strict evaluation](#non-strict-evaluation)

## <a id="motivation"></a> [≡](#contents) [Motivation](#motivation)

## <a id="references"></a> [≡](#contents) [References](#references)
35 changes: 15 additions & 20 deletions internals/testing/arithmetic_test.cpp
Original file line number Diff line number Diff line change
@@ -1,34 +1,29 @@
#include "lax_v1/arithmetic.hpp"
#include "lax_v1/force.hpp"

#include "config.hpp"

#include <type_traits>

static_assert(
std::is_same_v<
lax::force_t<lax::add_m<lax::value_t<short, 1>, lax::value_t<long, 2>>>,
lax::value_t<long, 3>>);
static_assert(std::is_same_v<lax::force_c<lax::adds_m<lax::value_c<short, 1>,
lax::value_c<long, 2>>>,
lax::value_c<long, 3>>);

static_assert(
std::is_same_v<
lax::force_t<lax::mod_m<lax::value_t<int, 2>, lax::value_t<int, 2>>>,
lax::value_t<int, 0>>);
std::is_same_v<lax::force_c<lax::mod_m<lax::auto_c<2>, lax::auto_c<2>>>,
lax::auto_c<0>>);

static_assert(
std::is_same_v<
lax::force_t<lax::mul_m<lax::value_t<int, 1>, lax::value_t<short, 2>>>,
lax::value_t<int, 2>>);
static_assert(std::is_same_v<
lax::force_c<lax::muls_m<lax::auto_c<1>, lax::value_c<short, 2>>>,
lax::auto_c<2>>);

static_assert(
std::is_same_v<
lax::force_t<lax::div_m<lax::value_t<short, 6>, lax::value_t<char, 2>>>,
lax::value_t<int, 3>>);
lax::force_c<lax::div_m<lax::value_c<short, 6>, lax::value_c<char, 2>>>,
lax::auto_c<3>>);

static_assert(
std::is_same_v<
lax::force_t<lax::sub_m<lax::value_t<int, 3>, lax::value_t<char, 2>>>,
lax::value_t<int, 1>>);
static_assert(std::is_same_v<
lax::force_c<lax::sub_m<lax::auto_c<3>, lax::value_c<char, 2>>>,
lax::auto_c<1>>);

static_assert(std::is_same_v<lax::force_t<lax::neg_m<lax::value_t<short, 3>>>,
lax::value_t<int, -3>>);
static_assert(std::is_same_v<lax::force_c<lax::neg_m<lax::value_c<short, 3>>>,
lax::auto_c<-3>>);
6 changes: 2 additions & 4 deletions internals/testing/comparison_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

#include "config.hpp"

static_assert(
lax::value_of_v<lax::gt_m<lax::value_t<int, 2>, lax::value_t<int, 1>>>);
static_assert(lax::gt_m<lax::auto_c<2>, lax::auto_c<1>>::value);

static_assert(
!lax::value_of_v<lax::eq_m<lax::value_t<int, 2>, lax::value_t<int, 1>>>);
static_assert(!lax::eq_m<lax::auto_c<2>, lax::auto_c<1>>::value);
2 changes: 2 additions & 0 deletions internals/testing/compile_only_test.cpp
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
#include "lax_v1/lax.hpp"

int main() { return 0; }
29 changes: 29 additions & 0 deletions internals/testing/core_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include "lax_v1/arithmetic.hpp"
#include "lax_v1/core.hpp"
#include "lax_v1/functional.hpp"
#include "lax_v1/type_traits.hpp"

#include "config.hpp"

struct X;
struct Y;
struct Z;

static_assert(
std::is_same_v<
lax::force_deep_c<
lax::seq_c<lax::add_m<>,
lax::add_m<lax::add_m<lax::auto_c<1>, lax::auto_c<2>>>,
lax::remove_pointer_m<lax::type_c<void *>>,
lax::seq_c<lax::add_m<lax::auto_c<1>, lax::auto_c<2>>>,
lax::fn_c<lax::seq_c<X, Y, Z>, lax::adds_m<X, Y, Z>>>>,
lax::seq_c<
lax::from_primitive_c<lax::add_p, 2>,
lax::closure_c<lax::from_primitive_c<lax::add_p, 2>,
lax::add_m<lax::auto_c<1>, lax::auto_c<2>>>,
lax::type_c<void>,
lax::seq_c<lax::auto_c<3>>,
lax::function_c<
X,
lax::function_c<Y,
lax::function_c<Z, lax::adds_m<X, Y, Z>>>>>>);
67 changes: 67 additions & 0 deletions internals/testing/functional_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#include "lax_v1/arithmetic.hpp"
#include "lax_v1/comparison.hpp"
#include "lax_v1/functional.hpp"
#include "lax_v1/type_traits.hpp"

#include "config.hpp"

static_assert(lax::apply_m<lax::compose_m<lax::neg_m<>, lax::neg_m<>>,
lax::auto_c<2>>::value == 2);

static_assert(lax::apply_m<lax::composes_m<lax::inc_m<>,
lax::neg_m<>,
lax::add_m<lax::auto_c<-1>>>,
lax::auto_c<1>>::value == 1);

static_assert(
lax::apply_m<
lax::pipes_m<lax::add_m<lax::auto_c<1>>, lax::neg_m<>, lax::dec_m<>>,
lax::auto_c<1>>::value == -3);

static_assert(lax::thru_m<lax::auto_c<1>,
lax::add_m<lax::auto_c<1>>,
lax::neg_m<>,
lax::add_m<lax::auto_c<-1>>,
lax::eq_m<lax::auto_c<-3>>>::value == true);

struct V;

static_assert(lax::apply_m<lax::function_c<V, lax::add_m<V, lax::neg_m<V>>>,
lax::auto_c<1>>::value == 0);

static_assert(lax::thru_m<lax::type_c<short * [1]>,
lax::remove_all_extents_m<>,
lax::remove_pointer_m<>,
lax::alignment_of_m<>>::value == alignof(short));

static_assert(lax::thru_m<lax::auto_c<0>,
lax::div_m<lax::auto_c<0>>,
lax::constant_m<lax::auto_c<101>>>::value == 101);

template <class T>
using adhoc_t = lax::as_type_trait_t<
lax::pipe_m<lax::remove_all_extents_m<>, lax::remove_pointer_m<>>,
T>;

static_assert(std::is_same_v<adhoc_t<int * [2][2]>, int>);

template <class T>
inline constexpr auto adhoc_v = lax::as_value_trait_v<
lax::pipe_m<lax::remove_all_extents_m<>, lax::alignment_of_m<>>,
T>;

static_assert(adhoc_v<int * [2][2]> == alignof(int *));

struct F;

template <int value>
inline constexpr auto factorial_v = lax::apply_m<
lax::fix_m<lax::fn_c<
lax::seq_c<F, V>,
lax::if_m<
lax::eq_m<lax::auto_c<0>, V>,
lax::auto_c<1>,
lax::mul_m<V, lax::apply_m<F, lax::sub_m<V, lax::auto_c<1>>>>>>>,
lax::auto_c<value>>::value;

static_assert(factorial_v<5> == 120);
22 changes: 14 additions & 8 deletions internals/testing/logical_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,20 @@

#include "config.hpp"

static_assert(
lax::value_of_v<
lax::if_m<lax::and_m<>, lax::value_t<int, 1>, lax::value_t<int, 2>>> ==
1);
static_assert(lax::if_m<lax::ands_m<>, lax::auto_c<1>, lax::auto_c<2>>::value ==
1);

static_assert(lax::if_m<lax::ors_m<>, lax::auto_c<1>, lax::auto_c<2>>::value ==
2);

static_assert(!lax::and_m<lax::false_c,
lax::div_m<lax::auto_c<1>, lax::auto_c<0>>>::value);

static_assert(
lax::value_of_v<
lax::if_m<lax::or_m<>, lax::value_t<int, 1>, lax::value_t<int, 2>>> ==
2);
lax::or_m<lax::true_c, lax::div_m<lax::auto_c<1>, lax::auto_c<0>>>::value);

static_assert(lax::not_m<lax::false_c>::value);

static_assert(lax::value_of_v<lax::not_m<lax::false_t>>);
static_assert(lax::switch_m<lax::case_c<lax::false_c, lax::auto_c<2>>,
lax::case_c<lax::true_c, lax::auto_c<1>>,
lax::default_c<lax::auto_c<3>>>::value == 1);
8 changes: 5 additions & 3 deletions internals/testing/type_traits_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,25 @@

#include "config.hpp"

static_assert(lax::value_of_v<lax::is_array_m<lax::type_t<int[2]>>>);
static_assert(lax::is_array_m<lax::type_c<int[2]>>::value);

template <class Value>
struct is_stored_plain_m
: lax::or_m<
lax::and_m<
lax::is_pointer_m<Value>,
lax::lte_m<lax::value_t<size_t, 2>,
lax::lte_m<lax::auto_c<2>,
lax::alignment_of_m<lax::remove_pointer_m<Value>>>>,
lax::and_m<lax::is_array_m<Value>,
is_stored_plain_m<lax::remove_all_extents_m<Value>>>> {};

template <class Value>
static inline constexpr bool is_stored_plain_v =
lax::value_of_v<is_stored_plain_m<lax::type_t<Value>>>;
is_stored_plain_m<lax::type_c<Value>>::value;

static_assert(!is_stored_plain_v<char>);
static_assert(!is_stored_plain_v<char *>);
static_assert(is_stored_plain_v<int *>);
static_assert(is_stored_plain_v<int * [2]>);

static_assert(!lax::is_same_m<lax::type_c<void>, lax::type_c<int>>::value);
18 changes: 9 additions & 9 deletions internals/testing/value_test.cpp
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
#include "lax_v1/value.hpp"
#include "lax_v1/core.hpp"

#include "config.hpp"

#include <type_traits>

static_assert(std::is_same_v<lax::value_t<bool, true>::value_type, bool>);
static_assert(std::is_same_v<lax::auto_c<true>::value_type, bool>);

static_assert(std::is_same_v<lax::value_t<char, 'x'>::value_type, char>);
static_assert(std::is_same_v<lax::value_t<short, 101>::value_type, short>);
static_assert(std::is_same_v<lax::value_t<int, 101>::value_type, int>);
static_assert(std::is_same_v<lax::auto_c<'x'>::value_type, char>);
static_assert(std::is_same_v<lax::value_c<short, 101>::value_type, short>);
static_assert(std::is_same_v<lax::auto_c<101>::value_type, int>);
static_assert(
std::is_same_v<lax::value_t<unsigned, 101u>::value_type, unsigned>);
static_assert(std::is_same_v<lax::value_t<long, 101l>::value_type, long>);
static_assert(std::is_same_v<lax::value_t<unsigned long, 101ul>::value_type,
std::is_same_v<lax::value_c<unsigned, 101u>::value_type, unsigned>);
static_assert(std::is_same_v<lax::value_c<long, 101l>::value_type, long>);
static_assert(std::is_same_v<lax::value_c<unsigned long, 101ul>::value_type,
unsigned long>);
static_assert(
std::is_same_v<lax::value_t<unsigned long long, 101ull>::value_type,
std::is_same_v<lax::value_c<unsigned long long, 101ull>::value_type,
unsigned long long>);
Loading