Last active
August 29, 2015 14:01
-
-
Save ldionne/fd460b13ef26856b1f3b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*! | |
* Barebones zip_with and fmap for std::tuple and std::integer_sequence. | |
* | |
* Copyright Louis Dionne 2014 | |
* Distributed under the Boost Software License, Version 1.0. | |
* (See accompanying file LICENSE.md or copy at | |
* http://www.boost.org/LICENSE_1_0.txt) | |
*/ | |
// Compiled with: | |
// clang++-3.5 -Wall -Wextra -pedantic -std=c++1y -c zip_with.cpp | |
#include <cstddef> | |
#include <tuple> | |
#include <type_traits> | |
#include <utility> | |
template <typename F, typename ...T, std::size_t ...Index> | |
constexpr auto fmap_impl(F f, std::tuple<T...> xs, std::index_sequence<Index...>) { | |
return std::make_tuple(f(std::get<Index>(xs))...); | |
} | |
template <typename F, typename ...T> | |
constexpr auto fmap(F f, std::tuple<T...> xs) { | |
return fmap_impl(f, xs, std::index_sequence_for<T...>{}); | |
} | |
// Note that we can't return a std::integer_sequence<T, f(Indices)...> | |
// because we can't go from runtime arguments to template arguments, even | |
// in constexpr. | |
template <typename F, typename T, T ...Indices> | |
constexpr auto fmap(F f, std::integer_sequence<T, Indices...>) { | |
return std::make_tuple(f(std::integral_constant<T, Indices>{})...); | |
} | |
// Requires a non-empty array. | |
template <typename T, std::size_t N> | |
constexpr T min(T (&arr)[N]) { | |
auto low = arr[0]; | |
for (auto n: arr) | |
if (n < low) | |
low = n; | |
return low; | |
} | |
template <typename F, typename ...Tuple> | |
constexpr auto zip_with(F f, Tuple ...xs) { | |
constexpr std::size_t lengths[] = {std::tuple_size<Tuple>{}...}; | |
constexpr std::size_t zip_length = min(lengths); | |
return fmap( | |
// We need constexpr lambdas badly... | |
[=](auto index) { return f(std::get<decltype(index){}>(xs)...); }, | |
std::make_index_sequence<zip_length>{} | |
); | |
} | |
/////////////////////////////////////////////////////////////////////// | |
// Tests | |
/////////////////////////////////////////////////////////////////////// | |
#include <cassert> | |
#include <functional> | |
// fmap on tuple | |
static_assert(fmap(std::negate<>{}, std::make_tuple()) == std::make_tuple(), ""); | |
static_assert(fmap(std::negate<>{}, std::make_tuple(1)) == std::make_tuple(-1), ""); | |
static_assert(fmap(std::negate<>{}, std::make_tuple(1, 2)) == std::make_tuple(-1, -2), ""); | |
static_assert(fmap(std::negate<>{}, std::make_tuple(1, 2, 3)) == std::make_tuple(-1, -2, -3), ""); | |
// fmap on integer_sequence | |
static_assert(fmap(std::negate<>{}, std::make_index_sequence<0>{}) == std::make_tuple(), ""); | |
static_assert(fmap(std::negate<>{}, std::make_index_sequence<1>{}) == std::make_tuple(0), ""); | |
static_assert(fmap(std::negate<>{}, std::make_index_sequence<2>{}) == std::make_tuple(0, -1), ""); | |
static_assert(fmap(std::negate<>{}, std::make_index_sequence<3>{}) == std::make_tuple(0, -1, -2), ""); | |
static_assert(fmap(std::negate<>{}, std::make_index_sequence<4>{}) == std::make_tuple(0, -1, -2, -3), ""); | |
int main() { | |
// zip_with on tuples (not constexpr) | |
assert( | |
zip_with(std::plus<>{}, std::make_tuple(), std::make_tuple()) | |
== | |
std::make_tuple() | |
); | |
assert( | |
zip_with(std::plus<>{}, std::make_tuple(1), std::make_tuple()) | |
== | |
std::make_tuple() | |
); | |
assert( | |
zip_with(std::plus<>{}, std::make_tuple(), std::make_tuple(3)) | |
== | |
std::make_tuple() | |
); | |
assert( | |
zip_with(std::plus<>{}, std::make_tuple(1), std::make_tuple(3)) | |
== | |
std::make_tuple(1 + 3) | |
); | |
assert( | |
zip_with(std::plus<>{}, std::make_tuple(1, 2), std::make_tuple(3, 4)) | |
== | |
std::make_tuple(1 + 3, 2 + 4) | |
); | |
assert( | |
zip_with(std::plus<>{}, std::make_tuple(1, 2, 3, 4), std::make_tuple(5, 6, 7)) | |
== | |
std::make_tuple(1 + 5, 2 + 6, 3 + 7) | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment