Home | History | Annotate | Download | only in core
      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:
     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       ref_ptr(const ref_ptr<T> &ref) : p(NULL) {
     92          reset(ref.p);
     93       }
     94 
     95       ~ref_ptr() {
     96          reset(NULL);
     97       }
     98 
     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 
    107       ref_ptr &operator=(const ref_ptr &ref) {
    108          reset(ref.p);
    109          return *this;
    110       }
    111 
    112       T *operator*() const {
    113          return p;
    114       }
    115 
    116       T *operator->() const {
    117          return p;
    118       }
    119 
    120       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>
    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
    144       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
    154       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
    165       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
    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
    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
    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
    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
    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> &)>
    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
    271    values(const std::pair<T, S> &ent) {
    272       return ent.second;
    273    }
    274 
    275    template<typename T>
    276    std::function<bool (const T &)>
    277    is_zero() {
    278       return [](const T &x) {
    279          return x == 0;
    280       };
    281    }
    282 }
    283 
    284 #endif
    285