 // CUDA functions
 //================
 
+// TODO: this will not work with asynchronous calls
+inline void cuda_check_last_error(const char* file_name, const int line_number)
+{
+    cudaError_t error = cudaGetLastError();
+    if (error != cudaSuccess)
+    {
+        printf("CUDA error at line %i of file %s: %s\n", line_number, file_name, cudaGetErrorString(error));
+        exit(-100);
+    }
+}
+
 extern "C" void cuda_initialize()
 {
-    if (cudaSetDeviceFlags(cudaDeviceMapHost) != cudaSuccess)
-    {
-        printf("failed to execute cudaSetDeviceFlags()\n");
-        exit(0);
-    }
+    cudaSetDeviceFlags(cudaDeviceMapHost);
+    cuda_check_last_error(__FILE__, __LINE__);
 }
 
 extern "C" void cuda_malloc(void** ptr, size_t size)
 {
-    if (cudaMalloc(ptr, size) != cudaSuccess)
-    {
-        printf("failed to execute cudaMalloc() \n");
-        exit(0);
-    }
+    cudaMalloc(ptr, size);
+    cuda_check_last_error(__FILE__, __LINE__);
 }
 
 extern "C" void cuda_free(void* ptr)
 {
-    if (cudaFree(ptr) != cudaSuccess)
-    {
-        printf("failed to execute cudaFree() \n");
-        exit(0);
-    }
+    cudaFree(ptr);
+    cuda_check_last_error(__FILE__, __LINE__);
 }
 
 extern "C" void cuda_malloc_host(void** ptr, size_t size)
 {
-    if (cudaMallocHost(ptr, size) != cudaSuccess)
-    {  
-        printf("cudaMallocHost failed\n");
-        exit(-1);
-    }
+    cudaMallocHost(ptr, size);
+    cuda_check_last_error(__FILE__, __LINE__);
 }
 
 extern "C" void cuda_free_host(void** ptr)
 {
-    if (cudaFreeHost(*ptr) != cudaSuccess)
-    {
-        printf("cudaFreeHost failed\n");
-        exit(-1);
-    }
+    cudaFreeHost(*ptr);
+    cuda_check_last_error(__FILE__, __LINE__);
 }
 
 extern "C" void cuda_copy_to_device(void* target, void* source, size_t size)
 {
-    if (cudaMemcpy(target, source, size, cudaMemcpyHostToDevice) != cudaSuccess)
-    {
-        printf("failed to execute cudaMemcpy(cudaMemcpyHostToDevice)\n");
-        exit(0);
-    }
+    cudaMemcpy(target, source, size, cudaMemcpyHostToDevice);
+    cuda_check_last_error(__FILE__, __LINE__);
 }
 
 extern "C" void cuda_copy_to_host(void* target, void* source, size_t size)
 {
-    if (cudaMemcpy(target, source, size, cudaMemcpyDeviceToHost) != cudaSuccess)
-    {
-        printf("failed to execute cudaMemcpy(cudaMemcpyDeviceToHost)\n");
-        exit(0);
-    }
+    cudaMemcpy(target, source, size, cudaMemcpyDeviceToHost);
+    cuda_check_last_error(__FILE__, __LINE__);
 }
 
 extern "C" void cuda_device_synchronize()
 {
-    if (cudaDeviceSynchronize() != cudaSuccess)
-    {
-        printf("failed to execute cudaDeviceSynchronize()\n");
-        exit(0);
-    }
+    cudaDeviceSynchronize();
+    cuda_check_last_error(__FILE__, __LINE__);
 }
 
 extern "C" void cuda_device_reset()
 {
-    if (cudaDeviceReset() != cudaSuccess)
-    {
-        printf("faile to execute cudaDeviceReset()\n");
-        exit(0);
-    }
+    cudaDeviceReset();
+    cuda_check_last_error(__FILE__, __LINE__);
 }
 
 cudaStream_t* streams;

extern "C" void cuda_device_info()
{
    int count;
    if (cudaGetDeviceCount(&count) != cudaSuccess)
    {
        printf("failed to execute cudaGetDeviceCount() \n");
        exit(-1);
    }

    if (count == 0)
    {


extern "C" void cuda_stream_synchronize(int stream_id)
{
    cudaStreamSynchronize(streams[stream_id]);
    cuda_check_last_error(__FILE__, __LINE__);
}

extern "C" void cuda_async_copy_to_device(void* target, void* source, size_t size, int stream_id)
{
    cudaStream_t stream = (stream_id == -1) ? NULL : streams[stream_id];

    cudaMemcpyAsync(target, source, size, cudaMemcpyHostToDevice, stream);
    cuda_check_last_error(__FILE__, __LINE__);
}

extern "C" void cuda_async_copy_to_host(void* target, void* source, size_t size, int stream_id)
{
    cudaStream_t stream = (stream_id == -1) ? NULL : streams[stream_id];

    cudaMemcpyAsync(target, source, size, cudaMemcpyDeviceToHost, stream);
    cuda_check_last_error(__FILE__, __LINE__);
}

extern "C" void cuda_memset(void* ptr, int value, size_t size)
{
    cudaMemset(ptr, value, size);
    cuda_check_last_error(__FILE__, __LINE__);
}

extern "C" void cuda_host_register(void* ptr, size_t size)
{
    assert(ptr);
    
    cudaHostRegister(ptr, size, cudaHostRegisterMapped);
    cuda_check_last_error(__FILE__, __LINE__);
}

extern "C" void cuda_host_unregister(void* ptr)
{
    cudaHostUnregister(ptr);
    cuda_check_last_error(__FILE__, __LINE__);
}

//* cudaDeviceProp& cuda_devprop()
