From f473e60d3ac02781caf75367f17844ecfbc4762c Mon Sep 17 00:00:00 2001
From: Yichao Yu <yyc1992@gmail.com>
Date: Thu, 22 May 2014 13:47:19 -0400
Subject: [PATCH] from_class/to_class

---
 src/c_wrapper/utils.h     |  64 +++++++++++-
 src/c_wrapper/wrap_cl.cpp | 209 ++++++++++++++++----------------------
 2 files changed, 148 insertions(+), 125 deletions(-)

diff --git a/src/c_wrapper/utils.h b/src/c_wrapper/utils.h
index 9ff7419d..a7f8ca38 100644
--- a/src/c_wrapper/utils.h
+++ b/src/c_wrapper/utils.h
@@ -52,6 +52,11 @@ public:
     {
         return this->get()[i];
     }
+    inline const T&
+    operator[](int i) const
+    {
+        return this->get()[i];
+    }
     inline void
     resize(size_t len)
     {
@@ -60,6 +65,59 @@ public:
         m_len = len;
         this->reset((T*)realloc((void*)this->release(), len * sizeof(T)));
     }
+    template<typename T2>
+    static pyopencl_buf<T>
+    from_class(const T2 *buf2, size_t len)
+    {
+        pyopencl_buf<T> buf(len);
+        for (size_t i = 0;i < len;i++) {
+            buf[i] = buf2[i]->data();
+        }
+        return buf;
+    }
+    template<typename T2>
+    static pyopencl_buf<T>
+    from_class(const void **buf2, size_t len)
+    {
+        return from_class<const T2*>(
+            reinterpret_cast<const T2 *const*>(buf2), len);
+    }
+    template<typename T2>
+    static pyopencl_buf<T>
+    from_class(const void *const *buf2, size_t len)
+    {
+        return from_class<const T2*>(
+            reinterpret_cast<const T2 *const*>(buf2), len);
+    }
+    template<typename T2>
+    static pyopencl_buf<T>
+    from_class(const pyopencl_buf<T2> buf2)
+    {
+        return from_class(buf2.get(), buf2.len());
+    }
+    template<typename T2, typename... ArgTypes>
+    static pyopencl_buf<T2*>
+    _to_class(const T *buf2, size_t len, ArgTypes&&... args)
+    {
+        pyopencl_buf<T2*> buf(len);
+        for (size_t i = 0;i < len;i++) {
+            buf[i] = new T2(buf2[i], std::forward<ArgTypes>(args)...);
+        }
+        return buf;
+    }
+    template<typename T2, typename... ArgTypes>
+    static pyopencl_buf<T2*>
+    to_class(const T *buf2, size_t len, ArgTypes&&... args)
+    {
+        return _to_class<T2>(buf2, len, std::forward<ArgTypes>(args)...);
+    }
+    template<typename T2, typename... ArgTypes>
+    pyopencl_buf<T2*>
+    to_class(ArgTypes... args)
+    {
+        return _to_class<T2>(this->get(), m_len,
+                             std::forward<ArgTypes>(args)...);
+    }
 };
 
 template<>
@@ -157,15 +215,11 @@ template<typename T, typename Cls>
 static inline generic_info
 convert_opaque_array_info(pyopencl_buf<T> &buf)
 {
-    pyopencl_buf<void*> ar(buf.len());
-    for (unsigned i = 0;i < buf.len();i++) {
-        ar[i] = new Cls(buf[i]);
-    }
     generic_info info;
     info.dontfree = 0;
     info.opaque_class = Cls::get_class_t();
     info.type = _copy_str(std::string("void*[") + tostring(buf.len()) + "]");
-    info.value = ar.release();
+    info.value = buf.template to_class<Cls>().release();
     return info;
 }
 
diff --git a/src/c_wrapper/wrap_cl.cpp b/src/c_wrapper/wrap_cl.cpp
index cad05c7e..81fa855e 100644
--- a/src/c_wrapper/wrap_cl.cpp
+++ b/src/c_wrapper/wrap_cl.cpp
@@ -28,24 +28,6 @@
 // }}}
 
 
-// {{{ event helpers
-
-#define PYOPENCL_PARSE_OBJECT_LIST(CLS, TYPE, OUT, NAME, NUM)   \
-  std::vector<TYPE> OUT((NUM));                                 \
-  {                                                             \
-    for(unsigned i = 0; i < (NUM); ++i) {                       \
-      OUT[i] = static_cast<pyopencl::CLS*>(NAME[i])->data();    \
-    }                                                           \
-  }
-
-#define PYOPENCL_PARSE_WAIT_FOR PYOPENCL_PARSE_OBJECT_LIST(event, cl_event, event_wait_list, wait_for, num_wait_for)
-
-#define PYOPENCL_WAITLIST_ARGS                                          \
-  num_wait_for, event_wait_list.empty( ) ? NULL : &event_wait_list.front()
-
-// }}}
-
-
 // {{{ equality testing
 
 #define PYOPENCL_EQUALITY_TESTS(cls) \
@@ -1243,13 +1225,14 @@ enqueue_read_image(command_queue &cq, image &img, size_t *origin,
                    size_t slice_pitch, void **wait_for, uint32_t num_wait_for,
                    bool is_blocking)
 {
-    PYOPENCL_PARSE_WAIT_FOR;
+    auto _wait_for =
+        pyopencl_buf<cl_event>::from_class<event>(wait_for, num_wait_for);
     cl_event evt;
     retry_mem_error<void>([&] {
             pyopencl_call_guarded(clEnqueueReadImage, cq.data(), img.data(),
                                   cast_bool(is_blocking), origin, region,
                                   row_pitch, slice_pitch, buffer,
-                                  PYOPENCL_WAITLIST_ARGS, &evt);
+                                  num_wait_for, _wait_for.get(), &evt);
         });
     return new_event(evt);
     //PYOPENCL_RETURN_NEW_NANNY_EVENT(evt, buffer);
@@ -1540,10 +1523,6 @@ enqueue_read_image(command_queue &cq, image &img, size_t *origin,
                             "invalid dimension");
   }
 
-
-
-
-
   // TODO:
   // inline
   // py::tuple get_gl_object_info(memory_object_holder const &mem)
@@ -1554,27 +1533,29 @@ enqueue_read_image(command_queue &cq, image &img, size_t *origin,
   //   return py::make_tuple(otype, gl_name);
   // }
 
-#define WRAP_GL_ENQUEUE(what, What)                                     \
-  inline                                                                \
-  event *enqueue_##what##_gl_objects(command_queue &cq,                 \
-                                     void **ptr_mem_objects,            \
-                                     uint32_t num_mem_objects,          \
-                                     void **wait_for,                   \
-                                     uint32_t num_wait_for)             \
-  {                                                                     \
-    PYOPENCL_PARSE_WAIT_FOR;                                            \
-    PYOPENCL_PARSE_OBJECT_LIST(memory_object_holder, cl_mem, mem_objects, ptr_mem_objects, num_mem_objects); \
-    cl_event evt;                                                       \
-    pyopencl_call_guarded(clEnqueue##What##GLObjects, cq.data(),        \
-                          mem_objects.size(),                           \
-                          mem_objects.empty( ) ? NULL : &mem_objects.front(), \
-                          PYOPENCL_WAITLIST_ARGS, &evt);                \
-                                                                        \
-    return pyopencl::new_event(evt);                                    \
-  }
+typedef cl_int (*clEnqueueGLObjectFunc)(cl_command_queue, cl_uint,
+                                        const cl_mem*, cl_uint,
+                                        const cl_event*, cl_event*);
+
+static inline event*
+enqueue_gl_objects(clEnqueueGLObjectFunc func, const char *name,
+                   command_queue &cq, void **mem_objects,
+                   uint32_t num_mem_objects, void **wait_for,
+                   uint32_t num_wait_for)
+{
+    auto _wait_for =
+        pyopencl_buf<cl_event>::from_class<event>(wait_for, num_wait_for);
+    auto _mem_objs = pyopencl_buf<cl_mem>::from_class<memory_object_holder>(
+        mem_objects, num_mem_objects);
+    cl_event evt;
+    call_guarded(func, name, cq.data(), num_mem_objects, _mem_objs.get(),
+                 num_wait_for, _wait_for.get(), &evt);
+    return new_event(evt);
+}
+#define enqueue_gl_objects(what, args...)                       \
+    enqueue_gl_objects(clEnqueue##what##GLObjects,              \
+                       "clEnqueue" #what "GLObjects", args)
 
-  WRAP_GL_ENQUEUE(acquire, Acquire);
-  WRAP_GL_ENQUEUE(release, Release);
 #endif
 
 
@@ -1930,17 +1911,16 @@ public:
         }
       }
 
-      void build(const char *options, cl_uint num_devices, void **ptr_devices)
+      void
+      build(const char *options, cl_uint num_devices, void **ptr_devices)
       {
-        // todo: this function should get a list of device instances, not raw pointers
-        // pointers are for the cffi interface and should not be here
-        std::vector<cl_device_id> devices(num_devices);
-        for(cl_uint i = 0; i < num_devices; ++i) {
-          devices[i] = static_cast<device*>(ptr_devices[i])->data();
-        }
-        pyopencl_call_guarded(clBuildProgram, m_program, num_devices,
-                              devices.empty() ? NULL : &devices.front(),
-                              options, NULL, NULL);
+          // todo: this function should get a list of device instances,
+          // not raw pointers pointers are for the cffi interface and
+          // should not be here
+          auto devices = pyopencl_buf<cl_device_id>::from_class<device>(
+              ptr_devices, num_devices);
+          pyopencl_call_guarded(clBuildProgram, m_program, num_devices,
+                                devices.get(), options, NULL, NULL);
       }
 
       // #if PYOPENCL_CL_VERSION >= 0x1020
@@ -2225,32 +2205,26 @@ enqueue_read_buffer(command_queue &cq, memory_object_holder &mem, void *buffer,
                     size_t size, size_t device_offset, void **wait_for,
                     uint32_t num_wait_for, bool is_blocking)
 {
-    PYOPENCL_PARSE_WAIT_FOR;
-
+    auto _wait_for =
+        pyopencl_buf<cl_event>::from_class<event>(wait_for, num_wait_for);
     cl_event evt;
     retry_mem_error<void>([&] {
             pyopencl_call_guarded(clEnqueueReadBuffer, cq.data(), mem.data(),
                                   cast_bool(is_blocking), device_offset, size,
-                                  buffer, PYOPENCL_WAITLIST_ARGS, &evt);
+                                  buffer, num_wait_for, _wait_for.get(), &evt);
         });
     return new_event(evt);
 }
 
 
 
-  inline
-  event *enqueue_copy_buffer(command_queue &cq,
-                             memory_object_holder &src,
-                             memory_object_holder &dst,
-                             ptrdiff_t byte_count,
-                             size_t src_offset,
-                             size_t dst_offset,
-                             void **wait_for, uint32_t num_wait_for
-                             )
-  {
-    PYOPENCL_PARSE_WAIT_FOR;
-    if (byte_count < 0)
-      {
+inline event*
+enqueue_copy_buffer(command_queue &cq, memory_object_holder &src,
+                    memory_object_holder &dst, ptrdiff_t byte_count,
+                    size_t src_offset, size_t dst_offset,
+                    void **wait_for, uint32_t num_wait_for)
+{
+    if (byte_count < 0) {
         size_t byte_count_src = 0;
         size_t byte_count_dst = 0;
         pyopencl_call_guarded(clGetMemObjectInfo, src.data(), CL_MEM_SIZE,
@@ -2258,29 +2232,32 @@ enqueue_read_buffer(command_queue &cq, memory_object_holder &mem, void *buffer,
         pyopencl_call_guarded(clGetMemObjectInfo, src.data(), CL_MEM_SIZE,
                               sizeof(byte_count), &byte_count_dst, NULL);
         byte_count = std::min(byte_count_src, byte_count_dst);
-      }
-
+    }
+    auto _wait_for =
+        pyopencl_buf<cl_event>::from_class<event>(wait_for, num_wait_for);
     cl_event evt;
     retry_mem_error<void>([&] {
             pyopencl_call_guarded(clEnqueueCopyBuffer, cq.data(), src.data(),
                                   dst.data(), src_offset, dst_offset,
-                                  byte_count, PYOPENCL_WAITLIST_ARGS, &evt);
+                                  byte_count, num_wait_for,
+                                  _wait_for.get(), &evt);
         });
     return new_event(evt);
-  }
+}
 
 inline event*
 enqueue_write_buffer(command_queue &cq,memory_object_holder &mem,
                      const void *buffer, size_t size, size_t device_offset,
                      void **wait_for, uint32_t num_wait_for, bool is_blocking)
 {
-    PYOPENCL_PARSE_WAIT_FOR;
-
+    auto _wait_for =
+        pyopencl_buf<cl_event>::from_class<event>(wait_for, num_wait_for);
     cl_event evt;
     retry_mem_error<void>([&] {
             pyopencl_call_guarded(clEnqueueWriteBuffer, cq.data(), mem.data(),
                                   cast_bool(is_blocking), device_offset,
-                                  size, buffer, PYOPENCL_WAITLIST_ARGS, &evt);
+                                  size, buffer, num_wait_for,
+                                  _wait_for.get(), &evt);
         });
     return new_event(evt);
     //PYOPENCL_RETURN_NEW_NANNY_EVENT(evt, buffer);
@@ -2295,44 +2272,42 @@ enqueue_nd_range_kernel(command_queue &cq, kernel &knl, cl_uint work_dim,
                         const size_t *local_work_size,
                         void **wait_for, uint32_t num_wait_for)
 {
-    PYOPENCL_PARSE_WAIT_FOR;
-
+    auto _wait_for =
+        pyopencl_buf<cl_event>::from_class<event>(wait_for, num_wait_for);
     cl_event evt;
     retry_mem_error<void>([&] {
             pyopencl_call_guarded(clEnqueueNDRangeKernel, cq.data(),
                                   knl.data(), work_dim, global_work_offset,
                                   global_work_size, local_work_size,
-                                  PYOPENCL_WAITLIST_ARGS, &evt);
+                                  num_wait_for, _wait_for.get(), &evt);
         });
     return new_event(evt);
 }
 
 #if PYOPENCL_CL_VERSION >= 0x1020
-  inline
-  event *enqueue_marker_with_wait_list(command_queue &cq,
-    void **wait_for, uint32_t num_wait_for)
-  {
-    PYOPENCL_PARSE_WAIT_FOR;
+inline event*
+enqueue_marker_with_wait_list(command_queue &cq, void **wait_for,
+                              uint32_t num_wait_for)
+{
+    auto _wait_for =
+        pyopencl_buf<cl_event>::from_class<event>(wait_for, num_wait_for);
     cl_event evt;
-
     pyopencl_call_guarded(clEnqueueMarkerWithWaitList, cq.data(),
-                          PYOPENCL_WAITLIST_ARGS, &evt);
-
+                          num_wait_for, _wait_for.get(), &evt);
     return new_event(evt);
-  }
+}
 
-  inline
-  event *enqueue_barrier_with_wait_list(command_queue &cq,
-    void **wait_for, uint32_t num_wait_for)
-  {
-    PYOPENCL_PARSE_WAIT_FOR;
+inline event*
+enqueue_barrier_with_wait_list(command_queue &cq, void **wait_for,
+                               uint32_t num_wait_for)
+{
+    auto _wait_for =
+        pyopencl_buf<cl_event>::from_class<event>(wait_for, num_wait_for);
     cl_event evt;
-
     pyopencl_call_guarded(clEnqueueBarrierWithWaitList, cq.data(),
-                          PYOPENCL_WAITLIST_ARGS, &evt);
-
+                          num_wait_for, _wait_for.get(), &evt);
     return new_event(evt);
-  }
+}
 #endif
 
 inline event*
@@ -2360,8 +2335,9 @@ void pyopencl_free_pointer(void *p)
 
 void pyopencl_free_pointer_array(void **p, uint32_t size)
 {
-  for(uint32_t i = 0; i < size; ++i)
-    pyopencl_free_pointer(p[i]);
+    for (uint32_t i = 0;i < size;i++) {
+        pyopencl_free_pointer(p[i]);
+    }
 }
 
 void
@@ -2381,11 +2357,8 @@ get_platforms(void **ptr_platforms, uint32_t *num_platforms)
             pyopencl_buf<cl_platform_id> platforms(*num_platforms);
             pyopencl_call_guarded(clGetPlatformIDs, *num_platforms,
                                   platforms.get(), num_platforms);
-            pyopencl_buf<pyopencl::platform*> _ptr_platforms(*num_platforms);
-            for (size_t i = 0;i < platforms.len();i++) {
-                _ptr_platforms[i] = new pyopencl::platform(platforms[i]);
-            }
-            *ptr_platforms = _ptr_platforms.release();
+            *ptr_platforms =
+                platforms.template to_class<pyopencl::platform>().release();
         });
 }
 
@@ -2398,10 +2371,7 @@ platform__get_devices(void *ptr_platform, void **ptr_devices,
             auto devices = static_cast<pyopencl::platform*>(ptr_platform)
                 ->get_devices(devtype);
             *num_devices = devices.len();
-            pyopencl_buf<pyopencl::device*> _ptr_devices(*num_devices);
-            for(size_t i = 0; i < devices.len();i++) {
-                _ptr_devices[i] = new pyopencl::device(devices[i]);
-            }
+            auto _ptr_devices = devices.template to_class<pyopencl::device>();
             *ptr_devices = _ptr_devices.release();
         });
 }
@@ -2412,11 +2382,8 @@ _create_context(void **ptr_ctx, cl_context_properties *properties,
                 cl_uint num_devices, void **ptr_devices)
 {
     return pyopencl::c_handle_error([&] {
-            pyopencl_buf<cl_device_id> devices(num_devices);
-            for(size_t i = 0;i < num_devices;i++) {
-                devices[i] = static_cast<pyopencl::device*>(
-                    ptr_devices[i])->data();
-            }
+            auto devices = pyopencl_buf<cl_device_id>
+                ::from_class<pyopencl::device>(ptr_devices, num_devices);
             *ptr_ctx = new pyopencl::context(
                 pyopencl_call_guarded(clCreateContext, properties,
                                       num_devices, devices.get(),
@@ -2876,9 +2843,10 @@ error *_create_from_gl_renderbuffer(
     uint32_t num_wait_for)
 {
     return pyopencl::c_handle_error([&] {
-            *ptr_event = enqueue_acquire_gl_objects(
-                *static_cast<pyopencl::command_queue*>(ptr_command_queue),
-                ptr_mem_objects, num_mem_objects, wait_for, num_wait_for);
+            *ptr_event = enqueue_gl_objects(
+                Acquire, *static_cast<pyopencl::command_queue*>(
+                    ptr_command_queue), ptr_mem_objects, num_mem_objects,
+                wait_for, num_wait_for);
         });
 }
 
@@ -2888,9 +2856,10 @@ _enqueue_release_gl_objects(void **ptr_event, void *ptr_command_queue,
                             void **wait_for, uint32_t num_wait_for)
 {
     return pyopencl::c_handle_error([&] {
-            *ptr_event = enqueue_release_gl_objects(
-                *static_cast<pyopencl::command_queue*>(ptr_command_queue),
-                ptr_mem_objects, num_mem_objects, wait_for, num_wait_for);
+            *ptr_event = enqueue_gl_objects(
+                Release, *static_cast<pyopencl::command_queue*>(
+                    ptr_command_queue), ptr_mem_objects, num_mem_objects,
+                wait_for, num_wait_for);
         });
 }
 #endif /* HAVE_GL */
-- 
GitLab