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 /// 38 namespace 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: error(cl_int code,std::string what="")45 error(cl_int code, std::string what = "") : 46 std::runtime_error(what), code(code) { 47 } 48 get() const49 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: ref_counter()62 ref_counter() : __ref_count(1) {} 63 ref_count()64 unsigned ref_count() { 65 return __ref_count; 66 } 67 retain()68 void retain() { 69 __ref_count++; 70 } 71 release()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: ref_ptr(T * q=NULL)87 ref_ptr(T *q = NULL) : p(NULL) { 88 reset(q); 89 } 90 ref_ptr(const ref_ptr<T> & ref)91 ref_ptr(const ref_ptr<T> &ref) : p(NULL) { 92 reset(ref.p); 93 } 94 ~ref_ptr()95 ~ref_ptr() { 96 reset(NULL); 97 } 98 reset(T * q=NULL)99 void reset(T *q = NULL) { 100 if (q) 101 q->retain(); 102 if (p && p->release()) 103 delete p; 104 p = q; 105 } 106 operator =(const ref_ptr & ref)107 ref_ptr &operator=(const ref_ptr &ref) { 108 reset(ref.p); 109 return *this; 110 } 111 operator *() const112 T *operator*() const { 113 return p; 114 } 115 operator ->() const116 T *operator->() const { 117 return p; 118 } 119 operator bool() const120 operator bool() const { 121 return p; 122 } 123 124 private: 125 T *p; 126 }; 127 128 /// 129 /// Transfer the caller's ownership of a reference-counted object 130 /// to a clover::ref_ptr smart pointer. 131 /// 132 template<typename T> 133 inline ref_ptr<T> transfer(T * p)134 transfer(T *p) { 135 ref_ptr<T> ref { p }; 136 p->release(); 137 return ref; 138 } 139 140 template<typename T, typename S, int N> 141 struct __iter_helper { 142 template<typename F, typename Its, typename... Args> 143 static T stepclover::__iter_helper144 step(F op, S state, Its its, Args... args) { 145 return __iter_helper<T, S, N - 1>::step( 146 op, state, its, *(std::get<N>(its)++), args...); 147 } 148 }; 149 150 template<typename T, typename S> 151 struct __iter_helper<T, S, 0> { 152 template<typename F, typename Its, typename... Args> 153 static T stepclover::__iter_helper154 step(F op, S state, Its its, Args... args) { 155 return op(state, *(std::get<0>(its)++), args...); 156 } 157 }; 158 159 struct __empty {}; 160 161 template<typename T> 162 struct __iter_helper<T, __empty, 0> { 163 template<typename F, typename Its, typename... Args> 164 static T stepclover::__iter_helper165 step(F op, __empty state, Its its, Args... args) { 166 return op(*(std::get<0>(its)++), args...); 167 } 168 }; 169 170 template<typename F, typename... Its> 171 struct __result_helper { 172 typedef typename std::remove_const< 173 typename std::result_of< 174 F (typename std::iterator_traits<Its>::value_type...) 175 >::type 176 >::type type; 177 }; 178 179 /// 180 /// Iterate \a op on the result of zipping all the specified 181 /// iterators together. 182 /// 183 /// Similar to std::for_each, but it accepts functions of an 184 /// arbitrary number of arguments. 185 /// 186 template<typename F, typename It0, typename... Its> 187 F for_each(F op,It0 it0,It0 end0,Its...its)188 for_each(F op, It0 it0, It0 end0, Its... its) { 189 while (it0 != end0) 190 __iter_helper<void, __empty, sizeof...(Its)>::step( 191 op, {}, std::tie(it0, its...)); 192 193 return op; 194 } 195 196 /// 197 /// Iterate \a op on the result of zipping all the specified 198 /// iterators together, storing return values in a new container. 199 /// 200 /// Similar to std::transform, but it accepts functions of an 201 /// arbitrary number of arguments and it doesn't have to be 202 /// provided with an output iterator. 203 /// 204 template<typename F, typename It0, typename... Its, 205 typename C = std::vector< 206 typename __result_helper<F, It0, Its...>::type>> 207 C map(F op,It0 it0,It0 end0,Its...its)208 map(F op, It0 it0, It0 end0, Its... its) { 209 C c; 210 211 while (it0 != end0) 212 c.push_back( 213 __iter_helper<typename C::value_type, __empty, sizeof...(Its)> 214 ::step(op, {}, std::tie(it0, its...))); 215 216 return c; 217 } 218 219 /// 220 /// Reduce the result of zipping all the specified iterators 221 /// together, using iterative application of \a op from left to 222 /// right. 223 /// 224 /// Similar to std::accumulate, but it accepts functions of an 225 /// arbitrary number of arguments. 226 /// 227 template<typename F, typename T, typename It0, typename... Its> 228 T fold(F op,T a,It0 it0,It0 end0,Its...its)229 fold(F op, T a, It0 it0, It0 end0, Its... its) { 230 while (it0 != end0) 231 a = __iter_helper<T, T, sizeof...(Its)>::step( 232 op, a, std::tie(it0, its...)); 233 234 return a; 235 } 236 237 /// 238 /// Iterate \a op on the result of zipping the specified iterators 239 /// together, checking if any of the evaluations returns \a true. 240 /// 241 /// Similar to std::any_of, but it accepts functions of an 242 /// arbitrary number of arguments. 243 /// 244 template<typename F, typename It0, typename... Its> 245 bool any_of(F op,It0 it0,It0 end0,Its...its)246 any_of(F op, It0 it0, It0 end0, Its... its) { 247 while (it0 != end0) 248 if (__iter_helper<bool, __empty, sizeof...(Its)>::step( 249 op, {}, std::tie(it0, its...))) 250 return true; 251 252 return false; 253 } 254 255 template<typename T, typename S> 256 T keys(const std::pair<T,S> & ent)257 keys(const std::pair<T, S> &ent) { 258 return ent.first; 259 } 260 261 template<typename T, typename S> 262 std::function<bool (const std::pair<T, S> &)> key_equals(const T & x)263 key_equals(const T &x) { 264 return [=](const std::pair<T, S> &ent) { 265 return ent.first == x; 266 }; 267 } 268 269 template<typename T, typename S> 270 S values(const std::pair<T,S> & ent)271 values(const std::pair<T, S> &ent) { 272 return ent.second; 273 } 274 275 template<typename T> 276 std::function<bool (const T &)> is_zero()277 is_zero() { 278 return [](const T &x) { 279 return x == 0; 280 }; 281 } 282 } 283 284 #endif 285