base.hpp revision c6db1b3396384186aab5b685fe1fd540e17b3a62
1// 2// Copyright 2012 Francisco Jerez 3// 4// Permission is hereby granted, free of charge, to any person obtaining a 5// copy of this software and associated documentation files (the "Software"), 6// to deal in the Software without restriction, including without limitation 7// the rights to use, copy, modify, merge, publish, distribute, sublicense, 8// and/or sell copies of the Software, and to permit persons to whom the 9// Software is furnished to do so, subject to the following conditions: 10// 11// The above copyright notice and this permission notice shall be included in 12// all copies or substantial portions of the Software. 13// 14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17// THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 19// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20// SOFTWARE. 21// 22 23#ifndef __CORE_BASE_HPP__ 24#define __CORE_BASE_HPP__ 25 26#include <stdexcept> 27#include <atomic> 28#include <cassert> 29#include <tuple> 30#include <vector> 31#include <functional> 32 33#include "CL/cl.h" 34 35/// 36/// Main namespace of the CL state tracker. 37/// 38namespace clover { 39 /// 40 /// Class that represents an error that can be converted to an 41 /// OpenCL status code. 42 /// 43 class error : public std::runtime_error { 44 public: 45 error(cl_int code, std::string what = "") : 46 std::runtime_error(what), code(code) { 47 } 48 49 cl_int get() const { 50 return code; 51 } 52 53 protected: 54 cl_int code; 55 }; 56 57 /// 58 /// Base class for objects that support reference counting. 59 /// 60 class ref_counter { 61 public: 62 ref_counter() : __ref_count(1) {} 63 64 unsigned ref_count() { 65 return __ref_count; 66 } 67 68 void retain() { 69 __ref_count++; 70 } 71 72 bool release() { 73 return (--__ref_count) == 0; 74 } 75 76 private: 77 std::atomic<unsigned> __ref_count; 78 }; 79 80 /// 81 /// Intrusive smart pointer for objects that implement the 82 /// clover::ref_counter interface. 83 /// 84 template<typename T> 85 class ref_ptr { 86 public: 87 ref_ptr(T *q = NULL) : p(NULL) { 88 reset(q); 89 } 90 91 template<typename S> 92 ref_ptr(const ref_ptr<S> &ref) : p(NULL) { 93 reset(ref.p); 94 } 95 96 ~ref_ptr() { 97 reset(NULL); 98 } 99 100 void reset(T *q = NULL) { 101 if (q) 102 q->retain(); 103 if (p && p->release()) 104 delete p; 105 p = q; 106 } 107 108 ref_ptr &operator=(const ref_ptr &ref) { 109 reset(ref.p); 110 return *this; 111 } 112 113 T *operator*() const { 114 return p; 115 } 116 117 T *operator->() const { 118 return p; 119 } 120 121 operator bool() const { 122 return p; 123 } 124 125 private: 126 T *p; 127 }; 128 129 /// 130 /// Transfer the caller's ownership of a reference-counted object 131 /// to a clover::ref_ptr smart pointer. 132 /// 133 template<typename T> 134 inline ref_ptr<T> 135 transfer(T *p) { 136 ref_ptr<T> ref { p }; 137 p->release(); 138 return ref; 139 } 140 141 template<typename T, typename S, int N> 142 struct __iter_helper { 143 template<typename F, typename Its, typename... Args> 144 static T 145 step(F op, S state, Its its, Args... args) { 146 return __iter_helper<T, S, N - 1>::step( 147 op, state, its, *(std::get<N>(its)++), args...); 148 } 149 }; 150 151 template<typename T, typename S> 152 struct __iter_helper<T, S, 0> { 153 template<typename F, typename Its, typename... Args> 154 static T 155 step(F op, S state, Its its, Args... args) { 156 return op(state, *(std::get<0>(its)++), args...); 157 } 158 }; 159 160 struct __empty {}; 161 162 template<typename T> 163 struct __iter_helper<T, __empty, 0> { 164 template<typename F, typename Its, typename... Args> 165 static T 166 step(F op, __empty state, Its its, Args... args) { 167 return op(*(std::get<0>(its)++), args...); 168 } 169 }; 170 171 template<typename F, typename... Its> 172 struct __result_helper { 173 typedef typename std::remove_const< 174 typename std::result_of< 175 F (typename std::iterator_traits<Its>::value_type...) 176 >::type 177 >::type type; 178 }; 179 180 /// 181 /// Iterate \a op on the result of zipping all the specified 182 /// iterators together. 183 /// 184 /// Similar to std::for_each, but it accepts functions of an 185 /// arbitrary number of arguments. 186 /// 187 template<typename F, typename It0, typename... Its> 188 F 189 for_each(F op, It0 it0, It0 end0, Its... its) { 190 while (it0 != end0) 191 __iter_helper<void, __empty, sizeof...(Its)>::step( 192 op, {}, std::tie(it0, its...)); 193 194 return op; 195 } 196 197 /// 198 /// Iterate \a op on the result of zipping all the specified 199 /// iterators together, storing return values in a new container. 200 /// 201 /// Similar to std::transform, but it accepts functions of an 202 /// arbitrary number of arguments and it doesn't have to be 203 /// provided with an output iterator. 204 /// 205 template<typename F, typename It0, typename... Its, 206 typename C = std::vector< 207 typename __result_helper<F, It0, Its...>::type>> 208 C 209 map(F op, It0 it0, It0 end0, Its... its) { 210 C c; 211 212 while (it0 != end0) 213 c.push_back( 214 __iter_helper<typename C::value_type, __empty, sizeof...(Its)> 215 ::step(op, {}, std::tie(it0, its...))); 216 217 return c; 218 } 219 220 /// 221 /// Reduce the result of zipping all the specified iterators 222 /// together, using iterative application of \a op from left to 223 /// right. 224 /// 225 /// Similar to std::accumulate, but it accepts functions of an 226 /// arbitrary number of arguments. 227 /// 228 template<typename F, typename T, typename It0, typename... Its> 229 T 230 fold(F op, T a, It0 it0, It0 end0, Its... its) { 231 while (it0 != end0) 232 a = __iter_helper<T, T, sizeof...(Its)>::step( 233 op, a, std::tie(it0, its...)); 234 235 return a; 236 } 237 238 /// 239 /// Iterate \a op on the result of zipping the specified iterators 240 /// together, checking if any of the evaluations returns \a true. 241 /// 242 /// Similar to std::any_of, but it accepts functions of an 243 /// arbitrary number of arguments. 244 /// 245 template<typename F, typename It0, typename... Its> 246 bool 247 any_of(F op, It0 it0, It0 end0, Its... its) { 248 while (it0 != end0) 249 if (__iter_helper<bool, __empty, sizeof...(Its)>::step( 250 op, {}, std::tie(it0, its...))) 251 return true; 252 253 return false; 254 } 255 256 template<typename T, typename S> 257 T 258 keys(const std::pair<T, S> &ent) { 259 return ent.first; 260 } 261 262 template<typename T, typename S> 263 std::function<bool (const std::pair<T, S> &)> 264 key_equals(const T &x) { 265 return [=](const std::pair<T, S> &ent) { 266 return ent.first == x; 267 }; 268 } 269 270 template<typename T, typename S> 271 S 272 values(const std::pair<T, S> &ent) { 273 return ent.second; 274 } 275 276 template<typename T> 277 std::function<bool (const T &)> 278 is_zero() { 279 return [](const T &x) { 280 return x == 0; 281 }; 282 } 283} 284 285#endif 286