#+TITLE: TEXT back end #+PROPERTY: comments org #+SETUPFILE: ../../docs/theme.setup # -*- mode: org -*- * Constant file prefixes (not used by the generator) :noexport: #+begin_src emacs-lisp (setq-local org-babel-default-header-args:c '((:comments . "both"))) org-babel-default-header-args:c #+end_src #+RESULTS: : ((:comments . both)) # Local Variables: # eval: (setq-local org-babel-default-header-args:Python '((:session . "foo"))) # End: #+NAME:header #+begin_src c /* This file was generated from the trexio.org org-mode file. To generate it, open trexio.org in Emacs and execute M-x org-babel-tangle */ #+end_src #+begin_src c :tangle prefix_text.h :noweb yes <
> #ifndef TREXIO_TEXT_H #define TREXIO_TEXT_H #include "trexio.h" #include "trexio_private.h" #include "trexio_s.h" #include #include #include #include #include #include #include #include #include #include #+end_src #+begin_src c :tangle prefix_text.c :noweb yes /* This file was generated from the trexio.org org-mode file. To generate it, open trexio.org in Emacs and execute M-x org-babel-tangle */ #include "trexio_text.h" #+end_src * TEXT back end The "file" produced by the text back end is a directory with one file per group. When the file is open, it is locked by the current process. No other process can read/write the same file. This guarantees that the representation in memory is consistent with the file and avoid re-reading the file before writing. To lock the file, we lock the =.lock= file which is present in the directory. The file is written when closed, or when the flush function is called. ** Template for group-related structures in text back end #+begin_src c :tangle struct_text_group_dset.h typedef struct $group$_s { $group_num_dtype_double$ $group_num$; bool $group_num$_isSet; $group_dset_dtype$* $group_dset$; uint32_t rank_$group_dset$; uint32_t to_flush; uint64_t dims_$group_dset$[16]; uint64_t len_$group_str$; char* $group_str$; char file_name[TREXIO_MAX_FILENAME_LENGTH]; } $group$_t; #+end_src ** Template for general structure in text back end #+begin_src c :tangle struct_text_group.h typedef struct rdm_s { uint64_t dim_one_e; uint32_t to_flush; uint32_t padding; double* one_e; char file_name[TREXIO_MAX_FILENAME_LENGTH]; char two_e_file_name[TREXIO_MAX_FILENAME_LENGTH]; } rdm_t; #+end_src #+begin_src c :tangle struct_text_group.h typedef struct trexio_text_s { trexio_t parent ; $group$_t* $group$; rdm_t* rdm; int lock_file; } trexio_text_t; #+end_src ** Initialize function (constant part) #+begin_src c :tangle basic_text.h :exports none trexio_exit_code trexio_text_init(trexio_t* const file); #+end_src #+begin_src c :tangle basic_text.c trexio_exit_code trexio_text_init (trexio_t* const file) { if (file == NULL) return TREXIO_INVALID_ARG_1; trexio_text_t* const f = (trexio_text_t*) file; /* Put all pointers to NULL but leave parent untouched */ memset(&(f->parent)+1,0,sizeof(trexio_text_t)-sizeof(trexio_t)); /* If directory doesn't exist, create it in write mode */ struct stat st; if (stat(file->file_name, &st) == 0 && S_ISDIR(st.st_mode)) { /* Do nothing */ } else { if (file->mode == 'r') return TREXIO_READONLY; if (mkdir(file->file_name, 0777) != 0) { return TREXIO_FAILURE; } } /* Create the lock file in the directory */ const char* lock_file_name = "/.lock"; char file_name[TREXIO_MAX_FILENAME_LENGTH]; strncpy (file_name, file->file_name, TREXIO_MAX_FILENAME_LENGTH); strncat (file_name, lock_file_name, TREXIO_MAX_FILENAME_LENGTH-strlen(lock_file_name)); if (file_name[TREXIO_MAX_FILENAME_LENGTH-1] != '\0') { return TREXIO_LOCK_ERROR; } f->lock_file = open(file_name,O_WRONLY|O_CREAT|O_TRUNC, 0644); if (f->lock_file <= 0) { return TREXIO_FAILURE; } return TREXIO_SUCCESS; } #+end_src #+begin_src c :tangle basic_text.h :exports none trexio_exit_code trexio_text_lock(trexio_t* const file); #+end_src #+begin_src c :tangle basic_text.c trexio_exit_code trexio_text_lock(trexio_t* const file) { if (file == NULL) return TREXIO_INVALID_ARG_1; trexio_text_t* const f = (trexio_text_t*) file; struct flock fl; fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; fl.l_pid = getpid(); int rc = fcntl(f->lock_file, F_SETLKW, &fl); if (rc == -1) return TREXIO_FAILURE; return TREXIO_SUCCESS; } #+end_src #+begin_src c :tangle basic_text.h :exports none trexio_exit_code trexio_text_deinit(trexio_t* const file); #+end_src #+begin_src c :tangle basic_text.h :exports none trexio_exit_code trexio_text_unlock(trexio_t* const file); #+end_src #+begin_src c :tangle basic_text.c trexio_exit_code trexio_text_unlock (trexio_t* const file) { if (file == NULL) return TREXIO_INVALID_ARG_1; trexio_text_t* const f = (trexio_text_t*) file; struct flock fl; fl.l_type = F_UNLCK; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; fl.l_pid = getpid(); fcntl(f->lock_file, F_SETLK, &fl); close(f->lock_file); return TREXIO_SUCCESS; } #+end_src ** Deinitialize function (templated part) #+begin_src c :tangle basic_text_group.c trexio_exit_code trexio_text_deinit (trexio_t* const file) { if (file == NULL) return TREXIO_INVALID_ARG_1; trexio_exit_code rc; /* Error handling for this call is added by the generator */ rc = trexio_text_free_$group$( (trexio_text_t*) file); rc = trexio_text_free_rdm( (trexio_text_t*) file); if (rc != TREXIO_SUCCESS) return rc; return TREXIO_SUCCESS; } #+end_src ** Template for text read struct #+begin_src c :tangle read_group_text.h :exports none $group$_t* trexio_text_read_$group$(trexio_text_t* const file); #+end_src #+begin_src c :tangle read_group_text.c $group$_t* trexio_text_read_$group$ (trexio_text_t* const file) { if (file == NULL) return NULL; /* If the data structure exists, return it */ if (file->$group$ != NULL) { return file->$group$; } /* Allocate the data structure */ $group$_t* $group$ = MALLOC($group$_t); if ($group$ == NULL) return NULL; memset($group$,0,sizeof($group$_t)); /* Build the file name */ const char* $group$_file_name = "/$group$.txt"; strncpy ($group$->file_name, file->parent.file_name, TREXIO_MAX_FILENAME_LENGTH); strncat ($group$->file_name, $group$_file_name, TREXIO_MAX_FILENAME_LENGTH-strlen($group$_file_name)); if ($group$->file_name[TREXIO_MAX_FILENAME_LENGTH-1] != '\0') { FREE($group$); return NULL; } /* If the file exists, read it */ FILE* f = fopen($group$->file_name,"r"); if (f != NULL) { /* Find size of file to allocate the max size of the string buffer */ fseek(f, 0L, SEEK_END); size_t sz = ftell(f); fseek(f, 0L, SEEK_SET); sz = (sz < 1024) ? (1024) : (sz); char* buffer = CALLOC(sz, char); if (buffer == NULL) { fclose(f); FREE($group$); return NULL; } /* Read the dimensioning variables */ int rc; // START REPEAT GROUP_DSET_ALL rc = fscanf(f, "%1023s", buffer); if ((rc != 1) || (strcmp(buffer, "rank_$group_dset$") != 0)) { FREE(buffer); fclose(f); FREE($group$); return NULL; } rc = fscanf(f, "%u", &($group$->rank_$group_dset$)); if (rc != 1) { FREE(buffer); fclose(f); FREE($group$); return NULL; } /* workaround for the case of missing blocks in the file */ uint64_t size_$group_dset$ = 0; if ($group$->rank_$group_dset$ != 0) size_$group_dset$ = 1; for (uint32_t i=0; i<$group$->rank_$group_dset$; ++i){ uint32_t j=0; rc = fscanf(f, "%1023s %u", buffer, &j); if ((rc != 2) || (strcmp(buffer, "dims_$group_dset$") != 0) || (j!=i)) { FREE(buffer); fclose(f); FREE($group$); return NULL; } rc = fscanf(f, "%" SCNu64 "\n", &($group$->dims_$group_dset$[i])); assert(!(rc != 1)); if (rc != 1) { FREE(buffer); fclose(f); FREE($group$); return NULL; } size_$group_dset$ *= $group$->dims_$group_dset$[i]; } // END REPEAT GROUP_DSET_ALL unsigned int local_isSet; // START REPEAT GROUP_NUM /* Read data */ rc = fscanf(f, "%1023s", buffer); assert(!((rc != 1) || (strcmp(buffer, "$group_num$_isSet") != 0))); if ((rc != 1) || (strcmp(buffer, "$group_num$_isSet") != 0)) { FREE(buffer); fclose(f); FREE($group$); return NULL; } /* additional parameter local_isSet is needed to suppress warning when fscanf into bool variable using %u or %d */ rc = fscanf(f, "%u", &(local_isSet)); $group$->$group_num$_isSet = (bool) local_isSet; assert(!(rc != 1)); if (rc != 1) { FREE(buffer); fclose(f); FREE($group$); return NULL; } if ($group$->$group_num$_isSet == true) { rc = fscanf(f, "%1023s", buffer); assert(!((rc != 1) || (strcmp(buffer, "$group_num$") != 0))); if ((rc != 1) || (strcmp(buffer, "$group_num$") != 0)) { FREE(buffer); fclose(f); FREE($group$); return NULL; } rc = fscanf(f, "%$group_num_std_dtype_in$", &($group$->$group_num$)); assert(!(rc != 1)); if (rc != 1) { FREE(buffer); fclose(f); FREE($group$); return NULL; } } // END REPEAT GROUP_NUM // START REPEAT GROUP_ATTR_STR rc = fscanf(f, "%1023s", buffer); assert(!((rc != 1) || (strcmp(buffer, "len_$group_str$") != 0))); if ((rc != 1) || (strcmp(buffer, "len_$group_str$") != 0)) { FREE(buffer); fclose(f); FREE($group$); return NULL; } rc = fscanf(f, "%" SCNu64 "", &($group$->len_$group_str$)); assert(!(rc != 1)); if (rc != 1) { FREE(buffer); fclose(f); FREE($group$); return NULL; } rc = fscanf(f, "%1023s", buffer); assert(!((rc != 1) || (strcmp(buffer, "$group_str$") != 0))); if ((rc != 1) || (strcmp(buffer, "$group_str$") != 0)) { FREE(buffer); fclose(f); FREE($group$->$group_str$); FREE($group$); return NULL; } if ($group$->len_$group_str$ != 0) { $group$->$group_str$ = CALLOC($group$->len_$group_str$, char); assert (!($group$->$group_str$ == NULL)); if ($group$->$group_str$ == NULL) { FREE(buffer); fclose(f); FREE($group$->$group_str$); FREE($group$); return NULL; } rc = fscanf(f, " %1023[^\n]", $group$->$group_str$); assert(!(rc != 1)); if (rc != 1) { FREE(buffer); fclose(f); FREE($group$->$group_str$); FREE($group$); return NULL; } } // END REPEAT GROUP_ATTR_STR // START REPEAT GROUP_DSET_NUM /* Allocate arrays */ $group$->$group_dset$ = CALLOC(size_$group_dset$, $group_dset_dtype$); assert (!($group$->$group_dset$ == NULL)); if ($group$->$group_dset$ == NULL) { FREE(buffer); fclose(f); FREE($group$->$group_dset$); FREE($group$); return NULL; } rc = fscanf(f, "%1023s", buffer); assert(!((rc != 1) || (strcmp(buffer, "$group_dset$") != 0))); if ((rc != 1) || (strcmp(buffer, "$group_dset$") != 0)) { FREE(buffer); fclose(f); FREE($group$->$group_dset$); FREE($group$); return NULL; } for (uint64_t i=0 ; i$group_dset$[i])); assert(!(rc != 1)); if (rc != 1) { FREE(buffer); fclose(f); FREE($group$->$group_dset$); FREE($group$); return NULL; } } // END REPEAT GROUP_DSET_NUM // START REPEAT GROUP_DSET_STR /* Allocate arrays */ if(size_$group_dset$ != 0) { $group$->$group_dset$ = CALLOC(size_$group_dset$, $group_dset_dtype$); assert (!($group$->$group_dset$ == NULL)); if ($group$->$group_dset$ == NULL) { FREE(buffer); fclose(f); FREE($group$->$group_dset$); FREE($group$); return NULL; } rc = fscanf(f, "%1023s", buffer); assert(!((rc != 1) || (strcmp(buffer, "$group_dset$") != 0))); if ((rc != 1) || (strcmp(buffer, "$group_dset$") != 0)) { FREE(buffer); fclose(f); FREE($group$->$group_dset$); FREE($group$); return NULL; } /* WARNING: this tmp array allows to avoid allocation of space for each element of array of string , BUT it's size has to be number_of_str*max_len_str where max_len_str is somewhat arbitrary, e.g. 32. ,*/ char* tmp_$group_dset$; tmp_$group_dset$ = CALLOC(size_$group_dset$*32, char); for (uint64_t i=0 ; i$group_dset$[i] = tmp_$group_dset$; /* conventional fcanf with "%s" only return the string before the first space character ,* to read string with spaces use "%[^\n]" possible with space before or after, i.e. " %[^\n]" ,* Q: depending on what ? */ rc = fscanf(f, " %1023[^\n]", tmp_$group_dset$); assert(!(rc != 1)); if (rc != 1) { FREE(buffer); fclose(f); FREE($group$->$group_dset$); FREE($group$); return NULL; } size_t tmp_$group_dset$_len = strlen($group$->$group_dset$[i]); tmp_$group_dset$ += tmp_$group_dset$_len + 1; } } // END REPEAT GROUP_DSET_STR FREE(buffer); fclose(f); f = NULL; } file->$group$ = $group$; return $group$; } #+end_src ** Template for text flush struct #+begin_src c :tangle flush_group_text.h :exports none trexio_exit_code trexio_text_flush_$group$(trexio_text_t* const file); #+end_src #+begin_src c :tangle flush_group_text.c trexio_exit_code trexio_text_flush_$group$ (trexio_text_t* const file) { if (file == NULL) return TREXIO_INVALID_ARG_1; if (file->parent.mode == 'r') return TREXIO_READONLY; $group$_t* $group$ = file->$group$; if ($group$ == NULL) return TREXIO_SUCCESS; if ($group$->to_flush == 0) return TREXIO_SUCCESS; assert (file->parent.mode == 'w'); FILE* f = fopen($group$->file_name, "w"); if (f == NULL) return TREXIO_INVALID_ARG_1; /* Write the dimensioning variables */ // START REPEAT GROUP_DSET_ALL fprintf(f, "rank_$group_dset$ %u\n", $group$->rank_$group_dset$); // workaround for the case of missing blocks in the file uint64_t size_$group_dset$ = 0; if ($group$->rank_$group_dset$ != 0) size_$group_dset$ = 1; for (unsigned int i=0; i<$group$->rank_$group_dset$; ++i){ fprintf(f, "dims_$group_dset$ %u %" PRIu64 "\n", i, $group$->dims_$group_dset$[i]); size_$group_dset$ *= $group$->dims_$group_dset$[i]; } // END REPEAT GROUP_DSET_ALL // START REPEAT GROUP_NUM fprintf(f, "$group_num$_isSet %u \n", $group$->$group_num$_isSet); if ($group$->$group_num$_isSet == true) fprintf(f, "$group_num$ %$group_num_std_dtype_out$ \n", $group$->$group_num$); // END REPEAT GROUP_NUM // START REPEAT GROUP_ATTR_STR fprintf(f, "len_$group_str$ %" PRIu64 "\n", $group$->len_$group_str$); fprintf(f, "$group_str$\n"); if ($group$->len_$group_str$ != 0) fprintf(f, "%s\n", $group$->$group_str$); // END REPEAT GROUP_ATTR_STR /* Write arrays */ // START REPEAT GROUP_DSET_ALL fprintf(f, "$group_dset$\n"); for (uint64_t i=0 ; i$group_dset$[i]); } // END REPEAT GROUP_DSET_ALL fclose(f); $group$->to_flush = 0; return TREXIO_SUCCESS; } #+end_src ** Template for text free memory Memory is allocated when reading. The following function frees memory. #+begin_src c :tangle free_group_text.h :exports none trexio_exit_code trexio_text_free_$group$(trexio_text_t* const file); #+end_src #+begin_src c :tangle free_group_text.c trexio_exit_code trexio_text_free_$group$ (trexio_text_t* const file) { if (file == NULL) return TREXIO_INVALID_ARG_1; if (file->parent.mode != 'r') { trexio_exit_code rc = trexio_text_flush_$group$(file); if (rc != TREXIO_SUCCESS) return TREXIO_FAILURE; } $group$_t* $group$ = file->$group$; if ($group$ == NULL) return TREXIO_SUCCESS; // START REPEAT GROUP_DSET_NUM if ($group$->$group_dset$ != NULL) FREE ($group$->$group_dset$); // END REPEAT GROUP_DSET_NUM // START REPEAT GROUP_DSET_STR if ($group$->$group_dset$ != NULL) { if($group$->rank_$group_dset$ != 0) FREE ($group$->$group_dset$[0]); FREE ($group$->$group_dset$); } // END REPEAT GROUP_DSET_STR // START REPEAT GROUP_ATTR_STR if ($group$->$group_str$ != NULL) FREE ($group$->$group_str$); // END REPEAT GROUP_ATTR_STR FREE ($group$); return TREXIO_SUCCESS; } #+end_src ** Template for has/read/write the numerical attribute #+begin_src c :tangle hrw_attr_num_text.h :exports none trexio_exit_code trexio_text_has_$group_num$ (trexio_t* const file); trexio_exit_code trexio_text_read_$group_num$ (trexio_t* const file, $group_num_dtype_double$* const num); trexio_exit_code trexio_text_write_$group_num$(trexio_t* const file, const $group_num_dtype_double$ num); #+end_src #+begin_src c :tangle read_attr_num_text.c trexio_exit_code trexio_text_read_$group_num$ (trexio_t* const file, $group_num_dtype_double$* const num) { if (file == NULL) return TREXIO_INVALID_ARG_1; if (num == NULL) return TREXIO_INVALID_ARG_2; $group$_t* $group$ = trexio_text_read_$group$((trexio_text_t*) file); if ($group$ == NULL) return TREXIO_FAILURE; *num = $group$->$group_num$; return TREXIO_SUCCESS; } #+end_src #+begin_src c :tangle write_attr_num_text.c trexio_exit_code trexio_text_write_$group_num$ (trexio_t* const file, const $group_num_dtype_double$ num) { if (file == NULL) return TREXIO_INVALID_ARG_1; if (file->mode == 'r') return TREXIO_READONLY; $group$_t* $group$ = trexio_text_read_$group$((trexio_text_t*) file); if ($group$ == NULL) return TREXIO_FAILURE; $group$->$group_num$ = num; $group$->$group_num$_isSet = true; $group$->to_flush = 1; return TREXIO_SUCCESS; } #+end_src #+begin_src c :tangle has_attr_num_text.c trexio_exit_code trexio_text_has_$group_num$ (trexio_t* const file) { if (file == NULL) return TREXIO_INVALID_ARG_1; $group$_t* $group$ = trexio_text_read_$group$((trexio_text_t*) file); if ($group$ == NULL) return TREXIO_FAILURE; if ($group$->$group_num$_isSet == true){ return TREXIO_SUCCESS; } else { return TREXIO_HAS_NOT; } } #+end_src ** Template for has/read/write the dataset of numerical data The ~group_dset~ array is assumed allocated with the appropriate size. #+begin_src c :tangle hrw_dset_data_text.h :exports none trexio_exit_code trexio_text_has_$group_dset$ (trexio_t* const file); trexio_exit_code trexio_text_read_$group_dset$ (trexio_t* const file, $group_dset_dtype$* const $group_dset$, const uint32_t rank, const uint64_t* dims); trexio_exit_code trexio_text_write_$group_dset$(trexio_t* const file, const $group_dset_dtype$* $group_dset$, const uint32_t rank, const uint64_t* dims); #+end_src #+begin_src c :tangle read_dset_data_text.c trexio_exit_code trexio_text_read_$group_dset$ (trexio_t* const file, $group_dset_dtype$* const $group_dset$, const uint32_t rank, const uint64_t* dims) { if (file == NULL) return TREXIO_INVALID_ARG_1; if ($group_dset$ == NULL) return TREXIO_INVALID_ARG_2; $group$_t* const $group$ = trexio_text_read_$group$((trexio_text_t*) file); if ($group$ == NULL) return TREXIO_FAILURE; if (rank != $group$->rank_$group_dset$) return TREXIO_INVALID_ARG_3; uint64_t dim_size = 1; for (uint32_t i=0; idims_$group_dset$[i]) return TREXIO_INVALID_ARG_4; dim_size *= dims[i]; } for (uint64_t i=0 ; i$group_dset$[i]; } return TREXIO_SUCCESS; } #+end_src #+begin_src c :tangle write_dset_data_text.c trexio_exit_code trexio_text_write_$group_dset$ (trexio_t* const file, const $group_dset_dtype$* $group_dset$, const uint32_t rank, const uint64_t* dims) { if (file == NULL) return TREXIO_INVALID_ARG_1; if ($group_dset$ == NULL) return TREXIO_INVALID_ARG_2; if (file->mode == 'r') return TREXIO_READONLY; $group$_t* const $group$ = trexio_text_read_$group$((trexio_text_t*) file); if ($group$ == NULL) return TREXIO_FAILURE; if ($group$->$group_dset$ != NULL) { FREE($group$->$group_dset$); } $group$->rank_$group_dset$ = rank; uint64_t dim_size = 1; for (uint32_t i=0; i<$group$->rank_$group_dset$; ++i){ $group$->dims_$group_dset$[i] = dims[i]; dim_size *= dims[i]; } $group$->$group_dset$ = CALLOC(dim_size, $group_dset_dtype$); for (uint64_t i=0 ; i$group_dset$[i] = $group_dset$[i]; } $group$->to_flush = 1; return TREXIO_SUCCESS; } #+end_src #+begin_src c :tangle has_dset_data_text.c trexio_exit_code trexio_text_has_$group_dset$ (trexio_t* const file) { if (file == NULL) return TREXIO_INVALID_ARG_1; $group$_t* const $group$ = trexio_text_read_$group$((trexio_text_t*) file); if ($group$ == NULL) return TREXIO_FAILURE; if ($group$->rank_$group_dset$ > 0){ return TREXIO_SUCCESS; } else { return TREXIO_HAS_NOT; } } #+end_src ** Template for has/read/write the dataset of strings The ~group_dset~ array is assumed allocated with the appropriate size. #+begin_src c :tangle hrw_dset_str_text.h :exports none trexio_exit_code trexio_text_has_$group_dset$ (trexio_t* const file); trexio_exit_code trexio_text_read_$group_dset$ (trexio_t* const file, char* const dset, const uint32_t rank, const uint64_t* dims, const uint32_t max_str_len); trexio_exit_code trexio_text_write_$group_dset$ (trexio_t* const file, const char** dset, const uint32_t rank, const uint64_t* dims); #+end_src #+begin_src c :tangle read_dset_str_text.c trexio_exit_code trexio_text_read_$group_dset$ (trexio_t* const file, char* const dset, const uint32_t rank, const uint64_t* dims, const uint32_t max_str_len) { if (file == NULL) return TREXIO_INVALID_ARG_1; if (dset == NULL) return TREXIO_INVALID_ARG_2; $group$_t* const $group$ = trexio_text_read_$group$((trexio_text_t*) file); if ($group$ == NULL) return TREXIO_FAILURE; if (rank != $group$->rank_$group_dset$) return TREXIO_INVALID_ARG_3; for (uint32_t i=0 ; idims_$group_dset$[i]) return TREXIO_INVALID_ARG_4; } strcpy(dset, ""); for (uint64_t i=0 ; i$group_dset$[i], max_str_len); strcat(dset, TREXIO_DELIM); } return TREXIO_SUCCESS; } #+end_src #+begin_src c :tangle write_dset_str_text.c trexio_exit_code trexio_text_write_$group_dset$ (trexio_t* const file, const char** dset, const uint32_t rank, const uint64_t* dims) { if (file == NULL) return TREXIO_INVALID_ARG_1; if (dset == NULL) return TREXIO_INVALID_ARG_2; if (file->mode == 'r') return TREXIO_READONLY; $group$_t* const $group$ = trexio_text_read_$group$((trexio_text_t*) file); if ($group$ == NULL) return TREXIO_FAILURE; if ($group$->$group_dset$ != NULL) { if ($group$->rank_$group_dset$ != 0) FREE($group$->$group_dset$[0]); FREE($group$->$group_dset$); } $group$->rank_$group_dset$ = rank; for (uint32_t i=0; i<$group$->rank_$group_dset$; ++i){ $group$->dims_$group_dset$[i] = dims[i]; } $group$->$group_dset$ = CALLOC(dims[0], char*); if ($group$->$group_dset$ == NULL) return TREXIO_ALLOCATION_FAILED; char* tmp_str = CALLOC(dims[0]*32 + 1, char); if (tmp_str == NULL) return TREXIO_ALLOCATION_FAILED; for (uint64_t i=0 ; i$group_dset$[i] = tmp_str; strncpy(tmp_str, dset[i], tmp_len); tmp_str += tmp_len + 1; } $group$->to_flush = 1; return TREXIO_SUCCESS; } #+end_src #+begin_src c :tangle has_dset_str_text.c trexio_exit_code trexio_text_has_$group_dset$ (trexio_t* const file) { if (file == NULL) return TREXIO_INVALID_ARG_1; $group$_t* const $group$ = trexio_text_read_$group$((trexio_text_t*) file); if ($group$ == NULL) return TREXIO_FAILURE; if ($group$->rank_$group_dset$ > 0){ return TREXIO_SUCCESS; } else { return TREXIO_HAS_NOT; } } #+end_src ** Template for has/read/write the string attribute #+begin_src c :tangle hrw_attr_str_text.h :exports none trexio_exit_code trexio_text_has_$group_str$ (trexio_t* const file); trexio_exit_code trexio_text_read_$group_str$ (trexio_t* const file, char* const str, const uint32_t max_str_len); trexio_exit_code trexio_text_write_$group_str$ (trexio_t* const file, const char* str); #+end_src #+begin_src c :tangle read_attr_str_text.c trexio_exit_code trexio_text_read_$group_str$ (trexio_t* const file, char* const str, const uint32_t max_str_len) { if (file == NULL) return TREXIO_INVALID_ARG_1; if (str == NULL) return TREXIO_INVALID_ARG_2; $group$_t* const $group$ = trexio_text_read_$group$((trexio_text_t*) file); if ($group$ == NULL) return TREXIO_FAILURE; strncpy(str, $group$->$group_str$, max_str_len); return TREXIO_SUCCESS; } #+end_src #+begin_src c :tangle write_attr_str_text.c trexio_exit_code trexio_text_write_$group_str$ (trexio_t* const file, const char *str) { if (file == NULL) return TREXIO_INVALID_ARG_1; if (str == NULL) return TREXIO_INVALID_ARG_2; if (file->mode == 'r') return TREXIO_READONLY; $group$_t* const $group$ = trexio_text_read_$group$((trexio_text_t*) file); if ($group$ == NULL) return TREXIO_FAILURE; if ($group$->$group_str$ != NULL) FREE($group$->$group_str$); size_t tmp_len = strlen(str); $group$->$group_str$ = CALLOC(tmp_len + 1, char); if ($group$->$group_str$ == NULL) return TREXIO_ALLOCATION_FAILED; $group$->len_$group_str$ = tmp_len + 1; strncpy($group$->$group_str$, str, tmp_len + 1); $group$->to_flush = 1; return TREXIO_SUCCESS; } #+end_src #+begin_src c :tangle has_attr_str_text.c trexio_exit_code trexio_text_has_$group_str$ (trexio_t* const file) { if (file == NULL) return TREXIO_INVALID_ARG_1; $group$_t* const $group$ = trexio_text_read_$group$((trexio_text_t*) file); if ($group$ == NULL) return TREXIO_FAILURE; if ($group$->len_$group_str$ > 0){ return TREXIO_SUCCESS; } else { return TREXIO_HAS_NOT; } } #+end_src ** RDM struct (hard-coded) *** Read the complete struct #+begin_src c :tangle rdm_text.h rdm_t* trexio_text_read_rdm(trexio_text_t* const file); #+end_src #+begin_src c :tangle rdm_text.c rdm_t* trexio_text_read_rdm(trexio_text_t* const file) { if (file == NULL) return NULL; if (file->rdm != NULL) return file->rdm; /* Allocate the data structure */ rdm_t* rdm = MALLOC(rdm_t); assert (rdm != NULL); rdm->one_e = NULL; rdm->two_e_file_name[0] = '\0'; rdm->to_flush = 0; /* Try to open the file. If the file does not exist, return */ const char* rdm_file_name = "/rdm.txt"; strncpy (rdm->file_name, file->parent.file_name, TREXIO_MAX_FILENAME_LENGTH); strncat (rdm->file_name, rdm_file_name, TREXIO_MAX_FILENAME_LENGTH-strlen(rdm_file_name)); if (rdm->file_name[TREXIO_MAX_FILENAME_LENGTH-1] != '\0') { FREE(rdm); return NULL; } /* If the file exists, read it */ FILE* f = fopen(rdm->file_name,"r"); if (f != NULL) { /* Find size of file to allocate the max size of the string buffer */ fseek(f, 0L, SEEK_END); size_t sz = ftell(f); fseek(f, 0L, SEEK_SET); sz = (sz < 1024) ? (1024) : (sz); char* buffer = CALLOC(sz, char); /* Read the dimensioning variables */ int rc; rc = fscanf(f, "%1023s", buffer); assert (rc == 1); assert (strcmp(buffer, "dim_one_e") == 0); rc = fscanf(f, "%" SCNu64 "", &(rdm->dim_one_e)); assert (rc == 1); /* Allocate arrays */ rdm->one_e = CALLOC(rdm->dim_one_e, double); assert (rdm->one_e != NULL); /* Read one_e */ rc = fscanf(f, "%1023s", buffer); assert (rc == 1); assert (strcmp(buffer, "one_e") == 0); for (uint64_t i=0 ; idim_one_e; ++i) { rc = fscanf(f, "%lf", &(rdm->one_e[i])); assert (rc == 1); } /* Read two_e */ rc = fscanf(f, "%1023s", buffer); assert (rc == 1); assert (strcmp(buffer, "two_e_file_name") == 0); rc = fscanf(f, "%1023s", buffer); assert (rc == 1); strncpy(rdm->two_e_file_name, buffer, 1024); if (rdm->two_e_file_name[TREXIO_MAX_FILENAME_LENGTH-1] != '\0') { FREE(buffer); FREE(rdm->one_e); FREE(rdm); fclose(f); return NULL; } FREE(buffer); fclose(f); f = NULL; } file->rdm = rdm ; return rdm; } #+end_src *** Flush the complete struct #+begin_src c :tangle rdm_text.h trexio_exit_code trexio_text_flush_rdm(trexio_text_t* const file); #+end_src #+begin_src c :tangle rdm_text.c trexio_exit_code trexio_text_flush_rdm(trexio_text_t* const file) { if (file == NULL) return TREXIO_INVALID_ARG_1; if (file->parent.mode == 'r') return TREXIO_READONLY; rdm_t* const rdm = file->rdm; if (rdm == NULL) return TREXIO_SUCCESS; if (rdm->to_flush == 0) return TREXIO_SUCCESS; FILE* f = fopen(rdm->file_name,"w"); assert (f != NULL); /* Write the dimensioning variables */ fprintf(f, "num %" PRIu64 "\n", rdm->dim_one_e); /* Write arrays */ fprintf(f, "one_e\n"); for (uint64_t i=0 ; i< rdm->dim_one_e; ++i) { fprintf(f, "%lf\n", rdm->one_e[i]); } fprintf(f, "two_e_file_name\n"); fprintf(f, "%s\n", rdm->two_e_file_name); fclose(f); rdm->to_flush = 0; return TREXIO_SUCCESS; } #+end_src *** Free memory Memory is allocated when reading. The followig function frees memory. #+begin_src c :tangle rdm_text.h trexio_exit_code trexio_text_free_rdm(trexio_text_t* const file); #+end_src #+begin_src c :tangle rdm_text.c trexio_exit_code trexio_text_free_rdm(trexio_text_t* const file) { if (file == NULL) return TREXIO_INVALID_ARG_1; if (file->parent.mode != 'r') { trexio_exit_code rc = trexio_text_flush_rdm(file); if (rc != TREXIO_SUCCESS) return TREXIO_FAILURE; } rdm_t* const rdm = file->rdm; if (rdm == NULL) return TREXIO_SUCCESS; if (rdm->one_e != NULL) { FREE (rdm->one_e); } free (rdm); file->rdm = NULL; return TREXIO_SUCCESS; } #+end_src *** Read/Write the one_e attribute The ~one_e~ array is assumed allocated with the appropriate size. #+begin_src c :tangle rdm_text.h trexio_exit_code trexio_text_read_rdm_one_e(trexio_t* const file, double* const one_e, const uint64_t dim_one_e); trexio_exit_code trexio_text_write_rdm_one_e(trexio_t* const file, const double* one_e, const uint64_t dim_one_e); #+end_src #+begin_src c :tangle rdm_text.c trexio_exit_code trexio_text_read_rdm_one_e(trexio_t* const file, double* const one_e, const uint64_t dim_one_e) { if (file == NULL) return TREXIO_INVALID_ARG_1; if (one_e == NULL) return TREXIO_INVALID_ARG_2; rdm_t* const rdm = trexio_text_read_rdm((trexio_text_t*) file); if (rdm == NULL) return TREXIO_FAILURE; if (dim_one_e != rdm->dim_one_e) return TREXIO_INVALID_ARG_3; for (uint64_t i=0 ; ione_e[i]; } return TREXIO_SUCCESS; } trexio_exit_code trexio_text_write_rdm_one_e(trexio_t* const file, const double* one_e, const uint64_t dim_one_e) { if (file == NULL) return TREXIO_INVALID_ARG_1; if (one_e == NULL) return TREXIO_INVALID_ARG_2; if (file->mode != 'r') return TREXIO_READONLY; rdm_t* const rdm = trexio_text_read_rdm((trexio_text_t*) file); if (rdm == NULL) return TREXIO_FAILURE; rdm->dim_one_e = dim_one_e; for (uint64_t i=0 ; ione_e[i] = one_e[i]; } rdm->to_flush = 1; return TREXIO_SUCCESS; } #+end_src *** Read/Write the two_e attribute ~two_e~ is a sparse data structure, which can be too large to fit in memory. So we provide functions to read and write it by chunks. In the text back end, the easiest way to do it is to create a file for each sparse float structure. #+begin_src c :tangle rdm_text.h trexio_exit_code trexio_text_buffered_read_rdm_two_e(trexio_t* const file, const uint64_t offset, const uint64_t size, int64_t* const index, double* const value); trexio_exit_code trexio_text_buffered_write_rdm_two_e(trexio_t* const file, const uint64_t offset, const uint64_t size, const int64_t* index, const double* value); #+end_src #+begin_src c :tangle rdm_text.c trexio_exit_code trexio_text_buffered_read_rdm_two_e(trexio_t* const file, const uint64_t offset, const uint64_t size, int64_t* const index, double* const value) { if (file == NULL) return TREXIO_INVALID_ARG_1; if (index == NULL) return TREXIO_INVALID_ARG_4; if (value == NULL) return TREXIO_INVALID_ARG_5; rdm_t* const rdm = trexio_text_read_rdm((trexio_text_t*) file); if (rdm == NULL) return TREXIO_FAILURE; FILE* f = fopen(rdm->two_e_file_name, "r"); if (f == NULL) return TREXIO_END; const uint64_t line_length = 64L; fseek(f, (long) offset * line_length, SEEK_SET); for (uint64_t i=0 ; imode != 'r') return TREXIO_READONLY; rdm_t* const rdm = trexio_text_read_rdm((trexio_text_t*) file); if (rdm == NULL) return TREXIO_FAILURE; FILE* f = fopen(rdm->two_e_file_name, "w"); if (f == NULL) return TREXIO_FAILURE; const uint64_t line_length = 64L; fseek(f, (long) offset * line_length, SEEK_SET); for (uint64_t i=0 ; i