Code Monkey home page Code Monkey logo

metal's Introduction

Metal version godbolt.badge

Metal is a single-header C++11 library designed to make you love template metaprogramming.

Overview

#include <metal.hpp>

// First we need some Values
union x { char payload[10]; };
class y { public: char c; };
struct z { char c; int i; };

// ... from which we construct some Lists
using l0 = metal::list<>;
using l1 = metal::prepend<l0, x>;
using l2 = metal::append<l1, z>;
using l3 = metal::insert<l2, metal::number<1>, y>;

static_assert(metal::same<l1, metal::list<x>>::value, "");
static_assert(metal::same<l2, metal::list<x, z>>::value, "");
static_assert(metal::same<l3, metal::list<x, y, z>>::value, "");

// Lists are versatile, we can check their sizes...
static_assert(metal::size<l0>::value == 0, "");
static_assert(metal::size<l1>::value == 1, "");
static_assert(metal::size<l2>::value == 2, "");
static_assert(metal::size<l3>::value == 3, "");

// retrieve their elements...
static_assert(metal::same<metal::front<l3>, x>::value, "");
static_assert(metal::same<metal::back<l3>, z>::value, "");
static_assert(metal::same<metal::at<l3, metal::number<1>>, y>::value, "");

// count those that satisfy a predicate...
static_assert(metal::count_if<l3, metal::trait<std::is_class>>::value == 2, "");
static_assert(metal::count_if<l3, metal::trait<std::is_union>>::value == 1, "");

// We can create new Lists by removing elements...
using l0_ = metal::drop<l3, metal::number<3>>;
using l1_ = metal::take<l3, metal::number<1>>;
using l2_ = metal::erase<l3, metal::number<1>>;

static_assert(metal::same<l0, l0_>::value, "");
static_assert(metal::same<l1, l1_>::value, "");
static_assert(metal::same<l2, l2_>::value, "");

// by reversing the order of elements...
static_assert(metal::same<metal::reverse<l0>, metal::list<>>::value, "");
static_assert(metal::same<metal::reverse<l1>, metal::list<x>>::value, "");
static_assert(metal::same<metal::reverse<l2>, metal::list<z, x>>::value, "");
static_assert(metal::same<metal::reverse<l3>, metal::list<z, y, x>>::value, "");

// by transforming the elements...
using l2ptrs = metal::transform<metal::lazy<std::add_pointer>, l2>;
using l3refs = metal::transform<metal::lazy<std::add_lvalue_reference>, l3>;

static_assert(metal::same<l2ptrs, metal::list<x*, z*>>::value, "");
static_assert(metal::same<l3refs, metal::list<x&, y&, z&>>::value, "");

// even by sorting them...
template<class x, class y>
using smaller = metal::number<(sizeof(x) < sizeof(y))>;

using sorted = metal::sort<l3, metal::lambda<smaller>>;

static_assert(metal::same<sorted, metal::list<y, z, x>>::value, "");

// that and much more!

Quick Start

  1. Download metal.hpp
  2. #include </path/to/metal.hpp>
  3. Love template metaprogramming

Blazingly Fast

You don't need to just take my word for it, see for yourself at metaben.ch.

Portable

Metal is known to work on GCC, Clang, Visual Studio, and Xcode.

Documentation

The complete up-to-date documentation is available online.

License

This project is licensed under the MIT.

metal's People

Contributors

brunocodutra avatar corristo avatar ecrypa avatar fernandoandreotti avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

metal's Issues

Sort performance and techniques

Whats up @brunocodutra . You got a very nice library going here.

I was looking around and getting to know the library and techniques (since I'm a template noob :) ), so I decided to pick up metal::sort which is something I (should) understand and play with it.

I took a list of 1500 reversed unique types (char[1500], char[1499] ... ) and sorted it.
I takes around 5.5 seconds to do that in my machine (GCC 6.3).

Just for fun, I implemented quick sort. Time went to 30 seconds (and can reach recursion limit - not nice).

Anyway, I was intrigued as to some implementation choices, for example:

        template<typename x, typename y>
        struct _sort_impl<list<x, y>> {
            template<template<typename...> class expr>
            using type = if_<expr<y, x>, list<y, x>, list<x, y>>;
        };

as opposed to:

        template<typename x, typename y, template<typename...> class expr>
        struct _sort_impl<list<x, y>, expr> {
            using type = if_<expr<y, x>, list<y, x>, list<x, y>>;
        };

Why is that?
I imagined it could have something to do with performance, so I changed the code into the second version but the compilation time went down to 4.5 seconds.

::value and ::type aliases?

Would you accept a PR that adds aliases for ::value and ::type like the modern C++ standard library provides? E.g.

metal::same_v<t1, t2>

instead of:

metal::same<t1, t2>::value

If I'm not mistaken these would be implemented with variable templates:

namespace metal {
  template<typename... Ts>
  auto same_v = same<Ts...>::value;
}

Though I believe this requires C++14 so perhaps they would only be enabled if the compilation supports at least that standard.

Selectively implement metal::fold using C++17 fold expressions

For reference, following is a standalone working implementation of an eager left fold using fold expressions.

  • Tested on Clang 3.6+ and GCC 6+
#include <type_traits>

template<typename...> using void_ = void;

template<template<typename...> class expr> struct lambda {};
template<typename...> struct list {};

template<template<typename...> class expr, typename state>
struct fold_impl {
    using type = state;
};

template<template<typename...> class expr, typename state, typename val>
fold_impl<expr, expr<state, val>> operator<<(fold_impl<expr, state>&&, fold_impl<expr, val>&&);

template<typename, typename, typename, typename = void>
struct lazy_fold {};

template<typename... vals, typename state, template<typename...> class expr> 
struct lazy_fold<list<vals...>, state, lambda<expr>,
    void_<decltype((fold_impl<expr, state>{} << ... << fold_impl<expr, vals>{}))>
> :
    decltype((fold_impl<expr, state>{} << ... << fold_impl<expr, vals>{}))
{};

template<typename seq, typename state, typename lbd> using fold = typename lazy_fold<seq, state, lbd>::type;

static_assert(std::is_same<
    fold<list<int, int*, int**, int***, int****>, list<>, lambda<list>>,
    list<list<list<list<list<list<>, int>, int*>, int**>, int***>, int****>
>{});

int main() {}

Download link is broken

The single hpp-file download link seems to go to a file which actually contains the GitHub HTML representation of the file, not the raw code.

Consider renaming apply to unpack

Generally, apply is synonymous with invoke. MPL library uses apply to invoke a metafunction or lambda. Boost.Hana's apply works just like std::invoke.

However, your apply unpacks the elements of a list and then invokes the lambda, which I found to be surprising. It seems like unpack would be a better name and would avoid the confusion.

Provide metal::if_

metal::conditional is great for conditionally evaluating optionals, however, due to its lazy nature, it is not as well-suited for composition as an eager conditional the likes of mpl::if_.

Also, to avoid confusion with std::conditional, metal::conditional should be renamed to metal::cond after its counterpart in lisp.

Provide the same folder structure as the MPL

If the same structure as that of the MPL is used, then people could really just rename from boost/mpl/... to boost/mpl2/... in their includes. Also, one advantage of a backwards compatible MPL is the fact that one does not have to relearn new stuff. The plain directory structure of the old MPL was easy to grok and I think will be expected by users of this library. Just my 0.2.

Provide benchmarks

Implement a set of benchmarks that may be run via CMake and [ab]use Travis to keep the results up to date and somehow integrated into the documentation.

partition is very slow for large-ish inputs

While investigating the cause of timeouts on metaben.ch, I came across this (on GCC 4.9):

partition - metal

This causes the total test time to take over 500 s, which contributes to the timing out of metaben.ch. I would suggest fixing this, or we will have to reduce the max size of the sample used for metal on metaben.ch.

Try supporting the Intel compiler

It was suggested in #59 that it shouldn't be too difficult to support the Intel compiler, given that its compliance to the C++11 is similar to that of GCC 4.7.

Make metal::lift lenient

Currently, lifted lambdas unnecessarily evaluate every argument prior to invocation. That wouldn't be a problem if it weren't for the fact an invocation is aborted if an unused argument is empty.

For example,

metal::invoke_t<metal::lift_t<metal::_2>, metal::nothing, metal::just<int>, metal::nothing>

should yield int, but, currently, this invocation is ill-formed due to the fact lifting metal::_1 causes the evaluation of every argument, even if it only requires evaluating the second one.

metal::back not working

same code as the Document
`
#include <metal.hpp>

// First we need some Values
union x { char payload[10]; };
class y { public: char c; };
struct z { char c; int i; };

// ... from which we construct some Lists
using l0 = metal::list<>;
using l1 = metal::prepend<l0, x>;
using l2 = metal::append<l1, z>;
using l3 = metal::insert<l2, metal::number<1>, y>;

// retrieve their elements...
static_assert(metal::same<metal::front, x>::value, "");
static_assert(metal::same<metal::back, z>::value, ""); /// cant pass
static_assert(metal::same<metal::at<l3, metal::number<1>>, y>::value, "");

// retrieve their elements...
static_assert(metal::same<metal::front, x>::value, "");
static_assert(metal::same<metal::back, >::value, ""); /// blank can pass
static_assert(metal::same<metal::at<l3, metal::number<1>>, y>::value, "");
`

Migrate Travis builds to Trusty

As suggested by @grafikrobot, migrating to Trusty would have the benefit of having sudo enabled, which would make it possible to install newer version of development packages without awaiting for them to be whitelisted by the Travis crew.

Document the internal workings

Add a section to the documentation describing some of the techniques used under the hood. It should serve as a reference for contributors, as well as a gentle introduction to template metaprogramming for the uninitiated.

Bump the feature set to C++14

The C++14 feature set is implemented to a great extent since GCC 4.8 and MSVC 14 and also in its entirety since Clang 3.4.

Since these basically match the set of currently supported compiler versions, there should be no impediment preventing the use of C++14 features commonly implemented by all those compilers and their accompanying implementations of the standard library.

Simplify Numbers

Inspired by P0127R1 and as a follow up to #38, Numbers in Metal can be much simplified by making them invariant to their actual underlying integral types, which are in fact irrelevant to compile time computations.

Since it is not reasonable to bump Metal requirements to C++17 at this point, added to the fact no mainstream compiler seems to implement auto template parameters as of yet, here it should suffice to fix the underlying representation of Numbers to some reasonable integral type, say std::intmax_t or even int.

Provide lazy proxies for algorithms

As shown by the example below, lazy proxies help reducing clutter when fancy composition is desired, the question is where to put them. One option would be within namespace metal::lazy, another would be to name them like shown below, so they could live at the root of namespace metal.

originally posted on cpplang.slack.com

using namespace metal;

template<typename... args>
using Transform = bind<lambda<transform>, args...>;

template<typename... args>
using If_ = bind<lambda<if_>, args...>;

template<typename... args>
using Invoke = bind<lambda<invoke>, args...>;

using lbd = Transform<If_<Invoke<_1, _2, _3>, _2, _3>, quote<l>>;

Given a predicate pred and unary lambdas f and g, you can then conditionally transform l with either f or g according to pred.

invoke<lbd, pred, f, g>;

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.