1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
|
//------------------------------------------------------------------------------
// GB_deserialize: decompress and deserialize a blob into a GrB_Matrix
//------------------------------------------------------------------------------
// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2022, All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//------------------------------------------------------------------------------
// A parallel decompression of a serialized blob into a GrB_Matrix.
#include "GB.h"
#include "GB_serialize.h"
#define GB_FREE_ALL \
{ \
GB_Matrix_free (&T) ; \
GB_Matrix_free (&C) ; \
}
GrB_Info GB_deserialize // deserialize a matrix from a blob
(
// output:
GrB_Matrix *Chandle, // output matrix created from the blob
// input:
GrB_Type type_expected, // type expected (NULL for any built-in)
const GB_void *blob, // serialized matrix
size_t blob_size, // size of the blob
GB_Context Context
)
{
//--------------------------------------------------------------------------
// check inputs
//--------------------------------------------------------------------------
GrB_Info info ;
ASSERT (blob != NULL && Chandle != NULL) ;
(*Chandle) = NULL ;
GrB_Matrix C = NULL, T = NULL ;
//--------------------------------------------------------------------------
// read the content of the header (160 bytes)
//--------------------------------------------------------------------------
size_t s = 0 ;
if (blob_size < GB_BLOB_HEADER_SIZE)
{
// blob is invalid
return (GrB_INVALID_OBJECT) ;
}
GB_BLOB_READ (blob_size2, uint64_t) ;
GB_BLOB_READ (typecode, int32_t) ;
uint64_t blob_size1 = (uint64_t) blob_size ;
if (blob_size1 != blob_size2
|| typecode < GB_BOOL_code || typecode > GB_UDT_code
|| (typecode == GB_UDT_code &&
blob_size < GB_BLOB_HEADER_SIZE + GxB_MAX_NAME_LEN))
{
// blob is invalid
return (GrB_INVALID_OBJECT) ;
}
GB_BLOB_READ (version, int32_t) ;
GB_BLOB_READ (vlen, int64_t) ;
GB_BLOB_READ (vdim, int64_t) ;
GB_BLOB_READ (nvec, int64_t) ;
GB_BLOB_READ (nvec_nonempty, int64_t) ; ASSERT (nvec_nonempty >= 0) ;
GB_BLOB_READ (nvals, int64_t) ;
GB_BLOB_READ (typesize, int64_t) ;
GB_BLOB_READ (Cp_len, int64_t) ;
GB_BLOB_READ (Ch_len, int64_t) ;
GB_BLOB_READ (Cb_len, int64_t) ;
GB_BLOB_READ (Ci_len, int64_t) ;
GB_BLOB_READ (Cx_len, int64_t) ;
GB_BLOB_READ (hyper_switch, float) ;
GB_BLOB_READ (bitmap_switch, float) ;
GB_BLOB_READ (sparsity_control, int32_t) ;
GB_BLOB_READ (sparsity_iso_csc, int32_t) ;
GB_BLOB_READ (Cp_nblocks, int32_t) ; GB_BLOB_READ (Cp_method, int32_t) ;
GB_BLOB_READ (Ch_nblocks, int32_t) ; GB_BLOB_READ (Ch_method, int32_t) ;
GB_BLOB_READ (Cb_nblocks, int32_t) ; GB_BLOB_READ (Cb_method, int32_t) ;
GB_BLOB_READ (Ci_nblocks, int32_t) ; GB_BLOB_READ (Ci_method, int32_t) ;
GB_BLOB_READ (Cx_nblocks, int32_t) ; GB_BLOB_READ (Cx_method, int32_t) ;
int32_t sparsity = sparsity_iso_csc / 4 ;
bool iso = ((sparsity_iso_csc & 2) == 2) ;
bool is_csc = ((sparsity_iso_csc & 1) == 1) ;
//--------------------------------------------------------------------------
// determine the matrix type
//--------------------------------------------------------------------------
GB_Type_code ccode = (GB_Type_code) typecode ;
GrB_Type ctype = GB_code_type (ccode, type_expected) ;
// ensure the type has the right size
if (ctype == NULL || ctype->size != typesize)
{
// blob is invalid; type is missing or the wrong size
return (GrB_DOMAIN_MISMATCH) ;
}
if (ccode == GB_UDT_code)
{
// user-defined name is 128 bytes, if present
// ensure the user-defined type has the right name
ASSERT (ctype == type_expected) ;
if (strncmp ((const char *) (blob + s), ctype->name,
GxB_MAX_NAME_LEN) != 0)
{
// blob is invalid
return (GrB_DOMAIN_MISMATCH) ;
}
s += GxB_MAX_NAME_LEN ;
}
else if (type_expected != NULL && ctype != type_expected)
{
// built-in type must match type_expected
// blob is invalid
return (GrB_DOMAIN_MISMATCH) ;
}
//--------------------------------------------------------------------------
// get the compressed block sizes from the blob for each array
//--------------------------------------------------------------------------
GB_BLOB_READS (Cp_Sblocks, Cp_nblocks) ;
GB_BLOB_READS (Ch_Sblocks, Ch_nblocks) ;
GB_BLOB_READS (Cb_Sblocks, Cb_nblocks) ;
GB_BLOB_READS (Ci_Sblocks, Ci_nblocks) ;
GB_BLOB_READS (Cx_Sblocks, Cx_nblocks) ;
//--------------------------------------------------------------------------
// allocate the output matrix C
//--------------------------------------------------------------------------
// allocate the matrix with info from the header
GB_OK (GB_new (&C, // new header (C is NULL on input)
ctype, vlen, vdim, GB_Ap_null, is_csc,
sparsity, hyper_switch, nvec, Context)) ;
C->nvec = nvec ;
C->nvec_nonempty = nvec_nonempty ;
C->nvals = nvals ; // revised below
C->bitmap_switch = bitmap_switch ;
C->sparsity_control = sparsity_control ;
C->iso = iso ;
// the matrix has no pending work
ASSERT (C->Pending == NULL) ;
ASSERT (C->nzombies == 0) ;
ASSERT (!C->jumbled) ;
//--------------------------------------------------------------------------
// decompress each array (Cp, Ch, Cb, Ci, and Cx)
//--------------------------------------------------------------------------
switch (sparsity)
{
case GxB_HYPERSPARSE :
// decompress Cp, Ch, and Ci
GB_OK (GB_deserialize_from_blob ((GB_void **) &(C->p), &(C->p_size),
Cp_len, blob, blob_size, Cp_Sblocks, Cp_nblocks, Cp_method,
&s, Context)) ;
GB_OK (GB_deserialize_from_blob ((GB_void **) &(C->h), &(C->h_size),
Ch_len, blob, blob_size, Ch_Sblocks, Ch_nblocks, Ch_method,
&s, Context)) ;
GB_OK (GB_deserialize_from_blob ((GB_void **) &(C->i), &(C->i_size),
Ci_len, blob, blob_size, Ci_Sblocks, Ci_nblocks, Ci_method,
&s, Context)) ;
break ;
case GxB_SPARSE :
// decompress Cp and Ci
GB_OK (GB_deserialize_from_blob ((GB_void **) &(C->p), &(C->p_size),
Cp_len, blob, blob_size, Cp_Sblocks, Cp_nblocks, Cp_method,
&s, Context)) ;
GB_OK (GB_deserialize_from_blob ((GB_void **) &(C->i), &(C->i_size),
Ci_len, blob, blob_size, Ci_Sblocks, Ci_nblocks, Ci_method,
&s, Context)) ;
break ;
case GxB_BITMAP :
// decompress Cb
GB_OK (GB_deserialize_from_blob ((GB_void **) &(C->b), &(C->b_size),
Cb_len, blob, blob_size, Cb_Sblocks, Cb_nblocks, Cb_method,
&s, Context)) ;
break ;
case GxB_FULL :
break ;
default: ;
}
// decompress Cx
GB_OK (GB_deserialize_from_blob ((GB_void **) &(C->x), &(C->x_size), Cx_len,
blob, blob_size, Cx_Sblocks, Cx_nblocks, Cx_method, &s, Context)) ;
if (C->p != NULL)
{
// C is sparse or hypersparse. v7.2.1 and later have the new C->nvals
// value inside the blob already. The blob prior to v7.2.1 had nvals
// of zero for sparse and hypersparse matrices. Set it here to the
// correct value, so that blobs written by v7.2.0 and earlier can be
// read by v7.2.1 and later. For both variants, ignore nvals in the
// blob and use Cp [nvec] when C is sparse or hypersparse.
ASSERT (GB_IMPLIES (version > GxB_VERSION (7,2,0),
C->nvals == C->p [C->nvec])) ;
C->nvals = C->p [C->nvec] ;
}
C->magic = GB_MAGIC ;
//--------------------------------------------------------------------------
// return result
//--------------------------------------------------------------------------
(*Chandle) = C ;
ASSERT_MATRIX_OK (*Chandle, "Final result from deserialize", GB0) ;
return (GrB_SUCCESS) ;
}
|