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 : }
|