text: // MIT License - Igor Machado Coelho (2017)
  // The library cudapp is the basis of SimplePyCuda, a simple wrapper for CUDA functions in Python.
  // The idea is to workaround the issues regarding Context in old CUDA versions, that persist on PyCuda.
  
  #ifndef __CUDAPP_H__
  #define __CUDAPP_H__
  
  #include<stdio.h>
  
  extern "C" int cudappGetDeviceCount();
  extern "C" void cudappSetDevice(int);
  
  extern "C" void cudappDeviceSynchronize();
  
  extern "C" void cudappDeviceReset();
  
  extern "C" void* cudappMalloc(size_t);
  extern "C" void cudappFree(void*);
  extern "C" void cudappMemset(void*, unsigned char, size_t);
  
  extern "C" void cudappMemcpyHostToDevice(void*, void*, size_t);
  extern "C" void cudappMemcpyDeviceToHost(void*, void*, size_t);
  
  extern "C" void* cudappEventCreate();
  extern "C" void cudappEventRecord(void*, size_t);
  extern "C" void cudappEventSynchronize(void*);
  extern "C" float cudappEventElapsedTime(void*, void*);
  extern "C" void cudappEventDestroy(void*);
  
  extern "C" cudaError_t cudappGetLastError();
  
  // helper functions for error checking
  
  #define checkCudaErrors(val)           check ( (val), #val )
  
  extern "C" const char* cudappGetErrorEnum(cudaError_t error)
  {
      switch (error)
      {
          case cudaSuccess:
              return "cudaSuccess";
  
          case cudaErrorMissingConfiguration:
              return "cudaErrorMissingConfiguration";
  
          case cudaErrorMemoryAllocation:
              return "cudaErrorMemoryAllocation";
  
          case cudaErrorInitializationError:
              return "cudaErrorInitializationError";
  
          case cudaErrorLaunchFailure:
              return "cudaErrorLaunchFailure";
  
          case cudaErrorPriorLaunchFailure:
              return "cudaErrorPriorLaunchFailure";
  
          case cudaErrorLaunchTimeout:
              return "cudaErrorLaunchTimeout";
  
          case cudaErrorLaunchOutOfResources:
              return "cudaErrorLaunchOutOfResources";
  
          case cudaErrorInvalidDeviceFunction:
              return "cudaErrorInvalidDeviceFunction";
  
          case cudaErrorInvalidConfiguration:
              return "cudaErrorInvalidConfiguration";
  
          case cudaErrorInvalidDevice:
              return "cudaErrorInvalidDevice";
  
          case cudaErrorInvalidValue:
              return "cudaErrorInvalidValue";
  
          case cudaErrorInvalidPitchValue:
              return "cudaErrorInvalidPitchValue";
  
          case cudaErrorInvalidSymbol:
              return "cudaErrorInvalidSymbol";
  
          case cudaErrorMapBufferObjectFailed:
              return "cudaErrorMapBufferObjectFailed";
  
          case cudaErrorUnmapBufferObjectFailed:
              return "cudaErrorUnmapBufferObjectFailed";
  
          case cudaErrorInvalidHostPointer:
              return "cudaErrorInvalidHostPointer";
  
          case cudaErrorInvalidDevicePointer:
              return "cudaErrorInvalidDevicePointer";
  
          case cudaErrorInvalidTexture:
              return "cudaErrorInvalidTexture";
  
          case cudaErrorInvalidTextureBinding:
              return "cudaErrorInvalidTextureBinding";
  
          case cudaErrorInvalidChannelDescriptor:
              return "cudaErrorInvalidChannelDescriptor";
  
          case cudaErrorInvalidMemcpyDirection:
              return "cudaErrorInvalidMemcpyDirection";
  
          case cudaErrorAddressOfConstant:
              return "cudaErrorAddressOfConstant";
  
          case cudaErrorTextureFetchFailed:
              return "cudaErrorTextureFetchFailed";
  
          case cudaErrorTextureNotBound:
              return "cudaErrorTextureNotBound";
  
          case cudaErrorSynchronizationError:
              return "cudaErrorSynchronizationError";
  
          case cudaErrorInvalidFilterSetting:
              return "cudaErrorInvalidFilterSetting";
  
          case cudaErrorInvalidNormSetting:
              return "cudaErrorInvalidNormSetting";
  
          case cudaErrorMixedDeviceExecution:
              return "cudaErrorMixedDeviceExecution";
  
          case cudaErrorCudartUnloading:
              return "cudaErrorCudartUnloading";
  
          case cudaErrorUnknown:
              return "cudaErrorUnknown";
  
          case cudaErrorNotYetImplemented:
              return "cudaErrorNotYetImplemented";
  
          case cudaErrorMemoryValueTooLarge:
              return "cudaErrorMemoryValueTooLarge";
  
          case cudaErrorInvalidResourceHandle:
              return "cudaErrorInvalidResourceHandle";
  
          case cudaErrorNotReady:
              return "cudaErrorNotReady";
  
          case cudaErrorInsufficientDriver:
              return "cudaErrorInsufficientDriver";
  
          case cudaErrorSetOnActiveProcess:
              return "cudaErrorSetOnActiveProcess";
  
          case cudaErrorInvalidSurface:
              return "cudaErrorInvalidSurface";
  
          case cudaErrorNoDevice:
              return "cudaErrorNoDevice";
  
          case cudaErrorECCUncorrectable:
              return "cudaErrorECCUncorrectable";
  
          case cudaErrorSharedObjectSymbolNotFound:
              return "cudaErrorSharedObjectSymbolNotFound";
  
          case cudaErrorSharedObjectInitFailed:
              return "cudaErrorSharedObjectInitFailed";
  
          case cudaErrorUnsupportedLimit:
              return "cudaErrorUnsupportedLimit";
  
          case cudaErrorDuplicateVariableName:
              return "cudaErrorDuplicateVariableName";
  
          case cudaErrorDuplicateTextureName:
              return "cudaErrorDuplicateTextureName";
  
          case cudaErrorDuplicateSurfaceName:
              return "cudaErrorDuplicateSurfaceName";
  
          case cudaErrorDevicesUnavailable:
              return "cudaErrorDevicesUnavailable";
  
          case cudaErrorInvalidKernelImage:
              return "cudaErrorInvalidKernelImage";
  
          case cudaErrorNoKernelImageForDevice:
              return "cudaErrorNoKernelImageForDevice";
  
          case cudaErrorIncompatibleDriverContext:
              return "cudaErrorIncompatibleDriverContext";
  
          case cudaErrorPeerAccessAlreadyEnabled:
              return "cudaErrorPeerAccessAlreadyEnabled";
  
          case cudaErrorPeerAccessNotEnabled:
              return "cudaErrorPeerAccessNotEnabled";
  
          case cudaErrorDeviceAlreadyInUse:
              return "cudaErrorDeviceAlreadyInUse";
  
          case cudaErrorProfilerDisabled:
              return "cudaErrorProfilerDisabled";
  
          case cudaErrorProfilerNotInitialized:
              return "cudaErrorProfilerNotInitialized";
  
          case cudaErrorProfilerAlreadyStarted:
              return "cudaErrorProfilerAlreadyStarted";
  
          case cudaErrorProfilerAlreadyStopped:
              return "cudaErrorProfilerAlreadyStopped";
  
          /* CUDA 4.0*/
          case cudaErrorAssert:
              return "cudaErrorAssert";
  
          case cudaErrorTooManyPeers:
              return "cudaErrorTooManyPeers";
  
          case cudaErrorHostMemoryAlreadyRegistered:
              return "cudaErrorHostMemoryAlreadyRegistered";
  
          case cudaErrorHostMemoryNotRegistered:
              return "cudaErrorHostMemoryNotRegistered";
  
          /* CUDA 5.0 */
          case cudaErrorOperatingSystem:
              return "cudaErrorOperatingSystem";
  
          case cudaErrorPeerAccessUnsupported:
              return "cudaErrorPeerAccessUnsupported";
  
          case cudaErrorLaunchMaxDepthExceeded:
              return "cudaErrorLaunchMaxDepthExceeded";
  
          case cudaErrorLaunchFileScopedTex:
              return "cudaErrorLaunchFileScopedTex";
  
          case cudaErrorLaunchFileScopedSurf:
              return "cudaErrorLaunchFileScopedSurf";
  
          case cudaErrorSyncDepthExceeded:
              return "cudaErrorSyncDepthExceeded";
  
          case cudaErrorLaunchPendingCountExceeded:
              return "cudaErrorLaunchPendingCountExceeded";
  
          case cudaErrorNotPermitted:
              return "cudaErrorNotPermitted";
  
          case cudaErrorNotSupported:
              return "cudaErrorNotSupported";
  
          /* CUDA 6.0 */
          case cudaErrorHardwareStackError:
              return "cudaErrorHardwareStackError";
  
          case cudaErrorIllegalInstruction:
              return "cudaErrorIllegalInstruction";
  
          case cudaErrorMisalignedAddress:
              return "cudaErrorMisalignedAddress";
  
          case cudaErrorInvalidAddressSpace:
              return "cudaErrorInvalidAddressSpace";
  
          case cudaErrorInvalidPc:
              return "cudaErrorInvalidPc";
  
          case cudaErrorIllegalAddress:
              return "cudaErrorIllegalAddress";
  
          /* CUDA 6.5 */
          case cudaErrorInvalidPtx:
              return "cudaErrorInvalidPtx";
  
          case cudaErrorInvalidGraphicsContext:
              return "cudaErrorInvalidGraphicsContext";
  
          case cudaErrorStartupFailure:
              return "cudaErrorStartupFailure";
  
          case cudaErrorApiFailureBase:
              return "cudaErrorApiFailureBase";
      }
  
      return "cudapp_unknown_error";
  }
  
  template< typename T >
  void check(T result, char const *const func)
  {
      if (result)
      {
          fprintf(stderr, "CUDA error code=%d(%s) \"%s\" \n",
                  static_cast<unsigned int>(result), cudappGetErrorEnum(result), func);
          cudaDeviceReset();
      }
  }
  
  #endif
  
  