From e93efa0d505e0337629b178d970e369c0745911d Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sun, 6 Oct 2013 13:47:19 -0700 Subject: [PATCH] clover: Import new utility library. Tested-by: Tom Stellard --- src/gallium/state_trackers/clover/Doxyfile | 2 +- .../state_trackers/clover/Makefile.sources | 10 + .../state_trackers/clover/util/adaptor.hpp | 183 ++++++++ .../state_trackers/clover/util/algebra.hpp | 160 +++++++ .../state_trackers/clover/util/algorithm.hpp | 206 +++++++++ .../state_trackers/clover/util/compat.cpp | 38 ++ .../state_trackers/clover/util/compat.hpp | 328 ++++++++++++++ .../state_trackers/clover/util/functional.hpp | 375 ++++++++++++++++ .../state_trackers/clover/util/lazy.hpp | 161 +++++++ .../state_trackers/clover/util/pointer.hpp | 157 +++++++ .../state_trackers/clover/util/range.hpp | 421 ++++++++++++++++++ .../state_trackers/clover/util/tuple.hpp | 117 +++++ 12 files changed, 2157 insertions(+), 1 deletion(-) create mode 100644 src/gallium/state_trackers/clover/util/adaptor.hpp create mode 100644 src/gallium/state_trackers/clover/util/algebra.hpp create mode 100644 src/gallium/state_trackers/clover/util/algorithm.hpp create mode 100644 src/gallium/state_trackers/clover/util/compat.cpp create mode 100644 src/gallium/state_trackers/clover/util/compat.hpp create mode 100644 src/gallium/state_trackers/clover/util/functional.hpp create mode 100644 src/gallium/state_trackers/clover/util/lazy.hpp create mode 100644 src/gallium/state_trackers/clover/util/pointer.hpp create mode 100644 src/gallium/state_trackers/clover/util/range.hpp create mode 100644 src/gallium/state_trackers/clover/util/tuple.hpp diff --git a/src/gallium/state_trackers/clover/Doxyfile b/src/gallium/state_trackers/clover/Doxyfile index 50250e75672..19337bbd656 100644 --- a/src/gallium/state_trackers/clover/Doxyfile +++ b/src/gallium/state_trackers/clover/Doxyfile @@ -610,7 +610,7 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = api/ core/ +INPUT = api/ core/ util/ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is diff --git a/src/gallium/state_trackers/clover/Makefile.sources b/src/gallium/state_trackers/clover/Makefile.sources index fd23d78b11f..e148ec8e584 100644 --- a/src/gallium/state_trackers/clover/Makefile.sources +++ b/src/gallium/state_trackers/clover/Makefile.sources @@ -1,4 +1,14 @@ CPP_SOURCES := \ + util/adaptor.hpp \ + util/algebra.hpp \ + util/algorithm.hpp \ + util/compat.cpp \ + util/compat.hpp \ + util/functional.hpp \ + util/lazy.hpp \ + util/pointer.hpp \ + util/range.hpp \ + util/tuple.hpp \ core/base.hpp \ core/compat.hpp \ core/compiler.hpp \ diff --git a/src/gallium/state_trackers/clover/util/adaptor.hpp b/src/gallium/state_trackers/clover/util/adaptor.hpp new file mode 100644 index 00000000000..fafb01fe9e7 --- /dev/null +++ b/src/gallium/state_trackers/clover/util/adaptor.hpp @@ -0,0 +1,183 @@ +// +// Copyright 2013 Francisco Jerez +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +#ifndef CLOVER_UTIL_ADAPTOR_HPP +#define CLOVER_UTIL_ADAPTOR_HPP + +#include + +#include "util/tuple.hpp" +#include "util/pointer.hpp" +#include "util/functional.hpp" + +namespace clover { + namespace detail { + /// + /// Implementation of the iterator concept that transforms the + /// value of the source iterators \a Is on dereference by use of + /// a functor \a F. + /// + /// The exact category of the resulting iterator should be the + /// least common denominator of the source iterator categories. + /// + template + class iterator_adaptor { + public: + typedef std::forward_iterator_tag iterator_category; + typedef typename std::result_of< + F(typename std::iterator_traits::reference...) + >::type reference; + typedef typename std::remove_reference::type value_type; + typedef pseudo_ptr pointer; + typedef std::ptrdiff_t difference_type; + + iterator_adaptor() { + } + + iterator_adaptor(F f, std::tuple &&its) : + f(f), its(std::move(its)) { + } + + reference + operator*() const { + return tuple::apply(f, tuple::map(derefs(), its)); + } + + iterator_adaptor & + operator++() { + tuple::map(preincs(), its); + return *this; + } + + iterator_adaptor + operator++(int) { + auto jt = *this; + ++*this; + return jt; + } + + bool + operator==(const iterator_adaptor &jt) const { + return its == jt.its; + } + + bool + operator!=(const iterator_adaptor &jt) const { + return its != jt.its; + } + + pointer + operator->() const { + return { **this }; + } + + iterator_adaptor & + operator--() { + tuple::map(predecs(), its); + return *this; + } + + iterator_adaptor + operator--(int) { + auto jt = *this; + --*this; + return jt; + } + + iterator_adaptor & + operator+=(difference_type n) { + tuple::map(advances_by(n), its); + return *this; + } + + iterator_adaptor & + operator-=(difference_type n) { + tuple::map(advances_by(n), its); + return *this; + } + + iterator_adaptor + operator+(difference_type n) const { + auto jt = *this; + jt += n; + return jt; + } + + iterator_adaptor + operator-(difference_type n) const { + auto jt = *this; + jt -= n; + return jt; + } + + difference_type + operator-(const iterator_adaptor &jt) const { + return std::get<0>(its) - std::get<0>(jt.its); + } + + reference + operator[](difference_type n) const { + return *(*this + n); + } + + bool + operator<(iterator_adaptor &jt) const { + return *this - jt < 0; + } + + bool + operator>(iterator_adaptor &jt) const { + return *this - jt > 0; + } + + bool + operator>=(iterator_adaptor &jt) const { + return !(*this < jt); + } + + bool + operator<=(iterator_adaptor &jt) const { + return !(*this > jt); + } + + protected: + F f; + std::tuple its; + }; + + template + iterator_adaptor + operator+(typename iterator_adaptor::difference_type n, + const iterator_adaptor &jt) { + return (jt + n); + } + + template + iterator_adaptor + operator-(typename iterator_adaptor::difference_type n, + const iterator_adaptor &jt) { + return (jt - n); + } + } +} + +#endif diff --git a/src/gallium/state_trackers/clover/util/algebra.hpp b/src/gallium/state_trackers/clover/util/algebra.hpp new file mode 100644 index 00000000000..43a9d8bbf5f --- /dev/null +++ b/src/gallium/state_trackers/clover/util/algebra.hpp @@ -0,0 +1,160 @@ +// +// Copyright 2013 Francisco Jerez +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +#ifndef CLOVER_UTIL_ALGEBRA_HPP +#define CLOVER_UTIL_ALGEBRA_HPP + +#include + +#include "util/range.hpp" +#include "util/functional.hpp" + +namespace clover { + /// + /// Class that identifies vectors (in the linear-algebraic sense). + /// + /// There should be a definition of this class for each type that + /// makes sense as vector arithmetic operand. + /// + template + struct vector_traits; + + /// + /// References of vectors are vectors. + /// + template + struct vector_traits::enable> { + typedef void enable; + }; + + /// + /// Constant vectors are vectors. + /// + template + struct vector_traits::enable> { + typedef void enable; + }; + + /// + /// Arrays of arithmetic types are vectors. + /// + template + struct vector_traits, + typename std::enable_if< + std::is_arithmetic::value>::type> { + typedef void enable; + }; + + namespace detail { + template + struct are_defined { + typedef void enable; + }; + } + + /// + /// The result of mapping a vector is a vector. + /// + template + struct vector_traits, + typename detail::are_defined< + typename vector_traits::enable...>::enable> { + typedef void enable; + }; + + /// + /// Vector sum. + /// + template::enable, + typename = typename vector_traits::enable> + adaptor_range + operator+(U &&u, V &&v) { + return map(plus(), std::forward(u), std::forward(v)); + } + + /// + /// Vector difference. + /// + template::enable, + typename = typename vector_traits::enable> + adaptor_range + operator-(U &&u, V &&v) { + return map(minus(), std::forward(u), std::forward(v)); + } + + /// + /// Scalar multiplication. + /// + template::enable> + adaptor_range, U> + operator*(U &&u, T &&a) { + return map(multiplies_by(std::forward(a)), std::forward(u)); + } + + /// + /// Scalar multiplication. + /// + template::enable> + adaptor_range, U> + operator*(T &&a, U &&u) { + return map(multiplies_by(std::forward(a)), std::forward(u)); + } + + /// + /// Additive inverse. + /// + template::enable> + adaptor_range + operator-(U &&u) { + return map(negate(), std::forward(u)); + } + + namespace detail { + template + using dot_type = typename std::common_type< + typename std::remove_reference::type::value_type, + typename std::remove_reference::type::value_type + >::type; + } + + /// + /// Dot product of two vectors. + /// + /// It can also do matrix multiplication if \a u or \a v is a + /// vector of vectors. + /// + template::enable, + typename = typename vector_traits::enable> + detail::dot_type + dot(U &&u, V &&v) { + return fold(plus(), detail::dot_type(), + map(multiplies(), u, v)); + } +} + +#endif diff --git a/src/gallium/state_trackers/clover/util/algorithm.hpp b/src/gallium/state_trackers/clover/util/algorithm.hpp new file mode 100644 index 00000000000..4eb90cffa9f --- /dev/null +++ b/src/gallium/state_trackers/clover/util/algorithm.hpp @@ -0,0 +1,206 @@ +// +// Copyright 2013 Francisco Jerez +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +#ifndef CLOVER_UTIL_ALGORITHM_HPP +#define CLOVER_UTIL_ALGORITHM_HPP + +#include +#include + +#include "util/range.hpp" +#include "util/functional.hpp" + +namespace clover { + namespace detail { + template + using preferred_reference_type = decltype(*std::declval().begin()); + } + + /// + /// Return the first element in a range. + /// + template + detail::preferred_reference_type + head(R &&r) { + assert(!r.empty()); + return r.front(); + } + + /// + /// Return all elements in a range but the first. + /// + template + slice_range + tail(R &&r) { + assert(!r.empty()); + return { std::forward(r), 1, r.size() }; + } + + /// + /// Combine a variable number of ranges element-wise in a single + /// range of tuples. + /// + template + adaptor_range + zip(Rs &&... rs) { + return map(zips(), std::forward(rs)...); + } + + /// + /// Evaluate the elements of a range. + /// + /// Useful because most of the range algorithms evaluate their + /// result lazily. + /// + template + void + eval(R &&r) { + for (auto i = r.begin(), e = r.end(); i != e; ++i) + *i; + } + + /// + /// Apply functor \a f element-wise on a variable number of ranges + /// \a rs. + /// + /// The functor \a f should take as many arguments as ranges are + /// provided. + /// + template + void + for_each(F &&f, Rs &&... rs) { + eval(map(std::forward(f), std::forward(rs)...)); + } + + /// + /// Copy all elements from range \a r into an output container + /// starting from iterator \a i. + /// + template + void + copy(R &&r, I i) { + for (detail::preferred_reference_type x : r) + *(i++) = x; + } + + /// + /// Reduce the elements of range \a r by applying functor \a f + /// element by element. + /// + /// \a f should take an accumulator value (which is initialized to + /// \a a) and an element value as arguments, and return an updated + /// accumulator value. + /// + /// \returns The final value of the accumulator. + /// + template + A + fold(F &&f, A a, R &&r) { + for (detail::preferred_reference_type x : r) + a = f(a, x); + + return a; + } + + /// + /// Return how many elements of range \a r are equal to \a x. + /// + template + typename std::remove_reference::type::size_type + count(T &&x, R &&r) { + typename std::remove_reference::type::size_type n = 0; + + for (detail::preferred_reference_type y : r) { + if (x == y) + n++; + } + + return n; + } + + /// + /// Return the first element in range \a r for which predicate \a f + /// evaluates to true. + /// + template + detail::preferred_reference_type + find(F &&f, R &&r) { + for (detail::preferred_reference_type x : r) { + if (f(x)) + return x; + } + + throw std::out_of_range(""); + } + + /// + /// Return true if the element-wise application of predicate \a f + /// on \a rs evaluates to true for all elements. + /// + template + bool + all_of(F &&f, Rs &&... rs) { + for (auto b : map(f, rs...)) { + if (!b) + return false; + } + + return true; + } + + /// + /// Return true if the element-wise application of predicate \a f + /// on \a rs evaluates to true for any element. + /// + template + bool + any_of(F &&f, Rs &&... rs) { + for (auto b : map(f, rs...)) { + if (b) + return true; + } + + return false; + } + + /// + /// Erase elements for which predicate \a f evaluates to true from + /// container \a r. + /// + template + void + erase_if(F &&f, R &&r) { + auto i = r.begin(), e = r.end(); + + for (auto j = r.begin(); j != e; ++j) { + if (!f(*j)) { + if (j != i) + *i = std::move(*j); + ++i; + } + } + + r.erase(i, e); + } +} + +#endif diff --git a/src/gallium/state_trackers/clover/util/compat.cpp b/src/gallium/state_trackers/clover/util/compat.cpp new file mode 100644 index 00000000000..80d5b3ecf82 --- /dev/null +++ b/src/gallium/state_trackers/clover/util/compat.cpp @@ -0,0 +1,38 @@ +// +// Copyright 2013 Francisco Jerez +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +#include "util/compat.hpp" + +using namespace clover::compat; + +exception::~exception() { +} + +const char * +exception::what() const { + return ""; +} + +const char * +runtime_error::what() const { + return _what.c_str(); +} diff --git a/src/gallium/state_trackers/clover/util/compat.hpp b/src/gallium/state_trackers/clover/util/compat.hpp new file mode 100644 index 00000000000..e68d9df2969 --- /dev/null +++ b/src/gallium/state_trackers/clover/util/compat.hpp @@ -0,0 +1,328 @@ +// +// Copyright 2012 Francisco Jerez +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +#ifndef CLOVER_UTIL_COMPAT_HPP +#define CLOVER_UTIL_COMPAT_HPP + +#include +#include +#include +#include +#include + +namespace clover { + namespace compat { + // XXX - For cases where we can't rely on STL... I.e. the + // interface between code compiled as C++98 and C++11 + // source. Get rid of this as soon as everything can be + // compiled as C++11. + + template + class vector { + protected: + static T * + alloc(int n, const T *q, int m) { + T *p = reinterpret_cast(std::malloc(n * sizeof(T))); + + for (int i = 0; i < m; ++i) + new(&p[i]) T(q[i]); + + return p; + } + + static void + free(int n, T *p) { + for (int i = 0; i < n; ++i) + p[i].~T(); + + std::free(p); + } + + public: + typedef T *iterator; + typedef const T *const_iterator; + typedef T value_type; + typedef T &reference; + typedef const T &const_reference; + typedef std::ptrdiff_t difference_type; + typedef std::size_t size_type; + + vector() : p(NULL), n(0) { + } + + vector(const vector &v) : p(alloc(v.n, v.p, v.n)), n(v.n) { + } + + vector(iterator p, size_type n) : p(alloc(n, p, n)), n(n) { + } + + template + vector(const C &v) : + p(alloc(v.size(), &*v.begin(), v.size())), n(v.size()) { + } + + ~vector() { + free(n, p); + } + + vector & + operator=(const vector &v) { + free(n, p); + + p = alloc(v.n, v.p, v.n); + n = v.n; + + return *this; + } + + void + reserve(size_type m) { + if (n < m) { + T *q = alloc(m, p, n); + free(n, p); + + p = q; + n = m; + } + } + + void + resize(size_type m, T x = T()) { + size_type n = size(); + + reserve(m); + + for (size_type i = n; i < m; ++i) + new(&p[i]) T(x); + } + + void + push_back(const T &x) { + size_type n = size(); + reserve(n + 1); + new(&p[n]) T(x); + } + + size_type + size() const { + return n; + } + + iterator + begin() { + return p; + } + + const_iterator + begin() const { + return p; + } + + iterator + end() { + return p + n; + } + + const_iterator + end() const { + return p + n; + } + + reference + operator[](size_type i) { + return p[i]; + } + + const_reference + operator[](size_type i) const { + return p[i]; + } + + private: + iterator p; + size_type n; + }; + + template + class vector_ref { + public: + typedef T *iterator; + typedef const T *const_iterator; + typedef T value_type; + typedef T &reference; + typedef const T &const_reference; + typedef std::ptrdiff_t difference_type; + typedef std::size_t size_type; + + vector_ref(iterator p, size_type n) : p(p), n(n) { + } + + template + vector_ref(C &v) : p(&*v.begin()), n(v.size()) { + } + + size_type + size() const { + return n; + } + + iterator + begin() { + return p; + } + + const_iterator + begin() const { + return p; + } + + iterator + end() { + return p + n; + } + + const_iterator + end() const { + return p + n; + } + + reference + operator[](int i) { + return p[i]; + } + + const_reference + operator[](int i) const { + return p[i]; + } + + private: + iterator p; + size_type n; + }; + + class istream { + public: + typedef vector_ref buffer_t; + + class error { + public: + virtual ~error() {} + }; + + istream(const buffer_t &buf) : buf(buf), offset(0) {} + + void + read(char *p, size_t n) { + if (offset + n > buf.size()) + throw error(); + + std::memcpy(p, buf.begin() + offset, n); + offset += n; + } + + private: + const buffer_t &buf; + size_t offset; + }; + + class ostream { + public: + typedef vector buffer_t; + + ostream(buffer_t &buf) : buf(buf), offset(buf.size()) {} + + void + write(const char *p, size_t n) { + buf.resize(offset + n); + std::memcpy(buf.begin() + offset, p, n); + offset += n; + } + + private: + buffer_t &buf; + size_t offset; + }; + + class string : public vector_ref { + public: + string(const char *p) : vector_ref(p, std::strlen(p)) { + } + + template + string(const C &v) : vector_ref(v) { + } + + operator std::string() const { + return std::string(begin(), end()); + } + + const char * + c_str() const { + return begin(); + } + + const char * + find(const string &s) const { + for (size_t i = 0; i + s.size() < size(); ++i) { + if (!std::memcmp(begin() + i, s.begin(), s.size())) + return begin() + i; + } + + return end(); + } + }; + + template + bool + operator==(const vector_ref &a, const vector_ref &b) { + if (a.size() != b.size()) + return false; + + for (size_t i = 0; i < a.size(); ++i) + if (a[i] != b[i]) + return false; + + return true; + } + + class exception { + public: + exception() {} + virtual ~exception(); + + virtual const char *what() const; + }; + + class runtime_error : public exception { + public: + runtime_error(const string &what) : _what(what) {} + + virtual const char *what() const; + + protected: + string _what; + }; + } +} + +#endif diff --git a/src/gallium/state_trackers/clover/util/functional.hpp b/src/gallium/state_trackers/clover/util/functional.hpp new file mode 100644 index 00000000000..8e0b483a78f --- /dev/null +++ b/src/gallium/state_trackers/clover/util/functional.hpp @@ -0,0 +1,375 @@ +// +// Copyright 2013 Francisco Jerez +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +#ifndef CLOVER_UTIL_FUNCTIONAL_HPP +#define CLOVER_UTIL_FUNCTIONAL_HPP + +#include + +namespace clover { + struct identity { + template + typename std::remove_reference::type + operator()(T &&x) const { + return x; + } + }; + + struct plus { + template + typename std::common_type::type + operator()(T x, S y) const { + return x + y; + } + }; + + struct minus { + template + typename std::common_type::type + operator()(T x, S y) const { + return x - y; + } + }; + + struct negate { + template + T + operator()(T x) const { + return -x; + } + }; + + struct multiplies { + template + typename std::common_type::type + operator()(T x, S y) const { + return x * y; + } + }; + + struct divides { + template + typename std::common_type::type + operator()(T x, S y) const { + return x / y; + } + }; + + struct modulus { + template + typename std::common_type::type + operator()(T x, S y) const { + return x % y; + } + }; + + struct minimum { + template + T + operator()(T x) const { + return x; + } + + template + T + operator()(T x, Ts... xs) const { + T y = minimum()(xs...); + return x < y ? x : y; + } + }; + + struct maximum { + template + T + operator()(T x) const { + return x; + } + + template + T + operator()(T x, Ts... xs) const { + T y = maximum()(xs...); + return x < y ? y : x; + } + }; + + struct preincs { + template + T & + operator()(T &x) const { + return ++x; + } + }; + + struct predecs { + template + T & + operator()(T &x) const { + return --x; + } + }; + + template + class multiplies_by_t { + public: + multiplies_by_t(T x) : x(x) { + } + + template + typename std::common_type::type + operator()(S y) const { + return x * y; + } + + private: + T x; + }; + + template + multiplies_by_t + multiplies_by(T x) { + return { x }; + } + + template + class preincs_by_t { + public: + preincs_by_t(T n) : n(n) { + } + + template + S & + operator()(S &x) const { + return x += n; + } + + private: + T n; + }; + + template + preincs_by_t + preincs_by(T n) { + return { n }; + } + + template + class predecs_by_t { + public: + predecs_by_t(T n) : n(n) { + } + + template + S & + operator()(S &x) const { + return x -= n; + } + + private: + T n; + }; + + template + predecs_by_t + predecs_by(T n) { + return { n }; + } + + struct greater { + template + bool + operator()(T x, S y) const { + return x > y; + } + }; + + struct derefs { + template + auto + operator()(T &&x) const -> decltype(*x) { + return *x; + } + }; + + struct addresses { + template + T * + operator()(T &x) const { + return &x; + } + + template + T * + operator()(std::reference_wrapper x) const { + return &x.get(); + } + }; + + struct begins { + template + auto + operator()(T &x) const -> decltype(x.begin()) { + return x.begin(); + } + }; + + struct ends { + template + auto + operator()(T &x) const -> decltype(x.end()) { + return x.end(); + } + }; + + struct sizes { + template + auto + operator()(T &x) const -> decltype(x.size()) { + return x.size(); + } + }; + + template + class advances_by_t { + public: + advances_by_t(T n) : n(n) { + } + + template + S + operator()(S &&it) const { + std::advance(it, n); + return it; + } + + private: + T n; + }; + + template + advances_by_t + advances_by(T n) { + return { n }; + } + + struct zips { + template + std::tuple + operator()(Ts &&... xs) const { + return std::tuple(std::forward(xs)...); + } + }; + + struct is_zero { + template + bool + operator()(const T &x) const { + return x == 0; + } + }; + + struct keys { + template + typename std::remove_reference

::type::first_type & + operator()(P &&p) const { + return p.first; + } + }; + + struct values { + template + typename std::remove_reference

::type::second_type & + operator()(P &&p) const { + return p.second; + } + }; + + class name_equals { + public: + name_equals(const std::string &name) : name(name) { + } + + template + bool + operator()(const T &x) const { + return std::string(x.name.begin(), x.name.end()) == name; + } + + private: + const std::string &name; + }; + + template + class key_equals_t { + public: + key_equals_t(T &&x) : x(x) { + } + + template + bool + operator()(const std::pair &p) const { + return p.first == x; + } + + private: + T x; + }; + + template + key_equals_t + key_equals(T &&x) { + return { std::forward(x) }; + } + + template + class type_equals_t { + public: + type_equals_t(T type) : type(type) { + } + + template + bool + operator()(const S &x) const { + return x.type == type; + } + + private: + T type; + }; + + template + type_equals_t + type_equals(T x) { + return { x }; + } + + struct interval_overlaps { + template + bool + operator()(T x0, T x1, T y0, T y1) { + return ((x0 <= y0 && y0 < x1) || + (y0 <= x0 && x0 < y1)); + } + }; +} + +#endif diff --git a/src/gallium/state_trackers/clover/util/lazy.hpp b/src/gallium/state_trackers/clover/util/lazy.hpp new file mode 100644 index 00000000000..e32a8f8b1b9 --- /dev/null +++ b/src/gallium/state_trackers/clover/util/lazy.hpp @@ -0,0 +1,161 @@ +// +// Copyright 2013 Francisco Jerez +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +#ifndef CLOVER_UTIL_LAZY_HPP +#define CLOVER_UTIL_LAZY_HPP + +#include +#include +#include + +namespace clover { + namespace detail { + template + class basic_lazy { + public: + virtual + ~basic_lazy() { + } + + virtual basic_lazy * + clone() const = 0; + + virtual + operator T() const = 0; + }; + + template + class deferred_lazy : public basic_lazy { + public: + template + deferred_lazy(G &&f) : f(new F(std::forward(f))) { + } + + virtual basic_lazy * + clone() const { + return new deferred_lazy(*this); + } + + operator T() const { + if (f) { + x = (*f)(); + f = {}; + } + + return x; + } + + private: + mutable std::shared_ptr f; + mutable T x; + }; + + template + class strict_lazy : public basic_lazy { + public: + template + strict_lazy(S &&x) : x(std::forward(x)) { + } + + virtual basic_lazy * + clone() const { + return new strict_lazy(*this); + } + + operator T() const { + return x; + } + + private: + T x; + }; + } + + /// + /// Object that represents a value of type \a T that is calculated + /// lazily as soon as it is required. + /// + template + class lazy { + public: + class undefined_error : std::logic_error { + public: + undefined_error() : std::logic_error("") { + } + }; + + /// + /// Initialize to some fixed value \a x which isn't calculated + /// lazily. + /// + lazy(T x) : obj(new detail::strict_lazy(x)) { + } + + /// + /// Initialize by providing a functor \a f that will calculate + /// the value on-demand. + /// + template + lazy(F &&f) : obj(new detail::deferred_lazy< + T, typename std::remove_reference::type + >(std::forward(f))) { + } + + /// + /// Initialize to undefined. + /// + lazy() : lazy([]() { + throw undefined_error(); + return T(); + }) { + } + + lazy(const lazy &other) : obj(obj->clone()) { + } + + lazy(lazy &&other) : obj(NULL) { + std::swap(obj, other.obj); + } + + ~lazy() { + delete obj; + } + + lazy & + operator=(lazy other) { + std::swap(obj, other.obj); + return *this; + } + + /// + /// Evaluate the value. + /// + operator T() const { + return *obj; + } + + private: + detail::basic_lazy *obj; + }; +} + +#endif diff --git a/src/gallium/state_trackers/clover/util/pointer.hpp b/src/gallium/state_trackers/clover/util/pointer.hpp new file mode 100644 index 00000000000..f0c5b1618a5 --- /dev/null +++ b/src/gallium/state_trackers/clover/util/pointer.hpp @@ -0,0 +1,157 @@ +// +// Copyright 2013 Francisco Jerez +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +#ifndef CLOVER_UTIL_POINTER_HPP +#define CLOVER_UTIL_POINTER_HPP + +#include + +namespace clover { + /// + /// Base class for objects that support reference counting. + /// + class ref_counter { + public: + ref_counter() : _ref_count(1) {} + + unsigned + ref_count() { + return _ref_count; + } + + void + retain() { + _ref_count++; + } + + bool + release() { + return (--_ref_count) == 0; + } + + private: + std::atomic _ref_count; + }; + + /// + /// Intrusive smart pointer for objects that implement the + /// clover::ref_counter interface. + /// + template + class ref_ptr { + public: + ref_ptr(T *q = NULL) : p(NULL) { + reset(q); + } + + ref_ptr(const ref_ptr &ref) : p(NULL) { + reset(ref.p); + } + + ~ref_ptr() { + reset(NULL); + } + + void + reset(T *q = NULL) { + if (q) + q->retain(); + if (p && p->release()) + delete p; + p = q; + } + + ref_ptr & + operator=(const ref_ptr &ref) { + reset(ref.p); + return *this; + } + + T & + operator*() const { + return *p; + } + + T * + operator->() const { + return p; + } + + explicit operator bool() const { + return p; + } + + private: + T *p; + }; + + /// + /// Transfer the caller's ownership of a reference-counted object + /// to a clover::ref_ptr smart pointer. + /// + template + inline ref_ptr + transfer(T *p) { + ref_ptr ref { p }; + p->release(); + return ref; + } + + /// + /// Class that implements the usual pointer interface but in fact + /// contains the object it seems to be pointing to. + /// + template + class pseudo_ptr { + public: + pseudo_ptr(T x) : x(x) { + } + + pseudo_ptr(const pseudo_ptr &p) : x(p.x) { + } + + pseudo_ptr & + operator=(const pseudo_ptr &p) { + x = p.x; + return *this; + } + + T & + operator*() { + return x; + } + + T * + operator->() { + return &x; + } + + explicit operator bool() const { + return true; + } + + private: + T x; + }; +} + +#endif diff --git a/src/gallium/state_trackers/clover/util/range.hpp b/src/gallium/state_trackers/clover/util/range.hpp new file mode 100644 index 00000000000..151992ed8f4 --- /dev/null +++ b/src/gallium/state_trackers/clover/util/range.hpp @@ -0,0 +1,421 @@ +// +// Copyright 2013 Francisco Jerez +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +#ifndef CLOVER_UTIL_RANGE_HPP +#define CLOVER_UTIL_RANGE_HPP + +#include +#include + +#include "util/adaptor.hpp" + +namespace clover { + /// + /// Class that identifies container types where the elements of a + /// range can be stored by the type conversion operator. + /// + /// \a T identifies the range element type. + /// + template + struct range_store_traits; + + template + struct range_store_traits> { + typedef void enable; + + template + static std::vector + create(const R &r) { + return { r.begin(), r.end() }; + } + }; + + template + struct range_store_traits> { + typedef void enable; + + template + static std::array + create(const R &r) { + std::array v; + assert(r.size() == v.size()); + copy(r, v.begin()); + return v; + } + }; + + namespace detail { + /// + /// Common functionality that is shared by other implementations + /// of the container concept. + /// + template + class basic_range { + public: + typedef I iterator; + typedef CI const_iterator; + typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::reference + reference; + typedef typename std::iterator_traits::reference + const_reference; + typedef typename std::iterator_traits::difference_type + difference_type; + typedef std::size_t size_type; + + bool + operator==(const basic_range &r) const { + return *static_cast(this) == r; + } + + bool + operator!=(const basic_range &r) const { + return !(*this == r); + } + + iterator + begin() { + return static_cast(this)->begin(); + } + + iterator + end() { + return static_cast(this)->end(); + } + + const_iterator + begin() const { + return static_cast(this)->begin(); + } + + const_iterator + end() const { + return static_cast(this)->end(); + } + + std::reverse_iterator + rbegin() { + return { begin() }; + } + + std::reverse_iterator + rend() { + return { end() }; + } + + reference + front() { + return *begin(); + } + + reference + back() { + return *(end() - 1); + } + + bool + empty() const { + return begin() == end(); + } + + reference + at(size_type i) { + if (i >= static_cast(this)->size()) + throw std::out_of_range(""); + + return begin()[i]; + } + + const_reference + at(size_type i) const { + if (i >= static_cast(this)->size()) + throw std::out_of_range(""); + + return begin()[i]; + } + + reference + operator[](size_type i) { + return begin()[i]; + } + + const_reference + operator[](size_type i) const { + return begin()[i]; + } + + template + using store_traits = range_store_traits< + typename std::remove_cv::type, V + >; + + template::enable> + operator V() const { + return store_traits::create(*static_cast(this)); + } + }; + } + + /// + /// Range that contains all elements delimited by an iterator pair + /// (\a i, \a j). Use range() as convenience constructor. + /// + template + class iterator_range : public detail::basic_range, I, I> { + public: + typedef detail::basic_range, I, I> super; + + iterator_range() : i(), j() { + } + + iterator_range(I i, I j) : i(i), j(j) { + } + + bool + operator==(const iterator_range &r) const { + return i == r.i && j == r.j; + } + + I + begin() const { + return i; + } + + I + end() const { + return j; + } + + typename super::size_type + size() const { + return end() - begin(); + } + + private: + I i, j; + }; + + namespace detail { + template + using preferred_iterator_type = decltype(std::declval().begin()); + + template + using adaptor_iterator = detail::iterator_adaptor< + F, preferred_iterator_type...>; + + template + using adaptor_const_iterator = detail::iterator_adaptor< + F, preferred_iterator_type...>; + } + + /// + /// Range that transforms the contents of a number of source ranges + /// \a os element-wise by using the provided functor \a f. Use + /// map() as convenience constructor. + /// + template + class adaptor_range : + public detail::basic_range, + detail::adaptor_iterator, + detail::adaptor_const_iterator> { + public: + typedef detail::basic_range, + detail::adaptor_iterator, + detail::adaptor_const_iterator + > super; + + template + adaptor_range(G &&f, Rs &&... os) : + f(std::forward(f)), os(std::forward(os)...) { + } + + bool + operator==(const adaptor_range &r) const { + return f == r.f && os == r.os; + } + + detail::adaptor_iterator + begin() { + return { f, tuple::map(begins(), os) }; + } + + detail::adaptor_iterator + end() { + return { f, tuple::map(advances_by(size()), + tuple::map(begins(), os)) }; + } + + detail::adaptor_const_iterator + begin() const { + return { f, tuple::map(begins(), os) }; + } + + detail::adaptor_const_iterator + end() const { + return { f, tuple::map(ends(), os) }; + } + + typename super::size_type + size() const { + return tuple::apply(minimum(), tuple::map(sizes(), os)); + } + + private: + F f; + std::tuple os; + }; + + /// + /// Range that contains all elements delimited by the index pair + /// (\a i, \a j) in the source range \a r. Use slice() as + /// convenience constructor. + /// + template + class slice_range : + public detail::basic_range, + detail::preferred_iterator_type, + detail::preferred_iterator_type> { + public: + typedef detail::basic_range, + detail::preferred_iterator_type, + detail::preferred_iterator_type + > super; + + template + slice_range(R &&r, typename super::size_type i, + typename super::size_type j) : + o(std::forward(r)), i(i), j(j) { + } + + bool + operator==(const slice_range &r) const { + return o == r.o && i == r.i && j == r.j; + } + + typename super::iterator + begin() { + return std::next(o.begin(), i); + } + + typename super::iterator + end() { + return std::next(o.begin(), j); + } + + typename super::const_iterator + begin() const { + return std::next(o.begin(), i); + } + + typename super::const_iterator + end() const { + return std::next(o.begin(), j); + } + + typename super::size_type + size() const { + return j - i; + } + + private: + O o; + typename super::size_type i, j; + }; + + /// + /// Create a range from an iterator pair (\a i, \a j). + /// + /// \sa iterator_range. + /// + template + iterator_range + range(T i, T j) { + return { i, j }; + } + + /// + /// Create a range of \a n elements starting from iterator \a i. + /// + /// \sa iterator_range. + /// + template + iterator_range + range(T i, typename std::iterator_traits::difference_type n) { + return { i, i + n }; + } + + /// + /// Create a range by transforming the contents of a number of + /// source ranges \a rs element-wise using a provided functor \a f. + /// + /// \sa adaptor_range. + /// + template + adaptor_range + map(F &&f, Rs &&... rs) { + return { std::forward(f), std::forward(rs)... }; + } + + /// + /// Create a range identical to another range \a r. + /// + template + adaptor_range + range(R &&r) { + return { identity(), std::forward(r) }; + } + + /// + /// Create a range by taking the elements delimited by the index + /// pair (\a i, \a j) in a source range \a r. + /// + /// \sa slice_range. + /// + template + slice_range + slice(R &&r, typename slice_range::size_type i, + typename slice_range::size_type j) { + return { std::forward(r), i, j }; + } + + /// + /// Range that behaves as a vector of references of type \a T. + /// + /// Useful because STL containers cannot contain references to + /// objects as elements. + /// + template + class ref_vector : public adaptor_range> { + public: + ref_vector(std::initializer_list> il) : + adaptor_range>(derefs(), map(addresses(), il)) { + } + + template + ref_vector(R &&r) : adaptor_range>( + derefs(), map(addresses(), std::forward(r))) { + } + }; +} + +#endif diff --git a/src/gallium/state_trackers/clover/util/tuple.hpp b/src/gallium/state_trackers/clover/util/tuple.hpp new file mode 100644 index 00000000000..bd49684a314 --- /dev/null +++ b/src/gallium/state_trackers/clover/util/tuple.hpp @@ -0,0 +1,117 @@ +// +// Copyright 2013 Francisco Jerez +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +#ifndef CLOVER_UTIL_TUPLE_HPP +#define CLOVER_UTIL_TUPLE_HPP + +#include + +namespace clover { + namespace tuple { + /// + /// Static sequence of integers. + /// + template + struct integral_sequence; + + /// + /// Static sequence containing all integers from 0 to N-1. + /// + template + struct enumerate { + typedef typename enumerate::type + type; + }; + + template + struct enumerate<0, Is...> { + typedef integral_sequence type; + }; + + namespace detail { + template::type>::value + >::type> + struct _apply; + + template + struct _apply> { + typedef typename std::remove_reference::type func_type; + typedef decltype( + std::declval()(std::get(std::declval())...) + ) value_type; + + static value_type + eval(F &&f, T &&t) { + return f(std::get(std::forward(t))...); + } + }; + } + + /// + /// Evaluate function \a f with the elements of tuple \a t + /// expanded as arguments. + /// + template + typename detail::_apply::value_type + apply(F &&f, T &&t) { + return detail::_apply::eval(std::forward(f), + std::forward(t)); + } + + namespace detail { + template::type>::value + >::type> + struct _map; + + template + struct _map> { + typedef typename std::remove_reference::type func_type; + typedef std::tuple< + decltype(std::declval()( + std::get(std::declval())))... + > value_type; + + static value_type + eval(F &&f, T &&t) { + return value_type(f(std::get(std::forward(t)))...); + } + }; + } + + /// + /// Evaluate function \a f on each element of the tuple \a t and + /// return the resulting values as a new tuple. + /// + template + typename detail::_map::value_type + map(F &&f, T &&t) { + return detail::_map::eval(std::forward(f), + std::forward(t)); + } + } +} + +#endif -- 2.30.2