0,0 → 1,282 |
// |
// 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 __CORE_BASE_HPP__ |
#define __CORE_BASE_HPP__ |
|
#include <stdexcept> |
#include <atomic> |
#include <cassert> |
#include <tuple> |
#include <vector> |
#include <functional> |
|
#include "CL/cl.h" |
|
/// |
/// Main namespace of the CL state tracker. |
/// |
namespace clover { |
/// |
/// Class that represents an error that can be converted to an |
/// OpenCL status code. |
/// |
class error : public std::runtime_error { |
public: |
error(cl_int code, std::string what = "") : |
std::runtime_error(what), code(code) { |
} |
|
cl_int get() const { |
return code; |
} |
|
protected: |
cl_int code; |
}; |
|
/// |
/// 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<unsigned> __ref_count; |
}; |
|
/// |
/// Intrusive smart pointer for objects that implement the |
/// clover::ref_counter interface. |
/// |
template<typename T> |
class ref_ptr { |
public: |
ref_ptr(T *q = NULL) : p(NULL) { |
reset(q); |
} |
|
ref_ptr(const ref_ptr<T> &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; |
} |
|
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<typename T> |
inline ref_ptr<T> |
transfer(T *p) { |
ref_ptr<T> ref { p }; |
p->release(); |
return ref; |
} |
|
template<typename T, typename S, int N> |
struct __iter_helper { |
template<typename F, typename Its, typename... Args> |
static T |
step(F op, S state, Its its, Args... args) { |
return __iter_helper<T, S, N - 1>::step( |
op, state, its, *(std::get<N>(its)++), args...); |
} |
}; |
|
template<typename T, typename S> |
struct __iter_helper<T, S, 0> { |
template<typename F, typename Its, typename... Args> |
static T |
step(F op, S state, Its its, Args... args) { |
return op(state, *(std::get<0>(its)++), args...); |
} |
}; |
|
struct __empty {}; |
|
template<typename T> |
struct __iter_helper<T, __empty, 0> { |
template<typename F, typename Its, typename... Args> |
static T |
step(F op, __empty state, Its its, Args... args) { |
return op(*(std::get<0>(its)++), args...); |
} |
}; |
|
template<typename F, typename... Its> |
struct __result_helper { |
typedef typename std::remove_const< |
typename std::result_of< |
F (typename std::iterator_traits<Its>::value_type...) |
>::type |
>::type type; |
}; |
|
/// |
/// Iterate \a op on the result of zipping all the specified |
/// iterators together. |
/// |
/// Similar to std::for_each, but it accepts functions of an |
/// arbitrary number of arguments. |
/// |
template<typename F, typename It0, typename... Its> |
F |
for_each(F op, It0 it0, It0 end0, Its... its) { |
while (it0 != end0) |
__iter_helper<void, __empty, sizeof...(Its)>::step( |
op, {}, std::tie(it0, its...)); |
|
return op; |
} |
|
/// |
/// Iterate \a op on the result of zipping all the specified |
/// iterators together, storing return values in a new container. |
/// |
/// Similar to std::transform, but it accepts functions of an |
/// arbitrary number of arguments and it doesn't have to be |
/// provided with an output iterator. |
/// |
template<typename F, typename It0, typename... Its, |
typename C = std::vector< |
typename __result_helper<F, It0, Its...>::type>> |
C |
map(F op, It0 it0, It0 end0, Its... its) { |
C c; |
|
while (it0 != end0) |
c.push_back( |
__iter_helper<typename C::value_type, __empty, sizeof...(Its)> |
::step(op, {}, std::tie(it0, its...))); |
|
return c; |
} |
|
/// |
/// Reduce the result of zipping all the specified iterators |
/// together, using iterative application of \a op from left to |
/// right. |
/// |
/// Similar to std::accumulate, but it accepts functions of an |
/// arbitrary number of arguments. |
/// |
template<typename F, typename T, typename It0, typename... Its> |
T |
fold(F op, T a, It0 it0, It0 end0, Its... its) { |
while (it0 != end0) |
a = __iter_helper<T, T, sizeof...(Its)>::step( |
op, a, std::tie(it0, its...)); |
|
return a; |
} |
|
/// |
/// Iterate \a op on the result of zipping the specified iterators |
/// together, checking if any of the evaluations returns \a true. |
/// |
/// Similar to std::any_of, but it accepts functions of an |
/// arbitrary number of arguments. |
/// |
template<typename F, typename It0, typename... Its> |
bool |
any_of(F op, It0 it0, It0 end0, Its... its) { |
while (it0 != end0) |
if (__iter_helper<bool, __empty, sizeof...(Its)>::step( |
op, {}, std::tie(it0, its...))) |
return true; |
|
return false; |
} |
|
template<typename T, typename S> |
T |
keys(const std::pair<T, S> &ent) { |
return ent.first; |
} |
|
template<typename T, typename S> |
std::function<bool (const std::pair<T, S> &)> |
key_equals(const T &x) { |
return [=](const std::pair<T, S> &ent) { |
return ent.first == x; |
}; |
} |
|
template<typename T, typename S> |
S |
values(const std::pair<T, S> &ent) { |
return ent.second; |
} |
|
template<typename T> |
bool |
is_zero(T x) { |
return x == 0; |
} |
} |
|
#endif |