LCOV - code coverage report
Current view: top level - experimental/utility - LAGraph_SRead.c (source / functions) Hit Total Coverage
Test: LAGraph code coverage report. Commit id: cc56ed4. Current time (UTC): 2024-08-30T17:14:30Z Lines: 117 117 100.0 %
Date: 2024-08-30 17:16:41 Functions: 2 2 100.0 %

          Line data    Source code
       1             : //------------------------------------------------------------------------------
       2             : // LAGraph_SRead: read a sequence of serialized objects from a file
       3             : //------------------------------------------------------------------------------
       4             : 
       5             : // LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved.
       6             : // SPDX-License-Identifier: BSD-2-Clause
       7             : //
       8             : // For additional details (including references to third party source code and
       9             : // other files) see the LICENSE file or contact permission@sei.cmu.edu. See
      10             : // Contributors.txt for a full list of contributors. Created, in part, with
      11             : // funding and support from the U.S. Government (see Acknowledgments.txt file).
      12             : // DM22-0790
      13             : 
      14             : // Contributed by Timothy A. Davis, Texas A&M University
      15             : 
      16             : //------------------------------------------------------------------------------
      17             : 
      18             : // LAGraph_SRead reads a set of serialized items from a file. The items are
      19             : // returned as-is and not converted into GrB_Matrix, GrB_Vector, or text
      20             : // objects.  The user application is responsible for freeing the output of this
      21             : // method, via:
      22             : 
      23             : //      LAGraph_Free ((void **) &collection, NULL) ;
      24             : //      LAGraph_SFreeContents (&Contents, ncontents) ;
      25             : 
      26             : // See also LAGraph_SLoadSet, which calls this function and then converts all
      27             : // serialized objects into their GrB_Matrix, GrB_Vector, or text components.
      28             : 
      29             : //------------------------------------------------------------------------------
      30             : 
      31             : #include "LG_internal.h"
      32             : #include "LAGraphX.h"
      33             : 
      34             : //------------------------------------------------------------------------------
      35             : // json.h: JSON parser
      36             : //------------------------------------------------------------------------------
      37             : 
      38             : #include "json.h"
      39             : 
      40             : typedef struct json_value_s  *json_val ;
      41             : typedef struct json_object_s *json_obj ; // { json_o start; size length }
      42             : typedef struct json_array_s  *json_arr ; // { json_a start; size length }
      43             : typedef struct json_string_s *json_str ; // { char *string; size string_size }
      44             : typedef struct json_number_s *json_num ; // { char *number; size number_size }
      45             : 
      46             : // object element: { char *name; json_val value ; json_o next }
      47             : typedef struct json_object_element_s *json_o ;
      48             : 
      49             : // array element:  {             json_val value ; json_a next }
      50             : typedef struct json_array_element_s  *json_a ;
      51             : 
      52             : #define STRMATCH(s,t) (strcmp (s,t) == 0)
      53             : #define OK(ok) LG_ASSERT_MSG (ok, LAGRAPH_IO_ERROR, "invalid file")
      54             : #define VER(major,minor,sub) (((major)*1000ULL + (minor))*1000ULL + (sub))
      55             : 
      56             : //------------------------------------------------------------------------------
      57             : // get_int_array_3: get an int array of size 3 from the JSON header
      58             : //------------------------------------------------------------------------------
      59             : 
      60         416 : static int get_int_array_3 (json_arr arr, int *x, char *msg)
      61             : {
      62         416 :     OK (arr != NULL) ;
      63         416 :     OK (x != NULL) ;
      64         416 :     OK (arr->length == 3) ;
      65         416 :     json_a a = arr->start ;
      66         416 :     json_num num = json_value_as_number (a->value) ;
      67         416 :     OK (num != NULL) ;
      68         416 :     x [0] = (int) strtol (num->number, NULL, 0) ;
      69         416 :     a = a->next ;
      70         416 :     num = json_value_as_number (a->value) ;
      71         416 :     OK (num != NULL) ;
      72         416 :     x [1] = (int) strtol (num->number, NULL, 0) ;
      73         416 :     a = a->next ;
      74         416 :     num = json_value_as_number (a->value) ;
      75         416 :     OK (num != NULL) ;
      76         416 :     x [2] = (int) strtol (num->number, NULL, 0) ;
      77         416 :     return (GrB_SUCCESS) ;
      78             : }
      79             : 
      80             : //------------------------------------------------------------------------------
      81             : // LAGraph_SRead
      82             : //------------------------------------------------------------------------------
      83             : 
      84             : #undef  LG_FREE_WORK
      85             : #define LG_FREE_WORK                                    \
      86             : {                                                       \
      87             :     if (root != NULL) { free (root) ; }                 \
      88             :     root = NULL ;                                       \
      89             :     LAGraph_Free ((void **) &json_string, NULL) ;       \
      90             : }
      91             : 
      92             : #undef  LG_FREE_ALL
      93             : #define LG_FREE_ALL                                     \
      94             : {                                                       \
      95             :     LG_FREE_WORK ;                                      \
      96             :     LAGraph_Free ((void **) &collection, NULL) ;        \
      97             :     LAGraph_SFreeContents (&Contents, ncontents) ;      \
      98             : }
      99             : 
     100         208 : int LAGraph_SRead   // read a set of matrices from a *.lagraph file
     101             : (
     102             :     FILE *f,                            // file to read from
     103             :     // output
     104             :     char **collection_handle,           // name of collection
     105             :     LAGraph_Contents **Contents_handle, // array of contents
     106             :     GrB_Index *ncontents_handle,        // # of items in the Contents array
     107             :     char *msg
     108             : )
     109             : {
     110             : 
     111             :     //--------------------------------------------------------------------------
     112             :     // check inputs
     113             :     //--------------------------------------------------------------------------
     114             : 
     115         208 :     LG_CLEAR_MSG ;
     116         208 :     char *json_string = NULL ;
     117         208 :     json_val root = NULL ;
     118         208 :     char *collection = NULL ;
     119         208 :     LAGraph_Contents *Contents = NULL ;
     120         208 :     GrB_Index ncontents = 0 ;
     121             : 
     122         208 :     LG_ASSERT (collection_handle != NULL, GrB_NULL_POINTER) ;
     123         208 :     LG_ASSERT (Contents_handle != NULL, GrB_NULL_POINTER) ;
     124         208 :     LG_ASSERT (f != NULL, GrB_NULL_POINTER) ;
     125         208 :     LG_ASSERT (ncontents_handle != NULL, GrB_NULL_POINTER) ;
     126         208 :     (*collection_handle) = NULL ;
     127         208 :     (*Contents_handle) = NULL ;
     128         208 :     (*ncontents_handle) = 0 ;
     129             : 
     130             :     //--------------------------------------------------------------------------
     131             :     // load in a json string from the file
     132             :     //--------------------------------------------------------------------------
     133             : 
     134         208 :     size_t s = 256, k = 0 ;
     135         208 :     LAGRAPH_TRY (LAGraph_Malloc ((void **) &json_string, s, sizeof (char),
     136             :         msg)) ;
     137             :     while (true)
     138       43028 :     {
     139       43236 :         if (k == s)
     140             :         {
     141             :             // json_string is full; double its size
     142           4 :             LG_TRY (LAGraph_Realloc ((void **) &json_string, 2*s, s,
     143             :                 sizeof (char), msg)) ;
     144           4 :             s = 2*s ;
     145             :         }
     146             :         // get the next character from the file
     147       43236 :         int c = fgetc (f) ;
     148       43236 :         if (c == EOF || c == '\0')
     149             :         {
     150             :             // end of the JSON string; remainder is matrix/vector/text data
     151         208 :             json_string [k] = '\0' ;
     152         208 :             break ;
     153             :         }
     154       43028 :         json_string [k++] = (char) c ;
     155             :     }
     156             : 
     157             :     //--------------------------------------------------------------------------
     158             :     // parse the json string and free it
     159             :     //--------------------------------------------------------------------------
     160             : 
     161         208 :     root = json_parse (json_string, k) ;
     162         208 :     LG_ASSERT (root != NULL, GrB_OUT_OF_MEMORY) ;
     163         208 :     LAGraph_Free ((void **) &json_string, NULL) ;
     164             : 
     165             :     //--------------------------------------------------------------------------
     166             :     // process the JSON header
     167             :     //--------------------------------------------------------------------------
     168             : 
     169         208 :     json_obj obj = json_value_as_object (root) ;
     170         208 :     json_o o = obj->start ;
     171         208 :     json_a a = NULL ;
     172         208 :     json_arr arr = NULL ;
     173         208 :     json_str str = NULL ;
     174             : 
     175             :     //--------------------------------------------------------------------------
     176             :     // check LAGraph version
     177             :     //--------------------------------------------------------------------------
     178             : 
     179         208 :     arr = json_value_as_array (o->value) ;
     180             :     int lagraph_version [3] ;
     181         208 :     int result = get_int_array_3 (arr, lagraph_version, msg) ;
     182         208 :     OK (result == GrB_SUCCESS) ;
     183         208 :     OK (VER (lagraph_version [0], lagraph_version [1], lagraph_version [2])
     184             :      <= VER (LAGRAPH_VERSION_MAJOR, LAGRAPH_VERSION_MINOR,
     185             :              LAGRAPH_VERSION_UPDATE)) ;
     186             : 
     187             :     //--------------------------------------------------------------------------
     188             :     // check GraphBLAS library name and version
     189             :     //--------------------------------------------------------------------------
     190             : 
     191         208 :     o = o->next ;
     192         208 :     OK (STRMATCH (o->name->string, "GraphBLAS")) ;
     193         208 :     arr = json_value_as_array (o->value) ;
     194         208 :     OK (arr->length == 2) ;
     195         208 :     a = arr->start ;
     196         208 :     str = json_value_as_string (a->value) ;
     197             :     #if LAGRAPH_SUITESPARSE
     198         208 :     OK (STRMATCH (str->string, "SuiteSparse:GraphBLAS")) ;
     199             :     #else
     200             :     OK (STRMATCH (str->string, "vanilla")) ;
     201             :     #endif
     202         208 :     a = a->next ;
     203         208 :     arr = json_value_as_array (a->value) ;
     204             : 
     205             :     int graphblas_version [3] ;
     206         208 :     result = get_int_array_3 (arr, graphblas_version, msg) ;
     207         208 :     OK (result == GrB_SUCCESS) ;
     208         208 :     uint64_t library_version =
     209         208 :         VER (graphblas_version [0],
     210             :              graphblas_version [1],
     211             :              graphblas_version [2]) ;
     212             :     #if LAGRAPH_SUITESPARSE
     213         208 :     OK (library_version <= GxB_IMPLEMENTATION) ;
     214             :     #else
     215             :     OK (library_version <= VER (1,0,0)) ;
     216             :     #endif
     217             : 
     218             :     //--------------------------------------------------------------------------
     219             :     // get the contents and the name of the collection
     220             :     //--------------------------------------------------------------------------
     221             : 
     222         208 :     o = o->next ;
     223         208 :     OK (o->value->type == json_type_array) ;
     224         208 :     size_t len = o->name->string_size ;
     225         208 :     LG_TRY (LAGraph_Calloc ((void **) &collection, len+1, sizeof (char), msg)) ;
     226         208 :     strncpy (collection, o->name->string, len) ;
     227             : 
     228             :     //--------------------------------------------------------------------------
     229             :     // iterate over the contents
     230             :     //--------------------------------------------------------------------------
     231             : 
     232         208 :     arr = json_value_as_array (o->value) ;
     233         208 :     OK (arr != NULL) ;
     234         208 :     a = arr->start ;
     235         208 :     len = arr->length ;
     236             :     // allocate an Contents array of size len to hold the contents
     237         208 :     LG_TRY (LAGraph_Calloc ((void **) &Contents, len, sizeof (LAGraph_Contents),
     238             :         msg)) ;
     239             : 
     240         464 :     for (int i = 0 ; i < len && a != NULL ; i++, a = a->next)
     241             :     {
     242             : 
     243             :         //----------------------------------------------------------------------
     244             :         // get the next item
     245             :         //----------------------------------------------------------------------
     246             : 
     247         464 :         if (a->value->type == json_type_null) break ;
     248         258 :         ncontents++ ;
     249         258 :         LAGraph_Contents *Item = &(Contents [i]) ;
     250         258 :         OK (a != NULL) ;
     251         258 :         OK (a->value->type == json_type_object) ;
     252         258 :         json_obj obj = json_value_as_object (a->value) ;
     253         258 :         OK (obj != NULL) ;
     254         258 :         json_o o = obj->start ;
     255         258 :         OK (o != NULL) ;
     256         258 :         OK (o->value->type == json_type_string) ;
     257         258 :         int len = obj->length ;
     258         258 :         OK (len == 3) ;
     259             : 
     260             :         //----------------------------------------------------------------------
     261             :         // parse the item kind: matrix, vector, or ascii text
     262             :         //----------------------------------------------------------------------
     263             : 
     264         258 :         if (STRMATCH (o->name->string, "GrB_Matrix"))
     265             :         {
     266         256 :             Item->kind = LAGraph_matrix_kind ;
     267             :         }
     268             : #if 0
     269             :         // todo: handle vectors and text
     270             :         else if (STRMATCH (o->name->string, "GrB_Vector"))
     271             :         {
     272             :             Item->kind = LAGraph_vector_kind ;
     273             :         }
     274             :         else if (STRMATCH (o->name->string, "text"))
     275             :         {
     276             :             Item->kind = LAGraph_text_kind ;
     277             :         }
     278             : #endif
     279             :         else
     280             :         {
     281           2 :             Item->kind = LAGraph_unknown_kind ;
     282           2 :             OK (false) ;
     283             :         }
     284             : 
     285             :         //----------------------------------------------------------------------
     286             :         // parse the item name
     287             :         //----------------------------------------------------------------------
     288             : 
     289         256 :         json_str str = json_value_as_string (o->value) ;
     290         256 :         strncpy (Item->name, str->string, LAGRAPH_MAX_NAME_LEN) ;
     291         256 :         Item->name [LAGRAPH_MAX_NAME_LEN+1] = '\0' ;
     292         256 :         OK (str != NULL) ;
     293         256 :         o = o->next ;
     294         256 :         str = json_value_as_string (o->value) ;
     295         256 :         OK (str != NULL) ;
     296             : 
     297             :         //----------------------------------------------------------------------
     298             :         // parse the text compression method, or matrix/vector type
     299             :         //----------------------------------------------------------------------
     300             : 
     301             : #if 0
     302             :         // todo: handle text, with optional compression
     303             :         if (Item->kind == LAGraph_text_kind)
     304             :         {
     305             :             // text, uncompressed or compressed
     306             :             int c ;
     307             :             if      (STRMATCH (str->string, "none"   )) c = -1 ;
     308             :             else if (STRMATCH (str->string, "default")) c = 0 ;
     309             :             else if (STRMATCH (str->string, "lz4"    )) c = 1000 ;
     310             :             else if (STRMATCH (str->string, "lz4hc:0")) c = 2000 ;
     311             :             else if (STRMATCH (str->string, "lz4hc:1")) c = 2001 ;
     312             :             else if (STRMATCH (str->string, "lz4hc:2")) c = 2002 ;
     313             :             else if (STRMATCH (str->string, "lz4hc:3")) c = 2003 ;
     314             :             else if (STRMATCH (str->string, "lz4hc:4")) c = 2004 ;
     315             :             else if (STRMATCH (str->string, "lz4hc:5")) c = 2005 ;
     316             :             else if (STRMATCH (str->string, "lz4hc:6")) c = 2006 ;
     317             :             else if (STRMATCH (str->string, "lz4hc:7")) c = 2007 ;
     318             :             else if (STRMATCH (str->string, "lz4hc:8")) c = 2008 ;
     319             :             else if (STRMATCH (str->string, "lz4hc:9")) c = 2009 ;
     320             :             else OK (false) ;
     321             :             Item->type_name [0] = '\0' ;    // or set to "char"?
     322             :             Item->compression = c ;
     323             :         }
     324             :         else
     325             : #endif
     326             :         {
     327             :             // serialized matrix or vector
     328         256 :             strncpy (Item->type_name, str->string, LAGRAPH_MAX_NAME_LEN) ;
     329         256 :             Item->type_name [LAGRAPH_MAX_NAME_LEN+1] = '\0' ;
     330         256 :             Item->compression = 0 ;
     331             :         }
     332             : 
     333             :         //----------------------------------------------------------------------
     334             :         // parse the item size
     335             :         //----------------------------------------------------------------------
     336             : 
     337         256 :         o = o->next ;
     338         256 :         json_num num = json_value_as_number (o->value) ;
     339         256 :         OK (num != NULL) ;
     340         256 :         Item->blob_size = (GrB_Index) strtoll (num->number, NULL, 0) ;
     341             : 
     342             :         //----------------------------------------------------------------------
     343             :         // allocate the blob and read it from the file
     344             :         //----------------------------------------------------------------------
     345             : 
     346         256 :         LAGRAPH_TRY (LAGraph_Malloc ((void **) &(Item->blob), Item->blob_size,
     347             :             sizeof (uint8_t), msg)) ;
     348         256 :         size_t bytes_read = fread (Item->blob, sizeof (uint8_t),
     349             :             Item->blob_size, f) ;
     350         256 :         OK (bytes_read == Item->blob_size) ;
     351             :     }
     352             : 
     353             :     // todo: optional components will be needed for matrices from
     354             :     // sparse.tamu.edu (matrix id, author, editor, title, etc)
     355             : #if 0
     356             :     // optional components
     357             :     o = o->next ;
     358             :     while (o != NULL)
     359             :     {
     360             :         printf ("other: [%s]\n", o->name->string) ;
     361             :         o = o->next ;
     362             :     }
     363             : #endif
     364             : 
     365             :     //--------------------------------------------------------------------------
     366             :     // free workspace and return result
     367             :     //--------------------------------------------------------------------------
     368             : 
     369         206 :     LG_FREE_WORK  ;
     370         206 :     (*collection_handle) = collection ;
     371         206 :     (*Contents_handle) = Contents ;
     372         206 :     (*ncontents_handle) = ncontents ;
     373         206 :     return (GrB_SUCCESS) ;
     374             : }

Generated by: LCOV version 1.14