From 1ce4b472f0a7a9612df5f11d713aff04cb6d022b Mon Sep 17 00:00:00 2001
From: Marko Bencun <mbencun@gmail.com>
Date: Tue, 3 Sep 2013 04:15:43 +0200
Subject: [PATCH] generic info: opaque, opaque array, char array, ...

---
 pyopencl/cffi_cl.py          |  72 ++++++------
 src/c_wrapper/wrap_cl.cpp    | 214 ++++++++++++-----------------------
 src/c_wrapper/wrap_cl_core.h |  16 +--
 3 files changed, 114 insertions(+), 188 deletions(-)

diff --git a/pyopencl/cffi_cl.py b/pyopencl/cffi_cl.py
index f42b9329..451c71e5 100644
--- a/pyopencl/cffi_cl.py
+++ b/pyopencl/cffi_cl.py
@@ -328,24 +328,6 @@ class _Program(_Common):
         _handle_error(_lib.program__get_build_info(self.ptr, device.ptr, param, info))
         return _generic_info_to_python(info)
         
-
-    def get_info(self, param):
-        if param == program_info.DEVICES:
-            # todo: refactor, same code as in get_devices 
-            devices = _CArray(_ffi.new('void**'))
-            _handle_error(_lib.program__get_info__devices(self.ptr, devices.ptr, devices.size))
-            result = []
-            for i in xrange(devices.size[0]):
-                # TODO why is the cast needed? 
-                device_ptr = _ffi.cast('void**', devices.ptr[0])[i]
-                result.append(_create_instance(Device, device_ptr))
-            return result
-        elif param == program_info.BINARIES:
-            ptr_binaries = _CArrays(_ffi.new('char***'))
-            _handle_error(_lib.program__get_info__binaries(self.ptr, ptr_binaries.ptr, ptr_binaries.size))
-            return map(_ffi.string, ptr_binaries)
-        return super(_Program, self).get_info(param)
-        
 class Platform(_Common):
     _id = 'platform'
     # todo: __del__
@@ -358,35 +340,45 @@ class Platform(_Common):
             # TODO why is the cast needed? 
             device_ptr = _ffi.cast('void**', devices.ptr[0])[i]
             result.append(_create_instance(Device, device_ptr))
-        # TODO remove, should be done via get_info(PLATFORM)
-        for r in result:
-            r.__dict__["platform"] = self
         return result
 
 def _generic_info_to_python(info):
     type_ = _ffi.string(info.type)
+    value = _ffi.cast(type_, info.value)
+    if info.opaque_class != _lib.CLASS_NONE:
+        klass = {
+            _lib.CLASS_PLATFORM: Platform,
+            _lib.CLASS_DEVICE: Device,
+            _lib.CLASS_KERNEL: Kernel, 
+            _lib.CLASS_CONTEXT: Context,
+            _lib.CLASS_BUFFER: Buffer,
+            _lib.CLASS_PROGRAM: _Program, 
+            _lib.CLASS_EVENT: Event,
+            _lib.CLASS_COMMAND_QUEUE: CommandQueue
+            }[info.opaque_class]
+
+        def ci(ptr):
+            ins = _create_instance(klass, ptr)
+            if info.opaque_class == _lib.CLASS_PROGRAM: # HACK?
+                from . import Program
+                return Program(ins)
+            return ins
+            
+        if type_.endswith(']'):
+            ret = map(ci, value)
+            _lib._free(info.value)
+            return ret
+        else:
+            return ci(value)
     if type_ == 'char*':
-        ret = _ffi.string(_ffi.cast(type_, info.value))
+        ret = _ffi.string(value)
+    elif type_.startswith('char*['):
+        ret = map(_ffi.string, value)
+        _lib._free2(info.value, len(value))
     elif type_.endswith(']'):
-        ret = list(_ffi.cast(type_, info.value))
-    elif type_ == 'cl_platform_id':
-        return _create_instance(Platform, _ffi.cast('void *', info.value))
-    elif type_ == 'cl_device_id':
-        return _create_instance(Device, _ffi.cast('void *', info.value))
-    elif type_ == 'cl_kernel':
-        return _create_instance(Kernel, _ffi.cast('void *', info.value))
-    elif type_ == 'cl_context':
-        return _create_instance(Context, _ffi.cast('void *', info.value))
-    elif type_ == 'cl_buffer':
-        return _create_instance(Buffer, _ffi.cast('void *', info.value))
-    elif type_ == 'cl_program':
-        return _create_instance(Program, _ffi.cast('void *', info.value))
-    elif type_ == 'cl_event':
-        return _create_instance(Event, _ffi.cast('void *', info.value))
-    elif type_ == 'cl_command_queue':
-        return _create_instance(CommandQueue, _ffi.cast('void *', info.value))
+        ret = list(value)
     else:
-        ret = _ffi.cast('%s*' % type_, info.value)[0]
+        ret = value[0]
     _lib._free(info.value)
     return ret
 
diff --git a/src/c_wrapper/wrap_cl.cpp b/src/c_wrapper/wrap_cl.cpp
index 85118230..c3fdf08d 100644
--- a/src/c_wrapper/wrap_cl.cpp
+++ b/src/c_wrapper/wrap_cl.cpp
@@ -70,21 +70,36 @@
 			   RES_VEC.empty( ) ? NULL : &RES_VEC.front(), &size)); \
   }
 
-#define PYOPENCL_GET_OPAQUE_INFO(WHAT, FIRST_ARG, SECOND_ARG, CL_TYPE, TYPE) \
+#define PYOPENCL_GET_OPAQUE_INFO(WHAT, FIRST_ARG, SECOND_ARG, CL_TYPE, TYPE, TYPEU) \
   {									\
     CL_TYPE param_value;						\
     PYOPENCL_CALL_GUARDED(clGet##WHAT##Info,				\
 			  (FIRST_ARG, SECOND_ARG, sizeof(param_value), &param_value, 0)); \
     generic_info info;							\
-    info.type = #CL_TYPE;						\
-    if (param_value)							\
-      info.value = (void*)(new TYPE(param_value, /*retain*/ true));	\
-    else								\
-      info.value = NULL;						\
-    return info;							\
+    info.opaque_class = CLASS_##TYPEU;					\
+      info.type = "void *";						\
+      if (param_value)							\
+	info.value = (void*)(new TYPE(param_value, /*retain*/ true));	\
+      else								\
+	info.value = NULL;						\
+      return info;							\
   }
 
 
+#define PYOPENCL_GET_OPAQUE_ARRAY_INFO(TYPE, CLS, CLSU, VEC)		\
+  {									\
+    MALLOC(void*, ar, VEC.size());					\
+    for(uint32_t i = 0; i < VEC.size(); ++i) {				\
+      ar[i] = new pyopencl::CLS(VEC[i]);				\
+    }									\
+    generic_info info;							\
+    info.opaque_class = CLASS_##CLSU;					\
+    info.type = _copy_str(std::string("void*[") + tostring(VEC.size()) + "]"); \
+    info.value = (void**)ar;						\
+    return info;							\
+  }
+  
+
 #define PYOPENCL_GET_STR_INFO(WHAT, FIRST_ARG, SECOND_ARG)		\
   {									\
     size_t param_value_size;						\
@@ -96,7 +111,8 @@
 			  (FIRST_ARG, SECOND_ARG, param_value_size,	\
 			   param_value, &param_value_size));		\
     generic_info info;							\
-    info.type = "char*";				\
+    info.opaque_class = CLASS_NONE;					\
+    info.type = "char*";						\
     info.value = (void*)param_value;					\
     return info;							\
   }
@@ -107,7 +123,8 @@
     PYOPENCL_CALL_GUARDED(clGet##WHAT##Info,				\
 			  (FIRST_ARG, SECOND_ARG, sizeof(param_value), param_value, 0)); \
     generic_info info;							\
-    info.type = #TYPE;							\
+    info.opaque_class = CLASS_NONE;					\
+    info.type = #TYPE"*";						\
       info.value = (void*)param_value;					\
       return info;							\
   }
@@ -119,6 +136,7 @@
       ar[i] = VEC[i];							\
     }									\
     generic_info info;							\
+    info.opaque_class = CLASS_NONE;					\
     info.type = _copy_str(std::string(#TYPE"[") + tostring(VEC.size()) + "]"); \
     info.value = (void*)ar;						\
     return info;							\
@@ -225,9 +243,6 @@ run_python_gc(); \
 #define PYOPENCL_CL_BUFFER cl_mem
 #define PYOPENCL_CL_PROGRAM cl_program
 #define PYOPENCL_CL_EVENT cl_event
-  
-
-
 
 template<class T>
 std::string tostring(const T& v) {
@@ -508,7 +523,7 @@ namespace pyopencl
 	  PYOPENCL_GET_STR_INFO(Device, m_device, param_name);
 	  
 	case CL_DEVICE_PLATFORM:
-	  PYOPENCL_GET_OPAQUE_INFO(Device, m_device, param_name, cl_platform_id, platform);
+	  PYOPENCL_GET_OPAQUE_INFO(Device, m_device, param_name, cl_platform_id, platform, PLATFORM);
 
 	  // #if PYOPENCL_CL_VERSION >= 0x1010
 	  //           case CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF: DEV_GET_INT_INF(cl_uint);
@@ -538,7 +553,7 @@ namespace pyopencl
 	  // #endif
 	  // #if defined(cl_ext_device_fission) && defined(PYOPENCL_USE_DEVICE_FISSION)
 	  //           case CL_DEVICE_PARENT_DEVICE_EXT:
-	  //             PYOPENCL_GET_OPAQUE_INFO(Device, m_device, param_name, cl_device_id, device);
+	  //             PYOPENCL_GET_OPAQUE_INFO(Device, m_device, param_name, cl_device_id, device, DEVICE);
 	  //           case CL_DEVICE_PARTITION_TYPES_EXT:
 	  //           case CL_DEVICE_AFFINITY_DOMAINS_EXT:
 	  //           case CL_DEVICE_PARTITION_STYLE_EXT:
@@ -556,7 +571,7 @@ namespace pyopencl
 	  //           case CL_DEVICE_IMAGE_MAX_BUFFER_SIZE: DEV_GET_INT_INF(size_t);
 	  //           case CL_DEVICE_IMAGE_MAX_ARRAY_SIZE: DEV_GET_INT_INF(size_t);
 	  //           case CL_DEVICE_PARENT_DEVICE:
-	  //             PYOPENCL_GET_OPAQUE_INFO(Device, m_device, param_name, cl_device_id, device);
+	  //             PYOPENCL_GET_OPAQUE_INFO(Device, m_device, param_name, cl_device_id, device, DEVICE);
 	  //           case CL_DEVICE_PARTITION_MAX_SUB_DEVICES: DEV_GET_INT_INF(cl_uint);
 	  //           case CL_DEVICE_PARTITION_TYPE:
 	  //           case CL_DEVICE_PARTITION_PROPERTIES:
@@ -745,21 +760,16 @@ namespace pyopencl
     {
       switch (param_name)
 	{
-    //           case CL_CONTEXT_REFERENCE_COUNT:
-    //             PYOPENCL_GET_INTEGRAL_INFO(
-    // 				       Context, m_context, param_name, cl_uint);
-
-    //           case CL_CONTEXT_DEVICES:
-    //             {
-    //               std::vector<cl_device_id> result;
-    //               PYOPENCL_GET_VEC_INFO(Context, m_context, param_name, result);
+	case CL_CONTEXT_REFERENCE_COUNT:
+	  PYOPENCL_GET_INTEGRAL_INFO(Context, m_context, param_name, cl_uint);
 
-    //               py::list py_result;
-    //               BOOST_FOREACH(cl_device_id did, result)
-    //                 py_result.append(handle_from_new_ptr(
-    // 						     new pyopencl::device(did)));
-    //               return py_result;
-    //             }
+	case CL_CONTEXT_DEVICES:
+	  {
+	    std::vector<cl_device_id> result;
+	    PYOPENCL_GET_VEC_INFO(Context, m_context, param_name, result);
+	    PYOPENCL_GET_OPAQUE_ARRAY_INFO(cl_device_id, device, DEVICE, result);
+	    
+	  }
 
     //           case CL_CONTEXT_PROPERTIES:
     //             {
@@ -808,11 +818,10 @@ namespace pyopencl
     //               return py_result;
     //             }
 
-    // #if PYOPENCL_CL_VERSION >= 0x1010
-    //           case CL_CONTEXT_NUM_DEVICES:
-    //             PYOPENCL_GET_INTEGRAL_INFO(
-    // 				       Context, m_context, param_name, cl_uint);
-    // #endif
+#if PYOPENCL_CL_VERSION >= 0x1010
+	case CL_CONTEXT_NUM_DEVICES:
+	  PYOPENCL_GET_INTEGRAL_INFO(Context, m_context, param_name, cl_uint);
+#endif
 
 	default:
 	  throw error("Context.get_info", CL_INVALID_VALUE);
@@ -890,10 +899,10 @@ namespace pyopencl
       {
         case CL_QUEUE_CONTEXT:
           PYOPENCL_GET_OPAQUE_INFO(CommandQueue, m_queue, param_name,
-              cl_context, context);
+              cl_context, context, CONTEXT);
         case CL_QUEUE_DEVICE:
           PYOPENCL_GET_OPAQUE_INFO(CommandQueue, m_queue, param_name,
-              cl_device_id, device);
+              cl_device_id, device, DEVICE);
         case CL_QUEUE_REFERENCE_COUNT:
           PYOPENCL_GET_INTEGRAL_INFO(CommandQueue, m_queue, param_name,
               cl_uint);
@@ -974,7 +983,7 @@ namespace pyopencl
 	{
 	case CL_EVENT_COMMAND_QUEUE:
 	  PYOPENCL_GET_OPAQUE_INFO(Event, m_event, param_name,
-				   cl_command_queue, command_queue);
+				   cl_command_queue, command_queue, COMMAND_QUEUE);
 	case CL_EVENT_COMMAND_TYPE:
 	  PYOPENCL_GET_INTEGRAL_INFO(Event, m_event, param_name,
 				     cl_command_type);
@@ -987,7 +996,7 @@ namespace pyopencl
 #if PYOPENCL_CL_VERSION >= 0x1010
 	case CL_EVENT_CONTEXT:
 	  PYOPENCL_GET_OPAQUE_INFO(Event, m_event, param_name,
-				   cl_context, context);
+				   cl_context, context, CONTEXT);
 #endif
 
 	default:
@@ -1060,7 +1069,7 @@ namespace pyopencl
 				   cl_uint);
       case CL_MEM_CONTEXT:
 	PYOPENCL_GET_OPAQUE_INFO(MemObject, data(), param_name,
-				 cl_context, context);
+				 cl_context, context, CONTEXT);
 
 #if PYOPENCL_CL_VERSION >= 0x1010
 	//       case CL_MEM_ASSOCIATED_MEMOBJECT:
@@ -1410,25 +1419,6 @@ namespace pyopencl
       return result;
     }
 
-    char **get_info__binaries(uint32_t *num_binaries) {
-      std::vector<size_t> sizes;
-      PYOPENCL_GET_VEC_INFO(Program, m_program, CL_PROGRAM_BINARY_SIZES, sizes);
-      
-      *num_binaries = sizes.size();
-      
-      MALLOC(char *, result_ptrs, sizes.size());
-      
-      for (unsigned i = 0; i < sizes.size(); ++i) {
-	result_ptrs[i] = new char[sizes[i]+1];
-	result_ptrs[i][sizes[i]] = '\0';
-      }
-      PYOPENCL_CALL_GUARDED(clGetProgramInfo,
-			    (m_program, CL_PROGRAM_BINARIES, sizes.size()*sizeof(char *),
-			     result_ptrs, 0)); \
-      return result_ptrs;
-    }
-    
-
     generic_info get_info(cl_program_info param_name) const
     {
       switch (param_name)
@@ -1438,21 +1428,16 @@ namespace pyopencl
 				     cl_uint);
 	case CL_PROGRAM_CONTEXT:
 	  PYOPENCL_GET_OPAQUE_INFO(Program, m_program, param_name,
-				   cl_context, context);
+				   cl_context, context, CONTEXT);
 	case CL_PROGRAM_NUM_DEVICES:
 	  PYOPENCL_GET_INTEGRAL_INFO(Program, m_program, param_name,
 				     cl_uint);
-	  //           case CL_PROGRAM_DEVICES:
-	  //             {
-	  //               std::vector<cl_device_id> result;
-	  //               PYOPENCL_GET_VEC_INFO(Program, m_program, param_name, result);
-
-	  //               py::list py_result;
-	  //               BOOST_FOREACH(cl_device_id did, result)
-	  //                 py_result.append(handle_from_new_ptr(
-	  //                       new pyopencl::device(did)));
-	  //               return py_result;
-	  //             }
+	case CL_PROGRAM_DEVICES:
+	  {
+	    std::vector<cl_device_id> result;
+	    PYOPENCL_GET_VEC_INFO(Program, m_program, param_name, result);
+	    PYOPENCL_GET_OPAQUE_ARRAY_INFO(cl_device_id, device, DEVICE, result);
+	  }
 	case CL_PROGRAM_SOURCE:
 	  PYOPENCL_GET_STR_INFO(Program, m_program, param_name);
 	case CL_PROGRAM_BINARY_SIZES:
@@ -1461,48 +1446,22 @@ namespace pyopencl
 	    PYOPENCL_GET_VEC_INFO(Program, m_program, param_name, result);
 	    PYOPENCL_GET_ARRAY_INFO(size_t, result);
 	  }
-	  //           case CL_PROGRAM_BINARIES:
-	  //             // {{{
-	  //             {
-	  //               std::vector<size_t> sizes;
-	  //               PYOPENCL_GET_VEC_INFO(Program, m_program, CL_PROGRAM_BINARY_SIZES, sizes);
-
-	  //               size_t total_size = std::accumulate(sizes.begin(), sizes.end(), 0);
-
-	  //               boost::scoped_array<unsigned char> result(
-	  //                   new unsigned char[total_size]);
-	  //               std::vector<unsigned char *> result_ptrs;
-
-	  //               unsigned char *ptr = result.get();
-	  //               for (unsigned i = 0; i < sizes.size(); ++i)
-	  //               {
-	  //                 result_ptrs.push_back(ptr);
-	  //                 ptr += sizes[i];
-	  //               }
-
-	  //               PYOPENCL_CALL_GUARDED(clGetProgramInfo,
-	  //                   (m_program, param_name, sizes.size()*sizeof(unsigned char *),
-	  //                    result_ptrs.empty( ) ? NULL : &result_ptrs.front(), 0)); 
-
-	  //               py::list py_result;
-	  //               ptr = result.get();
-	  //               for (unsigned i = 0; i < sizes.size(); ++i)
-	  //               {
-	  //                 py::handle<> binary_pyobj(
-	  // #if PY_VERSION_HEX >= 0x03000000
-	  //                     PyBytes_FromStringAndSize(
-	  //                       reinterpret_cast<char *>(ptr), sizes[i])
-	  // #else
-	  //                     PyString_FromStringAndSize(
-	  //                       reinterpret_cast<char *>(ptr), sizes[i])
-	  // #endif
-	  //                     );
-	  //                 py_result.append(binary_pyobj);
-	  //                 ptr += sizes[i];
-	  //               }
-	  //               return py_result;
-	  //             }
-	  //             // }}}
+	case CL_PROGRAM_BINARIES:
+	  {
+	    std::vector<size_t> sizes;
+	    PYOPENCL_GET_VEC_INFO(Program, m_program, CL_PROGRAM_BINARY_SIZES, sizes);
+
+	    std::vector<char *> result_ptrs(sizes.size());
+	    for (unsigned i = 0; i < sizes.size(); ++i) {
+	      result_ptrs[i] = new char[sizes[i]+1];
+	      result_ptrs[i][sizes[i]] = '\0';
+	    }
+	    PYOPENCL_CALL_GUARDED(clGetProgramInfo,
+				  (m_program, CL_PROGRAM_BINARIES, sizes.size()*sizeof(char *),
+				   &result_ptrs.front(), 0)); 
+	    PYOPENCL_GET_ARRAY_INFO(char*, result_ptrs)
+	  }
+	  
 #if PYOPENCL_CL_VERSION >= 0x1020
 	case CL_PROGRAM_NUM_KERNELS:
 	  PYOPENCL_GET_INTEGRAL_INFO(Program, m_program, param_name,
@@ -1739,10 +1698,10 @@ namespace pyopencl
 				     cl_uint);
 	case CL_KERNEL_CONTEXT:
 	  PYOPENCL_GET_OPAQUE_INFO(Kernel, m_kernel, param_name,
-				   cl_context, context);
+				   cl_context, context, CONTEXT);
 	case CL_KERNEL_PROGRAM:
 	  PYOPENCL_GET_OPAQUE_INFO(Kernel, m_kernel, param_name,
-				   cl_program, program);
+				   cl_program, program, PROGRAM);
 #if PYOPENCL_CL_VERSION >= 0x1020
 	case CL_KERNEL_ATTRIBUTES:
 	  PYOPENCL_GET_STR_INFO(Kernel, m_kernel, param_name);
@@ -2127,33 +2086,6 @@ namespace pyopencl
 		   )
       return 0;
   }
-
-  ::error *program__get_info__devices(void *ptr_program, void **ptr_devices, uint32_t *num_devices) {
-    typedef std::vector<cl_device_id> vec;
-
-    // todo: refactor, same as get_devices()
-    C_HANDLE_ERROR(
-		   vec devices = static_cast<program*>(ptr_program)->get_info__devices();
-		   
-		   *num_devices = devices.size();
-
-		   MALLOC(device*, _ptr_devices, *num_devices);
-		   for(vec::size_type i = 0; i < devices.size(); ++i) {
-		     _ptr_devices[i] = new device(devices[i]);
-		   }
-		   *ptr_devices = _ptr_devices;
-		   )
-      return 0;
-    
-  }
-
-  ::error *program__get_info__binaries(void *ptr_program, char ***ptr_binaries, uint32_t *num_binaries) {
-    C_HANDLE_ERROR(
-		   *ptr_binaries = static_cast<program*>(ptr_program)->get_info__binaries(num_binaries);
-		   )
-      return 0;
-  }
-
   
   ::error *_create_kernel(void **ptr_kernel, void *ptr_program, char *name) {
     program *prg = static_cast<program*>(ptr_program);
diff --git a/src/c_wrapper/wrap_cl_core.h b/src/c_wrapper/wrap_cl_core.h
index d04c8657..0473ffd5 100644
--- a/src/c_wrapper/wrap_cl_core.h
+++ b/src/c_wrapper/wrap_cl_core.h
@@ -1,10 +1,5 @@
 typedef enum { KND_UNKNOWN, KND_SOURCE, KND_BINARY } program_kind_type;
 
-typedef struct {
-  const char *type;
-  void *value;
-} generic_info;
-
 typedef struct {
   const char *routine;
   const char *msg;
@@ -12,6 +7,7 @@ typedef struct {
 } error;
 
 typedef enum {
+  CLASS_NONE,
   CLASS_PLATFORM,
   CLASS_DEVICE,
   CLASS_KERNEL,
@@ -22,6 +18,14 @@ typedef enum {
   CLASS_COMMAND_QUEUE
 } class_t;
 
+
+typedef struct {
+  class_t opaque_class;
+  const char *type;
+  void *value;
+} generic_info;
+
+
 int get_cl_version(void);
 error *get_platforms(void **ptr_platforms, uint32_t *num_platforms);
 error *platform__get_devices(void *ptr_platform, void **ptr_devices, uint32_t *num_devices, cl_device_type devtype);
@@ -33,8 +37,6 @@ error *_create_program_with_binary(void **ptr_program, void *ptr_context, cl_uin
 error *program__build(void *ptr_program, char *options, cl_uint num_devices, void **ptr_devices);
 error *program__kind(void *ptr_program, int *kind);
 error *program__get_build_info(void *ptr_program, void *ptr_device, cl_program_build_info param, generic_info *out);
-error *program__get_info__devices(void *ptr_program, void **ptr_devices, uint32_t *num_devices);
-error *program__get_info__binaries(void *ptr_program, char ***ptr_binaries, uint32_t *num_binaries);
 
 error *_create_kernel(void **ptr_kernel, void *ptr_program, char *name);
 error *kernel__set_arg_mem_buffer(void *ptr_kernel, cl_uint arg_index, void *ptr_buffer);
-- 
GitLab