#ifndef array_io_H #define array_io_H /* Reading and writing generic multidimensional arrays */ #define array_io_H_COPYRIGHT "Copyright © 2009 by J. Stolfi, UNICAMP" /* Created on 2008-09-31 by J.Stolfi, UNICAMP */ /* Last edited on 2011-09-26 11:33:07 by stolfilocal */ /* This interface provides basic I/O operations on generic multidimensional arrays. !!! Add optional {fmt} argument to {PREFIX##_write}, {PREFIX##_elem_write}. !!! !!! OR add optional {elem_write} argument to {PREFIX##_write}. !!! !!! Add optional {cmt} argument to {PREFIX##_write}, and {cmptP} to {PREFIX##_read}. !!! !!! {PREFIX##_read} must return a descriptor (not a pointer to); or take {&A} argument. !!! ??? Possibly add {fmt} argument to {PREFIX##_read}, {PREFIX##_elem_read}. ??? For example, if {darray_t} was defined as a multidimensional array of {double} values, one can write ------------------------------------------------------------ //Read a multidimensional array {A} from {stdin}: darray_t A = darray_new(3,sz,ix_order_L); darray_read(stdin, &A); //Write the result to {stdout}: darray_write(stdout, &A); ------------------------------------------------------------ */ /* The I/O functions are made available by the macros {array_io_def} and {array_io_impl} (see below). For example, ------------------------------------------------------------ / * Declarations * / #include array_typedef(darray_t, darray, double); array_io_def(darray_t, darray, double); ------------------------------------------------------------ */ /* ------------------------------------------------------------ / * Implementations * / #include array_typedef(darray_t, darray, double); void darray_elem_read(FILE *rd, double *valP) { fscanf(rd, "%f", valP); } void darray_elem_write(FILE *wr, double *valP) { fprintf(wr, "%6.3f", *valP); } array_io_impl(darray_t, darray, double); ------------------------------------------------------------ */ #include #include #include #define array_io_def(ARRAY_TYPE,PREFIX,ELEM_TYPE) \ array_io_DEF(ARRAY_TYPE,PREFIX,ELEM_TYPE) /* This macro expands into the prototype declarations of four procedures, explained later: ------------------------------------------------------------ PREFIX##_write PREFIX##_read PREFIX##_elem_write PREFIX##_elem_read ------------------------------------------------------------ */ #define array_io_impl(ARRAY_TYPE,PREFIX,ELEM_TYPE) \ array_io_IMPL(ARRAY_TYPE,PREFIX,ELEM_TYPE) /* These macros expand into implementations of the procedures ------------------------------------------------------------ PREFIX##_write PREFIX##_read ------------------------------------------------------------ The client must provide adequate implementations for the functions {PREFIX##_elem_write} and {PREFIX##_elem_read}, as explained below. */ /* ====================================================================== The remainder of this interface describes the functions provided by the macros {array_io_def} and {array_io_impl}. */ /* ARRAY I/O */ /* ------------------------------------------------------------ void PREFIX##_write(FILE *wr, ARRAY_TYPE *A, ix_order_t ixor); ------------------------------------------------------------ */ /* Writes the array {A} to {wr}, in ASCII format. The file will start with a standard header line "begin ARRAY_TYPE (version {DATE})", followed by two lines with "axes = {A.ds.na}" and "size = {A.sz[0]} {A.sz[1]} ... {A.sz[A.ds.na-1]}". Then follow the array elements, one per line, in the format "{ix[0]} {ix[1]} ... {ix[A.ds.na-1]} {ELEMENT}", in the order specified by {ixor}. For all elements except the first one, if the last {k} indices are zero, the line is preceded by {k} blank lines. The file ends with a footer "end ARRAY_TYPE". Uses the client-defined function {PREFIX##_elem_write} to write each value; which will be preceded by a space, and followed by an end-of-line. */ /* ------------------------------------------------------------ ARRAY_TYPE *PREFIX##_read(FILE *rd); ------------------------------------------------------------ */ /* Reads an array from {rd}, in ASCII format generated by {PREFIX##_write}. The array and its descriptor are allocated by the procedure. Uses the client-defined function PREFIX##_elem_read} to parse each value. */ /* ELEMENT I/O FUNCTIONS The macro {array_io_def} also declares the following procedures:*/ /* ------------------------------------------------------------ void PREFIX##_elem_write(FILE *wr, ELEM_TYPE *valP); ------------------------------------------------------------ */ /* Writes to the output stream {wr} the value {*valP}. This procedure must be implemented by the client. It is often advisable to use a human- and machine-readable plain text representation that preserves all the relevant information contained in {*valP}. For example, a prudent choice for {double} values would be {fprintf(wr, "%24.16e", *valP)}.*/ /* ------------------------------------------------------------ void PREFIX##_elem_read(FILE *rd, ELEM_TYPE *valP); ------------------------------------------------------------ */ /* Parses an {ELEM_TYPE} value from the input stream {rd}, and stores it into the variable {val}. This function must be implemented by the client. It is often advisable to define it so that it can parse any output that may be produced by {PREFIX##_elem_write}. */ #include #endif