25 NpyArray(
const std::vector<size_t>& _shape,
size_t _word_size,
bool _fortran_order) :
38 return reinterpret_cast<T*
>(&(*data_holder)[0]);
43 return reinterpret_cast<T*
>(&(*data_holder)[0]);
48 const T* p = data<T>();
49 return std::vector<T>(p, p+
num_vals);
63 using npz_t = std::map<std::string, NpyArray>;
66 char map_type(
const std::type_info& t);
67 template<
typename T> std::vector<char>
create_npy_header(
const std::vector<size_t>& shape);
68 void parse_npy_header(FILE* fp,
size_t& word_size, std::vector<size_t>& shape,
bool& fortran_order);
69 void parse_npy_header(
unsigned char* buffer,
size_t& word_size, std::vector<size_t>& shape,
bool& fortran_order);
70 void parse_zip_footer(FILE* fp, uint16_t& nrecs,
size_t& global_header_size,
size_t& global_header_offset);
75 template<
typename T> std::vector<char>&
operator+=(std::vector<char>& lhs,
const T rhs) {
77 for(
size_t byte = 0;
byte <
sizeof(T);
byte++) {
78 char val = *((
char*)&rhs+
byte);
84 template<> std::vector<char>&
operator+=(std::vector<char>& lhs,
const std::string rhs);
85 template<> std::vector<char>&
operator+=(std::vector<char>& lhs,
const char* rhs);
88 template<
typename T>
void npy_save(std::string fname,
const T* data,
const std::vector<size_t> shape, std::string mode =
"w") {
90 std::vector<size_t> true_data_shape;
92 if(mode ==
"a") fp = fopen(fname.c_str(),
"r+b");
99 assert(!fortran_order);
101 if(word_size !=
sizeof(T)) {
102 std::cout<<
"libnpy error: "<<fname<<
" has word size "<<word_size<<
" but npy_save appending data sized "<<
sizeof(T)<<
"\n";
103 assert( word_size ==
sizeof(T) );
105 if(true_data_shape.size() != shape.size()) {
106 std::cout<<
"libnpy error: npy_save attempting to append misdimensioned data to "<<fname<<
"\n";
107 assert(true_data_shape.size() != shape.size());
110 for(
size_t i = 1; i < shape.size(); i++) {
111 if(shape[i] != true_data_shape[i]) {
112 std::cout<<
"libnpy error: npy_save attempting to append misshaped data to "<<fname<<
"\n";
113 assert(shape[i] == true_data_shape[i]);
116 true_data_shape[0] += shape[0];
119 fp = fopen(fname.c_str(),
"wb");
120 true_data_shape = shape;
123 std::vector<char> header = create_npy_header<T>(true_data_shape);
124 size_t nels = std::accumulate(shape.begin(),shape.end(),1,std::multiplies<size_t>());
126 fseek(fp,0,SEEK_SET);
127 fwrite(&header[0],
sizeof(
char),header.size(),fp);
128 fseek(fp,0,SEEK_END);
129 fwrite(data,
sizeof(T),nels,fp);
133 template<
typename T>
void npz_save(std::string zipname, std::string fname,
const T* data,
const std::vector<size_t>& shape, std::string mode =
"w")
141 size_t global_header_offset = 0;
142 std::vector<char> global_header;
144 if(mode ==
"a") fp = fopen(zipname.c_str(),
"r+b");
151 size_t global_header_size;
153 fseek(fp,global_header_offset,SEEK_SET);
154 global_header.resize(global_header_size);
155 size_t res = fread(&global_header[0],
sizeof(
char),global_header_size,fp);
156 if(res != global_header_size){
157 throw std::runtime_error(
"npz_save: header read error while adding to existing zip");
159 fseek(fp,global_header_offset,SEEK_SET);
162 fp = fopen(zipname.c_str(),
"wb");
165 std::vector<char> npy_header = create_npy_header<T>(shape);
167 size_t nels = std::accumulate(shape.begin(),shape.end(),1,std::multiplies<size_t>());
168 size_t nbytes = nels*
sizeof(T) + npy_header.size();
171 uint32_t crc = crc32(0L,(uint8_t*)&npy_header[0],npy_header.size());
172 crc = crc32(crc,(uint8_t*)data,nels*
sizeof(T));
175 std::vector<char> local_header;
176 local_header +=
"PK";
177 local_header += (uint16_t) 0x0403;
178 local_header += (uint16_t) 20;
179 local_header += (uint16_t) 0;
180 local_header += (uint16_t) 0;
181 local_header += (uint16_t) 0;
182 local_header += (uint16_t) 0;
183 local_header += (uint32_t) crc;
184 local_header += (uint32_t) nbytes;
185 local_header += (uint32_t) nbytes;
186 local_header += (uint16_t) fname.size();
187 local_header += (uint16_t) 0;
188 local_header += fname;
191 global_header +=
"PK";
192 global_header += (uint16_t) 0x0201;
193 global_header += (uint16_t) 20;
194 global_header.insert(global_header.end(),local_header.begin()+4,local_header.begin()+30);
195 global_header += (uint16_t) 0;
196 global_header += (uint16_t) 0;
197 global_header += (uint16_t) 0;
198 global_header += (uint32_t) 0;
199 global_header += (uint32_t) global_header_offset;
200 global_header += fname;
203 std::vector<char> footer;
205 footer += (uint16_t) 0x0605;
206 footer += (uint16_t) 0;
207 footer += (uint16_t) 0;
208 footer += (uint16_t) (nrecs+1);
209 footer += (uint16_t) (nrecs+1);
210 footer += (uint32_t) global_header.size();
211 footer += (uint32_t) (global_header_offset + nbytes + local_header.size());
212 footer += (uint16_t) 0;
215 fwrite(&local_header[0],
sizeof(
char),local_header.size(),fp);
216 fwrite(&npy_header[0],
sizeof(
char),npy_header.size(),fp);
217 fwrite(data,
sizeof(T),nels,fp);
218 fwrite(&global_header[0],
sizeof(
char),global_header.size(),fp);
219 fwrite(&footer[0],
sizeof(
char),footer.size(),fp);
223 template<
typename T>
void npy_save(std::string fname,
const std::vector<T> data, std::string mode =
"w") {
224 std::vector<size_t> shape;
225 shape.push_back(data.size());
226 npy_save(fname, &data[0], shape, mode);
229 template<
typename T>
void npz_save(std::string zipname, std::string fname,
const std::vector<T> data, std::string mode =
"w") {
230 std::vector<size_t> shape;
231 shape.push_back(data.size());
232 npz_save(zipname, fname, &data[0], shape, mode);
237 std::vector<char> dict;
238 dict +=
"{'descr': '";
241 dict += std::to_string(
sizeof(T));
242 dict +=
"', 'fortran_order': False, 'shape': (";
243 dict += std::to_string(shape[0]);
244 for(
size_t i = 1;i < shape.size();i++) {
246 dict += std::to_string(shape[i]);
248 if(shape.size() == 1) dict +=
",";
251 int remainder = 16 - (10 + dict.size()) % 16;
252 dict.insert(dict.end(),remainder,
' ');
255 std::vector<char> header;
256 header += (char) 0x93;
258 header += (char) 0x01;
259 header += (char) 0x00;
260 header += (uint16_t) dict.size();
261 header.insert(header.end(),dict.begin(),dict.end());