mirror of
https://github.com/TREX-CoE/trexio.git
synced 2025-04-27 10:54:44 +02:00
612 lines
15 KiB
Org Mode
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
|
|
|
|
|
|
|