| 225 | } |
| 226 | |
| 227 | void RGLFile::saveFile(std::ofstream& out) const |
| 228 | { |
| 229 | out.write("tensor_file", 12); |
| 230 | |
| 231 | // Write header. |
| 232 | uint8_t version[] = {1, 0}; |
| 233 | write(out, version, 2); |
| 234 | write(out, uint32_t(mFields.size())); |
| 235 | |
| 236 | // Compute size of header+field descriptions. |
| 237 | uint64_t writeOffset = 18; |
| 238 | for (const auto& field : mFields) |
| 239 | { |
| 240 | writeOffset += 13 + field.name.size() + 8 * field.dim; |
| 241 | } |
| 242 | |
| 243 | // RGL data blocks seem to be aligned at 8 byte boundaries. |
| 244 | auto alignAddress = [&](uint64_t a) { return ((a + 7) / 8) * 8; }; |
| 245 | uint64_t alignedOffset = alignAddress(writeOffset); |
| 246 | uint64_t headerPadding = alignedOffset - writeOffset; |
| 247 | |
| 248 | // Write fields and keep track of where data blocks will start via alignedOffset. |
| 249 | for (const auto& field : mFields) |
| 250 | { |
| 251 | write(out, uint16_t(field.name.size())); |
| 252 | write(out, field.name.data(), field.name.size()); |
| 253 | write(out, uint16_t(field.dim)); |
| 254 | write(out, uint8_t(field.type)); |
| 255 | write(out, alignedOffset); |
| 256 | write(out, field.shape.get(), field.dim); |
| 257 | alignedOffset += fieldSize(field.type) * field.numElems; |
| 258 | alignedOffset = alignAddress(alignedOffset); |
| 259 | } |
| 260 | // Pad with zeros to get correct alignment. |
| 261 | uint8_t zeros[8] = {0}; |
| 262 | write(out, zeros, headerPadding); |
| 263 | for (size_t i = 0; i < mFields.size(); ++i) |
| 264 | { |
| 265 | size_t length = mFields[i].numElems * fieldSize(mFields[i].type); |
| 266 | write(out, mFields[i].data.get(), length); |
| 267 | write(out, zeros, alignAddress(length) - length); |
| 268 | } |
| 269 | } |
| 270 | } |