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