Skip to content

Instantly share code, notes, and snippets.

@mralfarrakhan
Created September 16, 2023 05:02
Show Gist options
  • Select an option

  • Save mralfarrakhan/e8cc0391f4d2e2dcb6cacea314d640ca to your computer and use it in GitHub Desktop.

Select an option

Save mralfarrakhan/e8cc0391f4d2e2dcb6cacea314d640ca to your computer and use it in GitHub Desktop.
Compile time linked list in C++14
#pragma once
#include <type_traits>
#ifndef DEBUGM
namespace comptime {
namespace List {
#endif
// List variant for tail end.
struct Nothing {};
// List implementation, adapted from https://gist.github.com/hdon/da3ce733c26651c1d340
template<int Val = 0, typename T = Nothing>
struct List {
using Tail = T;
STC(int) value = Val;
STC(size_t) len = 1 + T::len;
};
template<int Val>
struct List<Val, Nothing> {
using Tail = Nothing;
STC(int) value = Val;
STC(size_t) len = 1;
};
// Indexing by recursion from first element
template<typename L, int I>
struct Index {
STC(int) value = Index<typename L::Tail, I - 1>::value;
};
template<typename L>
struct Index<L, 0> {
STC(int) value = L::value;
};
template<typename L>
struct Head {
using T = L;
};
// Tail getter = Index<L, 1>
template<typename L>
struct Tail {
using T = typename L::Tail;
};
// Generator from template args
template<int Val, int... Vals>
struct From {
using T = List<Val, typename From<Vals...>::T>;
};
template<int Val>
struct From<Val> {
using T = List<Val, Nothing>;
};
// Front concatenation
template<typename L, int Val>
struct Cons {
using T = List<Val, L>;
};
// Back concat.
template<typename L, int Val, typename M = L, int... Vals>
struct Append {
using T = typename Append<typename L::Tail, Val, L, Vals..., L::value>::T;
};
template<typename M, int Val, int... Vals>
struct Append<Nothing, Val, M, Vals...> {
using T = typename From<Vals..., Val>::T;
};
// Compile time mapping
// For now, feed a function-like struct F that takes one int template argument
// and calculation on static const member named `value`
template<typename L, template<int S> class F, typename M = L, int... Vals>
struct Map {
using T = typename Map<typename L::Tail, F, L, Vals..., F<L::value>::value>::T;
};
template<template<int S> class F, typename M, int... Vals>
struct Map<Nothing, F,M, Vals...> {
using T = typename From<Vals...>::T;
};
// zip two list, works like Map above
// stops at the shortes list
template<typename A, typename B, template<int R, int S> class F, typename M = A, typename N = B, int... Vals>
struct ZipWith {
using T = typename ZipWith<typename A::Tail, typename B::Tail, F, A, B, Vals..., F<A::value, B::value>::value>::T;
};
template<typename B, template<int R, int S> class F, typename M, typename N, int... Vals>
struct ZipWith<Nothing, B, F, M, N, Vals...> {
using T = typename From<Vals...>::T;
};
template<typename A, template<int R, int S> class F, typename M, typename N, int... Vals>
struct ZipWith<A, Nothing, F, M, N, Vals...> {
using T = typename From<Vals...>::T;
};
template<template<int R, int S> class F, typename M, typename N, int... Vals>
struct ZipWith<Nothing, Nothing, F, M, N, Vals...> {
using T = typename From<Vals...>::T;
};
#ifndef DEBUGM
}
}
#endif
#include <iostream>
#include <typeinfo>
#define DEBUGM
#include "list.h"
#ifndef DEBUGM
using namespace comptime::List;
#endif
#define print(v) std::cout << #v << ": " << v << std::endl
#define print_type(t) std::cout << #t << ": " << typeid(t).name() << std::endl // intelligible w/ clang
template<int S>
struct F {
static constexpr int value = S * S;
};
template<int S, int T>
struct G {
static constexpr int value = S * T;
};
int main() {
using head = From<11, 13, 15>::T;
using front = Cons<head, 9>::T;
using to = Append<front, 17>::T;
using second = Tail<Tail<to>::T>::T;
using map = Map<to, F>::T;
using zipped = ZipWith<head, second, G>::T;
print_type(head);
print_type(front);
print_type(to);
print_type(second);
print_type(map);
print_type(zipped);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment