1
0
mirror of https://github.com/TREX-CoE/trexio.git synced 2025-04-27 10:54:44 +02:00
trexio/src/templates_front/templator_front.org
2021-03-22 16:15:07 +01:00

612 lines
15 KiB
Org Mode

#+Title: Templator for frontend
* Constant file prefixes (not used by generator) :noxport:
#+NAME:header
#+begin_src c
/* This file was generated from the templator_front.org org-mode file.
To generate it, open trexio.org in Emacs and execute
M-x org-babel-tangle
*/
#+end_src
#+begin_src fortran :tangle prefix_fortran.f90 :noweb yes
<<header>>
module trexio
use, intrinsic :: iso_c_binding
#+end_src
#+begin_src c :tangle prefix_front.h :noweb yes
<<header>>
#ifndef _TREXIO_H
#define _TREXIO_H
#include <stdint.h>
#+end_src
#+begin_src c :tangle prefix_front.c :noweb yes
<<header>>
#include <pthread.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "trexio.h"
#include "trexio_s.h"
#include "trexio_text.h"
#include "trexio_hdf5.h"
/*
#include "trexio_json.h"
,*/
#+end_src
#+begin_src c :tangle prefix_s_front.h :noweb yes
<<header>>
#ifndef _TREXIO_S_H
#define _TREXIO_S_H
#include "trexio.h"
#include <pthread.h>
#include <assert.h>
#+end_src
* Coding conventions
- integer types will be defined using types given in ~stdint.h~
- pointers are always initialized to ~NULL~
- when memory is freed, the pointer is set to ~NULL~
- ~assert.h~ should be used extensively
- variable names are in lower case
- ~#define~ constants are in upper case
- structs are suffixed by ~_s~
- types are suffixed by ~_t~
** Memory allocation
Memory allocation of structures can be facilitated by using the
following macro, which ensures that the size of the allocated
object is the same as the size of the data type pointed by the pointer.
#+begin_src c :tangle trexio_private.h
#define MALLOC(T) (T*) malloc (sizeof(T));
#define CALLOC(N,T) (T*) calloc ((N),sizeof(T));
#+end_src
When a pointer is freed, it should be set to ~NULL~.
This can be facilitated by the use of the following macro:
#+begin_src c :tangle trexio_private.h
#define FREE(X) { free(X) ; (X)=NULL; }
#+end_src
* Front end
All calls to TREXIO are thread-safe.
** Error handling
#+begin_src c :tangle prefix_front.h
typedef int32_t trexio_exit_code;
#define TREXIO_FAILURE ( (trexio_exit_code) -1 )
#define TREXIO_SUCCESS ( (trexio_exit_code) 0 )
#define TREXIO_INVALID_ARG_1 ( (trexio_exit_code) 1 )
#define TREXIO_INVALID_ARG_2 ( (trexio_exit_code) 2 )
#define TREXIO_INVALID_ARG_3 ( (trexio_exit_code) 3 )
#define TREXIO_INVALID_ARG_4 ( (trexio_exit_code) 4 )
#define TREXIO_INVALID_ARG_5 ( (trexio_exit_code) 5 )
#define TREXIO_END ( (trexio_exit_code) 10 )
#define TREXIO_READONLY ( (trexio_exit_code) 11 )
#define TREXIO_ERRNO ( (trexio_exit_code) 12 )
#define TREXIO_INVALID_ID ( (trexio_exit_code) 20 )
#define TREXIO_ALLOCATION_FAILED ( (trexio_exit_code) 21 )
#define TREXIO_INVALID_NUM ( (trexio_exit_code) 22 )
#+end_src
** Back ends
#+begin_src c :tangle prefix_front.h
typedef int32_t back_end_t;
#define TREXIO_HDF5 ( (back_end_t) 0 )
#define TREXIO_TEXT ( (back_end_t) 1 )
#define TREXIO_JSON ( (back_end_t) 2 )
#define TREXIO_INVALID_BACK_END ( (back_end_t) 3 )
#+end_src
** Read/write behavior
Every time a reading function is called, the data is read from the
disk. If data needs to be cached, this is left to the user of the
library.
Writing to TREXIO files is done with transactions (all-or-nothing
effect) in a per-group fashion. File writes are attempted by
calling explicitly the flush function, or when the TREXIO file is
closed. If writing is impossible because the data is not valid, no
data is written.
The order in which the data is written is not necessarily consistent
with the order in which the function calls were made.
The TREXIO files are supposed to be opened by only one program at a
time: if the same TREXIO file is modified simultaneously by multiple
concurrent programs, the behavior is not specified.
** TREXIO file type
~trexio_s~ is the the main type for TREXIO files, visible to the users
of the library. This type is kept opaque, and all modifications to
the files will be necessarily done through the use of functions,
taking such a type as argument.
File creation and opening functions will return /TREXIO file handles/,
namely pointers to ~trexio_s~ types. All functions accessing to the
TREXIO files will have as a first argument the TREXIO file handle.
#+begin_src c :tangle prefix_front.h
typedef struct trexio_s trexio_t;
#+end_src
#+begin_src c :tangle prefix_s_front.h
struct trexio_s {
char* file_name;
pthread_mutex_t thread_lock;
back_end_t back_end;
char mode;
char padding[7]; /* Ensures the proper alignment of back-ends */
};
#+end_src
** Polymorphism of the file handle
Polymorphism of the ~trexio_t~ type is handled by ensuring that the
corresponding types for all back ends can be safely casted to
~trexio_t~. This is done by making the back end structs start with
~struct trexio_s~:
#+begin_src c
struct trexio_back_end_s {
trexio_t parent ;
/* add below specific back end data */
}
#+end_src
** File opening
#+begin_src c :tangle prefix_front.h
trexio_t* trexio_open(const char* file_name, const char mode, const back_end_t back_end);
#+end_src
#+begin_src c :tangle prefix_front.c
trexio_t* trexio_open(const char* file_name, const char mode, const back_end_t back_end) {
if (file_name == NULL) return NULL;
if (file_name[0] == '\0') return NULL;
if (back_end < 0) return NULL;
if (back_end >= TREXIO_INVALID_BACK_END) return NULL;
if (mode != 'r' && mode != 'w' && mode != 'a') return NULL;
trexio_t* result = NULL;
/* Allocate data structures */
switch (back_end) {
case TREXIO_TEXT:
result = (trexio_t*) malloc (sizeof(trexio_text_t));
break;
case TREXIO_HDF5:
result = (trexio_t*) malloc (sizeof(trexio_hdf5_t));
break;
/*
case TREXIO_JSON:
result = (trexio_t*) malloc (sizeof(trexio_json_t));
break;
,*/
}
assert (result != NULL); /* TODO: Error handling */
/* Data for the parent type */
result->file_name = (char*) calloc(strlen(file_name)+1,sizeof(char));
strcpy(result->file_name, file_name);
result->back_end = back_end;
result->mode = mode;
int irc = pthread_mutex_init ( &(result->thread_lock), NULL);
assert (irc == 0);
trexio_exit_code rc;
/* Back end initialization */
rc = TREXIO_FAILURE;
switch (back_end) {
case TREXIO_TEXT:
rc = trexio_text_init(result);
break;
case TREXIO_HDF5:
rc = trexio_hdf5_init(result);
break;
/*
case TREXIO_JSON:
rc = trexio_json_init(result);
break;
,*/
}
if (rc != TREXIO_SUCCESS) {
free(result->file_name);
free(result);
return NULL;
}
/* File locking */
rc = TREXIO_FAILURE;
switch (back_end) {
case TREXIO_TEXT:
rc = trexio_text_lock(result);
break;
case TREXIO_HDF5:
rc = TREXIO_SUCCESS;
break;
/*
case TREXIO_JSON:
rc = trexio_json_lock(result);
break;
*/
}
if (rc != TREXIO_SUCCESS) {
free(result->file_name);
free(result);
return NULL;
}
return result;
}
#+end_src
#+begin_src fortran :tangle prefix_fortran.f90
interface
type (c_ptr) function trexio_open (filename, mode, backend) bind(C)
use, intrinsic :: iso_c_binding
character(kind=c_char), dimension(*) :: filename
character(kind=c_char), intent(in) :: mode
integer (c_int32_t), intent(in), value :: backend
end function trexio_open
end interface
#+end_src
** File closing
#+begin_src c :tangle prefix_front.h
trexio_exit_code trexio_close(trexio_t* file);
#+end_src
#+begin_src c :tangle prefix_front.c
trexio_exit_code trexio_close(trexio_t* file) {
if (file == NULL) return TREXIO_FAILURE;
trexio_exit_code rc;
/* Terminate the back end */
switch (file->back_end) {
case TREXIO_TEXT:
rc = trexio_text_finalize(file);
break;
case TREXIO_HDF5:
rc = trexio_hdf5_finalize(file);
break;
/*
case TREXIO_JSON:
rc = trexio_json_finalize(file);
break;
,*/
default:
assert (1 == 0); /* Impossible case */
}
if (rc != TREXIO_SUCCESS) {
free(file->file_name);
free(file);
return TREXIO_FAILURE;
}
/* File unlocking */
rc = TREXIO_FAILURE;
switch (file->back_end) {
case TREXIO_TEXT:
rc = trexio_text_unlock(file);
break;
case TREXIO_HDF5:
rc = TREXIO_SUCCESS;
break;
/*
case TREXIO_JSON:
rc = trexio_json_unlock(file);
break;
*/
}
/* Terminate front end */
free(file->file_name);
file->file_name = NULL;
int irc = pthread_mutex_destroy( &(file->thread_lock) );
free(file);
if (irc != 0) return TREXIO_ERRNO;
if (rc != TREXIO_SUCCESS) return TREXIO_FAILURE;
return TREXIO_SUCCESS;
}
#+end_src
#+begin_src fortran :tangle prefix_fortran.f90
interface
type (c_int32_t) function trexio_close (trex_file) bind(C)
use, intrinsic :: iso_c_binding
type (c_ptr), intent(in), value :: trex_file
end function trexio_close
end interface
#+end_src
* Templates for front end
** Template for frontend read/write a number
#+begin_src c :tangle rw_num_front.h
trexio_exit_code trexio_read_$group_num$(trexio_t* file, int64_t* num);
trexio_exit_code trexio_write_$group_num$(trexio_t* file, const int64_t num);
#+end_src
#+begin_src c :tangle read_num_front.c
trexio_exit_code trexio_read_$group_num$(trexio_t* file, int64_t* num) {
if (file == NULL) return TREXIO_INVALID_ARG_1;
uint64_t u_num = 0;
trexio_exit_code rc = TREXIO_FAILURE;
switch (file->back_end) {
case TREXIO_TEXT:
rc = trexio_text_read_$group_num$(file, &u_num);
break;
case TREXIO_HDF5:
rc = trexio_hdf5_read_$group_num$(file, &u_num);
break;
/*
case TREXIO_JSON:
rc =trexio_json_read_$group_num$(file, &u_num);
break;
,*/
}
if (rc != TREXIO_SUCCESS) return rc;
/**/ *num = (int64_t) u_num;
return TREXIO_SUCCESS;
}
#+end_src
#+begin_src c :tangle write_num_front.c
trexio_exit_code trexio_write_$group_num$(trexio_t* file, const int64_t num) {
if (file == NULL) return TREXIO_INVALID_ARG_1;
if (num < 0 ) return TREXIO_INVALID_ARG_2;
trexio_exit_code rc = TREXIO_FAILURE;
switch (file->back_end) {
case TREXIO_TEXT:
rc = trexio_text_write_$group_num$(file, (uint64_t) num);
break;
case TREXIO_HDF5:
rc = trexio_hdf5_write_$group_num$(file, (uint64_t) num);
break;
/*
case TREXIO_JSON:
rc = trexio_json_write_$group_num$(file, (uint64_t) num);
break;
,*/
}
if (rc != TREXIO_SUCCESS) return rc;
return TREXIO_SUCCESS;
}
#+end_src
#+begin_src fortran :tangle write_num_front_fortran.f90
interface
integer (c_int32_t) function trexio_write_$group_num$ (trex_file, num) bind(C)
use, intrinsic :: iso_c_binding
type (c_ptr), intent(in), value :: trex_file
integer (c_int64_t), intent(in), value :: num
end function trexio_write_$group_num$
end interface
#+end_src
#+begin_src fortran :tangle read_num_front_fortran.f90
interface
integer (c_int32_t) function trexio_read_$group_num$ (trex_file, num) bind(C)
use, intrinsic :: iso_c_binding
type (c_ptr), intent(in), value :: trex_file
integer (c_int64_t), intent(inout), value :: num
end function trexio_read_$group_num$
end interface
#+end_src
** Template for frontend read/write a dataset
#+begin_src c :tangle rw_dset_front.h
trexio_exit_code trexio_read_$group$_$group_dset$(trexio_t* file, $group_dset_dtype$* $group_dset$);
trexio_exit_code trexio_write_$group$_$group_dset$(trexio_t* file, const $group_dset_dtype$* $group_dset$);
#+end_src
#+begin_src c :tangle read_dset_front.c
trexio_exit_code trexio_read_$group$_$group_dset$(trexio_t* file, $group_dset_dtype$* $group_dset$) {
if (file == NULL) return TREXIO_INVALID_ARG_1;
if ($group_dset$ == NULL) return TREXIO_INVALID_ARG_2;
trexio_exit_code rc;
uint64_t $group_dset_dim$ = -1;
switch (file->back_end) {
case TREXIO_TEXT:
rc = trexio_text_read_$group_dset_dim$(file, &$group_dset_dim$);
break;
case TREXIO_HDF5:
rc = trexio_hdf5_read_$group_dset_dim$(file, &$group_dset_dim$);
break;
/*
case TREXIO_JSON:
rc = trexio_json_read_$group_dset_dim$(file, &$group_dset_dim$);
break;
*/
}
if (rc != TREXIO_SUCCESS) return rc;
if ($group_dset_dim$ <= 0L) return TREXIO_INVALID_NUM;
uint32_t rank = $group_dset_rank$;
uint64_t dims[$group_dset_rank$] = {$group_dset_dim_list$};
switch (file->back_end) {
case TREXIO_TEXT:
return trexio_text_read_$group$_$group_dset$(file, $group_dset$, rank, dims);
break;
case TREXIO_HDF5:
return trexio_hdf5_read_$group$_$group_dset$(file, $group_dset$, rank, dims);
break;
/*
case TREXIO_JSON:
return trexio_json_read_$group$_$group_dset$(file, $group_dset$);
break;
,*/
default:
return TREXIO_FAILURE; /* Impossible case */
}
}
#+end_src
#+begin_src c :tangle write_dset_front.c
trexio_exit_code trexio_write_$group$_$group_dset$(trexio_t* file, const $group_dset_dtype$* $group_dset$) {
if (file == NULL) return TREXIO_INVALID_ARG_1;
if ($group_dset$ == NULL) return TREXIO_INVALID_ARG_2;
trexio_exit_code rc;
uint64_t $group_dset_dim$ = -1;
switch (file->back_end) {
case TREXIO_TEXT:
rc = trexio_text_read_$group_dset_dim$(file, &$group_dset_dim$);
break;
case TREXIO_HDF5:
rc = trexio_hdf5_read_$group_dset_dim$(file, &$group_dset_dim$);
break;
/*
case TREXIO_JSON:
rc = trexio_json_read_$group_dset_dim$(file, &$group_dset_dim$);
break;
*/
}
if (rc != TREXIO_SUCCESS) return rc;
if ($group_dset_dim$ <= 0L) return TREXIO_INVALID_NUM;
uint32_t rank = $group_dset_rank$;
uint64_t dims[$group_dset_rank$] = {$group_dset_dim_list$};
switch (file->back_end) {
case TREXIO_TEXT:
return trexio_text_write_$group$_$group_dset$(file, $group_dset$, rank, dims);
break;
case TREXIO_HDF5:
return trexio_hdf5_write_$group$_$group_dset$(file, $group_dset$, rank, dims);
break;
/*
case TREXIO_JSON:
return trexio_json_write_$group$_$group_dset$(file, $group_dset$);
break;
,*/
default:
return TREXIO_FAILURE; /* Impossible case */
}
}
#+end_src
* Back ends
TREXIO has multiple possible back ends:
- HDF5: The most efficient back-end, by default
- Text files: not to be used for production, but useful for debugging
- JSON: for portability
* File suffixes :noxport:
#+begin_src c :tangle suffix_front.h
#endif
#+end_src
#+begin_src c :tangle suffix_s_front.h
#endif
#+end_src
#+begin_src fortran :tangle suffix_fortran.f90
end module trexio
#+end_src