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