////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Author: David Goz
// mail  : david.goz@inaf.it
// date  : 29.07.2024
// code tested using nvhpc
//
// - Compile the code:
//   $ nvc -mp=gpu -gpu=ccnative,debug,lineinfo -target=gpu -Minfo=all -v map_type_modifier.c -o map_type_modifier_omp
// - Run the code:
//   $ export OMP_TARGET_OFFLOAD=mandatory
//   $ ./map_type_modifier_omp
////////////////////////////////////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <omp.h>

#define N     8
typedef float MyData;

void allocate(      MyData **buffer,
	      const size_t   size)
{
  /* allocate the buffer on the host memory */
  MyData *tmp = malloc(size * sizeof(**buffer));
  assert(tmp != NULL);
  *buffer = tmp;

#pragma omp target enter data map(alloc: tmp[0:size])
  
  return;
}

void print(const MyData *const A,
	   const int           size)
{
  printf("\n");
  for (size_t i=0 ; i<N ; i++)
    printf("\n\t array[%i] = %lg", i, A[i]);
  printf("\n\n");
  
  return;
}

int main()
{
  MyData *array = NULL;
  allocate(&array, N);

  /* init on the GPU */
  #pragma omp target
  {
    for (size_t i=0 ; i<N ; i++)
      array[i] = (MyData)(i);
  }

  #pragma omp target update from(array[0:N])
  print(array, N);
  
  /* free the device's memory */
  #pragma omp target exit data map(delete: array[0:N])

  /* free the host's memory */
  free(array);

  return 0;
}
