| 347 | |
| 348 | |
| 349 | inline header_t parse_header(std::string header) { |
| 350 | /* |
| 351 | The first 6 bytes are a magic string: exactly "x93NUMPY". |
| 352 | The next 1 byte is an unsigned byte: the major version number of the file format, e.g. x01. |
| 353 | The next 1 byte is an unsigned byte: the minor version number of the file format, e.g. x00. Note: the version of the file format is not tied to the version of the numpy package. |
| 354 | The next 2 bytes form a little-endian unsigned short int: the length of the header data HEADER_LEN. |
| 355 | The next HEADER_LEN bytes form the header data describing the array's format. It is an ASCII string which contains a Python literal expression of a dictionary. It is terminated by a newline ('n') and padded with spaces ('x20') to make the total length of the magic string + 4 + HEADER_LEN be evenly divisible by 16 for alignment purposes. |
| 356 | The dictionary contains three keys: |
| 357 | |
| 358 | "descr" : dtype.descr |
| 359 | An object that can be passed as an argument to the numpy.dtype() constructor to create the array's dtype. |
| 360 | "fortran_order" : bool |
| 361 | Whether the array data is Fortran-contiguous or not. Since Fortran-contiguous arrays are a common form of non-C-contiguity, we allow them to be written directly to disk for efficiency. |
| 362 | "shape" : tuple of int |
| 363 | The shape of the array. |
| 364 | For repeatability and readability, this dictionary is formatted using pprint.pformat() so the keys are in alphabetic order. |
| 365 | */ |
| 366 | |
| 367 | // remove trailing newline |
| 368 | if (header.back() != '\n') |
| 369 | throw std::runtime_error("invalid header"); |
| 370 | header.pop_back(); |
| 371 | |
| 372 | // parse the dictionary |
| 373 | std::vector <std::string> keys{"descr", "fortran_order", "shape"}; |
| 374 | auto dict_map = npy::pyparse::parse_dict(header, keys); |
| 375 | |
| 376 | if (dict_map.size() == 0) |
| 377 | throw std::runtime_error("invalid dictionary in header"); |
| 378 | |
| 379 | std::string descr_s = dict_map["descr"]; |
| 380 | std::string fortran_s = dict_map["fortran_order"]; |
| 381 | std::string shape_s = dict_map["shape"]; |
| 382 | |
| 383 | std::string descr = npy::pyparse::parse_str(descr_s); |
| 384 | dtype_t dtype = parse_descr(descr); |
| 385 | |
| 386 | // convert literal Python bool to C++ bool |
| 387 | bool fortran_order = npy::pyparse::parse_bool(fortran_s); |
| 388 | |
| 389 | // parse the shape tuple |
| 390 | auto shape_v = npy::pyparse::parse_tuple(shape_s); |
| 391 | |
| 392 | std::vector <ndarray_len_t> shape; |
| 393 | for (auto item : shape_v) { |
| 394 | ndarray_len_t dim = static_cast<ndarray_len_t>(std::stoul(item)); |
| 395 | shape.push_back(dim); |
| 396 | } |
| 397 | |
| 398 | return {dtype, fortran_order, shape}; |
| 399 | } |
| 400 | |
| 401 | |
| 402 | inline std::string |
no test coverage detected