DNDSR 0.1.0.dev1+gcd065ad
Distributed Numeric Data Structure for CFV
Loading...
Searching...
No Matches
SerializerJSON.cpp
Go to the documentation of this file.
1#include "SerializerJSON.hpp"
2#include <algorithm>
3#include <string>
4#include "base64_rfc4648.hpp"
5#include <zlib.h>
6#include <fmt/core.h>
7#include <set>
8
9namespace DNDS::Serializer
10{
11
12 /**
13 * @brief returns good path and if the path is absolute
14 */
15 bool processPath(std::vector<std::string> &pth)
16 {
17 bool ifAbs = pth.empty() || pth[0].empty();
18 pth.erase(
19 std::remove_if(pth.begin(), pth.end(), [](const std::string &v)
20 { return v.empty(); }), // only keep non-zero sized path names
21 pth.end());
22
23 return ifAbs;
24 }
25
26 std::string constructPath(std::vector<std::string> &pth)
27 {
28 std::string ret;
29 for (auto &name : pth)
30 ret.append(std::string("/") + name);
31 return ret;
32 }
33
34 void SerializerJSON::OpenFile(const std::string &fName, bool read)
35 {
36 DNDS_assert(!fileStream.is_open());
37 reading = read;
38 if (read)
39 fileStream.open(fName, std::ios::in);
40 else
41 fileStream.open(fName, std::ios::out);
42 DNDS_assert_info(fileStream.is_open(), fmt::format(" attempted to {} file [{}]", read ? "read" : "write", fName));
43
44 if (reading)
45 fileStream >> jObj;
46 cP = "";
47 }
53 {
54 // DNDS_assert(fileStream.is_open());
55 if (!reading && bool(fileStream))
56 fileStream << jObj;
57 fileStream.close();
58 cPathSplit.clear();
59 dedupClear();
60 jObj.clear();
61 }
62 void SerializerJSON::CreatePath(const std::string &p)
63 {
64 auto pth = splitSString(p, '/');
65 // std::cout << pth.size() << std::endl;
66 // std::cout << cP + constructPath(pth) << std::endl;
67 bool isAbs = processPath(pth);
68 if (isAbs)
69 jObj[nlohmann::json::json_pointer(constructPath(pth))] = nlohmann::json::object();
70 else
71 jObj[nlohmann::json::json_pointer(cP + constructPath(pth))] = nlohmann::json::object();
72 }
73 void SerializerJSON::GoToPath(const std::string &p)
74 {
75 auto pth = splitSString(p, '/');
76 bool isAbs = processPath(pth);
77 if (isAbs)
78 cPathSplit = std::move(pth);
79 else
80 for (auto &name : pth)
81 cPathSplit.push_back(name);
82 cP = constructPath(cPathSplit);
83 DNDS_assert(jObj[nlohmann::json::json_pointer(cP)].is_object());
84 }
86 {
87 return cP;
88 }
89
90 std::set<std::string> SerializerJSON::ListCurrentPath()
91 {
92 auto cPointer = nlohmann::json::json_pointer(cP);
93 auto v = jObj[cPointer];
94 DNDS_assert_info(v.is_object(), fmt::format("current path is not an object " + cP));
95 std::set<std::string> ret;
96 for (auto &[key, value] : v.items())
97 ret.insert(key);
98 return ret;
99 }
100
101 void SerializerJSON::WriteInt(const std::string &name, int v)
102 {
103 auto cPointer = nlohmann::json::json_pointer(cP);
104 jObj[cPointer][name] = v;
105 }
106 void SerializerJSON::WriteIndex(const std::string &name, index v)
107 {
108 auto cPointer = nlohmann::json::json_pointer(cP);
109 jObj[cPointer][name] = v;
110 }
111 void SerializerJSON::WriteReal(const std::string &name, real v)
112 {
113 auto cPointer = nlohmann::json::json_pointer(cP);
114 jObj[cPointer][name] = v;
115 }
116 void SerializerJSON::WriteIndexVector(const std::string &name, const std::vector<index> &v, ArrayGlobalOffset offset)
117 {
118 auto cPointer = nlohmann::json::json_pointer(cP);
119 jObj[cPointer][name] = v;
120 }
121 void SerializerJSON::WriteRowsizeVector(const std::string &name, const std::vector<rowsize> &v, ArrayGlobalOffset offset)
122 {
123 auto cPointer = nlohmann::json::json_pointer(cP);
124 jObj[cPointer][name] = v;
125 }
126 void SerializerJSON::WriteRealVector(const std::string &name, const std::vector<real> &v, ArrayGlobalOffset offset)
127 {
128 auto cPointer = nlohmann::json::json_pointer(cP);
129 jObj[cPointer][name] = v;
130 }
131 void SerializerJSON::WriteString(const std::string &name, const std::string &v)
132 {
133 auto cPointer = nlohmann::json::json_pointer(cP);
134 jObj[cPointer][name] = v;
135 }
137 {
138 auto cPointer = nlohmann::json::json_pointer(cP);
139 std::string refPath;
140 if (dedupLookup(v, refPath))
141 jObj[cPointer][name]["ref"] = refPath;
142 else
143 {
144 jObj[cPointer][name] = *v;
145 dedupRegister(v, cP + "/" + name);
146 }
147 }
149 {
150 auto cPointer = nlohmann::json::json_pointer(cP);
151 std::string refPath;
152 if (dedupLookup(v, refPath))
153 jObj[cPointer][name]["ref"] = refPath;
154 else
155 {
156 jObj[cPointer][name] = *v;
157 dedupRegister(v, cP + "/" + name);
158 }
159 }
160
161 void SerializerJSON::ReadInt(const std::string &name, int &v)
162 {
163 auto cPointer = nlohmann::json::json_pointer(cP);
164 DNDS_assert(jObj[cPointer][name].is_number_integer());
165 v = jObj[cPointer][name].get<std::remove_reference_t<decltype(v)>>();
166 }
167 void SerializerJSON::ReadIndex(const std::string &name, index &v)
168 {
169 auto cPointer = nlohmann::json::json_pointer(cP);
170 DNDS_assert(jObj[cPointer][name].is_number_integer());
171 v = jObj[cPointer][name].get<std::remove_reference_t<decltype(v)>>();
172 }
173 void SerializerJSON::ReadReal(const std::string &name, real &v)
174 {
175 auto cPointer = nlohmann::json::json_pointer(cP);
176 DNDS_assert(jObj[cPointer][name].is_number_float());
177 v = jObj[cPointer][name].get<std::remove_reference_t<decltype(v)>>();
178 }
179 void SerializerJSON::ReadIndexVector(const std::string &name, std::vector<index> &v, ArrayGlobalOffset &offset)
180 {
181 auto cPointer = nlohmann::json::json_pointer(cP);
182 DNDS_assert(jObj[cPointer][name].is_array());
183 v = jObj[cPointer][name].get<std::remove_reference_t<decltype(v)>>();
184 offset = ArrayGlobalOffset_Unknown;
185 }
186 void SerializerJSON::ReadRowsizeVector(const std::string &name, std::vector<rowsize> &v, ArrayGlobalOffset &offset)
187 {
188 auto cPointer = nlohmann::json::json_pointer(cP);
189 DNDS_assert(jObj[cPointer][name].is_array());
190 v = jObj[nlohmann::json::json_pointer(cP)][name].get<std::remove_reference_t<decltype(v)>>();
191 offset = ArrayGlobalOffset_Unknown;
192 }
193 void SerializerJSON::ReadRealVector(const std::string &name, std::vector<real> &v, ArrayGlobalOffset &offset)
194 {
195 auto cPointer = nlohmann::json::json_pointer(cP);
196 DNDS_assert(jObj[cPointer][name].is_array());
197 v = jObj[cPointer][name].get<std::remove_reference_t<decltype(v)>>();
198 offset = ArrayGlobalOffset_Unknown;
199 }
200 void SerializerJSON::ReadString(const std::string &name, std::string &v)
201 {
202 auto cPointer = nlohmann::json::json_pointer(cP);
203 DNDS_assert(jObj[cPointer][name].is_string());
204 v = jObj[cPointer][name].get<std::remove_reference_t<decltype(v)>>();
205 }
207 {
208 auto cPointer = nlohmann::json::json_pointer(cP);
209 using tValue = host_device_vector<index>;
210 std::string refPath;
211 if (jObj[cPointer][name].is_object() && !jObj[cPointer][name].is_array())
212 {
213 DNDS_assert(jObj[cPointer][name]["ref"].is_string());
214 refPath = jObj[cPointer][name]["ref"].get<std::string>();
215 }
216 else
217 {
218 refPath = cP + "/" + name;
219 }
220
221 if (pth_2_ssp.count(refPath))
222 {
223 v = *((ssp<tValue> *)(pth_2_ssp[refPath]));
224 }
225 else
226 {
227 DNDS_assert(jObj[nlohmann::json::json_pointer(refPath)].is_array());
228 // TODO: OPTIMIZE into direct read from json
229 auto v_temp = jObj[nlohmann::json::json_pointer(refPath)].get<std::vector<index>>();
230 v = std::make_shared<tValue>(v_temp); // vector's copy constructor
231 pth_2_ssp[refPath] = &v;
232 }
233 offset = ArrayGlobalOffset_Unknown;
234 }
236 {
237 auto cPointer = nlohmann::json::json_pointer(cP);
238 using tValue = host_device_vector<rowsize>;
239 std::string refPath;
240 if (jObj[cPointer][name].is_object() && !jObj[cPointer][name].is_array())
241 {
242 DNDS_assert(jObj[cPointer][name]["ref"].is_string());
243 refPath = jObj[cPointer][name]["ref"].get<std::string>();
244 }
245 else
246 {
247 refPath = cP + "/" + name;
248 }
249
250 if (pth_2_ssp.count(refPath))
251 {
252 v = *((ssp<tValue> *)(pth_2_ssp[refPath]));
253 }
254 else
255 {
256 DNDS_assert(jObj[nlohmann::json::json_pointer(refPath)].is_array());
257 // TODO: OPTIMIZE into direct read from json
258 auto v_temp = jObj[nlohmann::json::json_pointer(refPath)].get<std::vector<rowsize>>();
259 v = std::make_shared<tValue>(v_temp); // vector's copy constructor
260 pth_2_ssp[refPath] = &v;
261 }
262 offset = ArrayGlobalOffset_Unknown;
263 }
264 void SerializerJSON::WriteUint8Array(const std::string &name, const uint8_t *data, index size, ArrayGlobalOffset offset)
265 {
266 auto zlibCompressedSize = [&](index sizeC)
267 {
268 return sizeC + (sizeC + 999) / 1000 + 12; // form vtk
269 };
270 int compressLevel = this->deflateLevel;
271 auto zlibCompressData = [&](const uint8_t *buf, index sizeC)
272 {
273 std::vector<uint8_t> ret(zlibCompressedSize(sizeC));
274 uLongf retSize = ret.size();
275 auto ret_v = compress2(ret.data(), &retSize, buf, sizeC, compressLevel);
276 if (ret_v != Z_OK)
277 DNDS_assert_info(false, "compression failed");
278 ret.resize(retSize);
279 return ret;
280 };
281
282 auto cPointer = nlohmann::json::json_pointer(cP);
283 if (!useCodecOnUint8)
284 jObj[cPointer][name] = std::vector<uint8_t>(data, data + size);
285 else
286 {
287 jObj[cPointer][name]["size"] = size;
288 jObj[cPointer][name]["encoded"] = cppcodec::base64_rfc4648::encode(
289 zlibCompressData(data, size));
290 }
291 }
292 void SerializerJSON::ReadUint8Array(const std::string &name, uint8_t *data, index &size, ArrayGlobalOffset &offset)
293 {
294 auto cPointer = nlohmann::json::json_pointer(cP);
295 DNDS_assert(jObj[cPointer][name].is_object() || jObj[cPointer][name].is_array());
296 if (jObj[cPointer][name].is_array())
297 {
298 size = jObj[cPointer][name].size();
299 if (data != nullptr)
300 std::copy(jObj[cPointer][name].begin(), jObj[cPointer][name].end(), data);
301 }
302 else if (jObj[cPointer][name].is_object() &&
303 jObj[cPointer][name]["size"].is_number_integer() &&
304 jObj[cPointer][name]["encoded"].is_string())
305 {
306 size = jObj[cPointer][name]["size"];
307 auto &dataIn = jObj[cPointer][name]["encoded"].get_ref<nlohmann::json::string_t &>();
308 if (data != nullptr)
309 {
310 std::vector<uint8_t> decodedData;
311 cppcodec::base64_rfc4648::decode(decodedData, dataIn);
312 std::vector<uint8_t> decodedDataUncompress(size);
313 uLongf sizeU{(uLongf)size};
314 auto ret = uncompress(decodedDataUncompress.data(), &sizeU, decodedData.data(), decodedData.size());
315 DNDS_assert_info(ret == Z_OK, "zlib uncompress failed");
316 DNDS_assert_info(sizeU == size, "zlib uncompress failed");
317 // DNDS_assert(decodedData.size() == size);
318 std::copy(decodedDataUncompress.begin(), decodedDataUncompress.end(), data);
319 }
320 }
321 else
322 {
323 DNDS_assert(false);
324 }
325 offset = ArrayGlobalOffset_Unknown;
326 }
327} // namespace DNDS::Serializer
#define DNDS_assert_info(expr, info)
Debug-only assertion with an extra std::string info message.
Definition Errors.hpp:113
#define DNDS_assert(expr)
Debug-only assertion (compiled out when DNDS_NDEBUG is defined). Prints the expression + file/line + ...
Definition Errors.hpp:108
Per-rank JSON serializer implementing the SerializerBase interface.
Describes one rank's window into a globally-distributed dataset.
void dedupRegister(const ssp< T > &v, const std::string &path)
Register a shared pointer after writing its data.
bool dedupLookup(const ssp< T > &v, std::string &outPath)
Check if a shared pointer was already written; if so return its path.
std::map< std::string, void * > pth_2_ssp
Reverse map for read-side dedup: path -> raw pointer to the ssp local variable.
void dedupClear()
Clear all dedup state (call on CloseFile).
void ReadIndexVector(const std::string &name, std::vector< index > &v, ArrayGlobalOffset &offset) override
void ReadSharedIndexVector(const std::string &name, ssp< host_device_vector< index > > &v, ArrayGlobalOffset &offset) override
void ReadString(const std::string &name, std::string &v) override
Read a UTF-8 string into v.
void ReadRealVector(const std::string &name, std::vector< real > &v, ArrayGlobalOffset &offset) override
std::set< std::string > ListCurrentPath() override
Names of direct children of the current path.
std::string GetCurrentPath() override
String form of the current path.
void CloseFile() override
Close the backing file, flushing buffers.
void WriteSharedRowsizeVector(const std::string &name, const ssp< host_device_vector< rowsize > > &v, ArrayGlobalOffset offset) override
Write a shared rowsize vector; deduplicated across multiple writes.
void WriteString(const std::string &name, const std::string &v) override
Write a UTF-8 string under name.
void OpenFile(const std::string &fName, bool read) override
Open a backing file (H5 file or JSON file depending on subclass).
void WriteSharedIndexVector(const std::string &name, const ssp< host_device_vector< index > > &v, ArrayGlobalOffset offset) override
Write a shared index vector; deduplicated across multiple writes that share the same shared_ptr.
void ReadInt(const std::string &name, int &v) override
Read a scalar int into v.
void ReadUint8Array(const std::string &name, uint8_t *data, index &size, ArrayGlobalOffset &offset) override
Two-pass byte array read.
void CreatePath(const std::string &p) override
Create a sub-path (H5 group / JSON object) at the current location.
void WriteRowsizeVector(const std::string &name, const std::vector< rowsize > &v, ArrayGlobalOffset offset) override
Write a rowsize vector (collective for H5).
void WriteInt(const std::string &name, int v) override
Write a scalar int under name at the current path.
void WriteIndexVector(const std::string &name, const std::vector< index > &v, ArrayGlobalOffset offset) override
Write an index vector (collective for H5). offset carries the distribution mode (ArrayGlobalOffset_Pa...
void WriteUint8Array(const std::string &name, const uint8_t *data, index size, ArrayGlobalOffset offset) override
Write a raw byte buffer under name. offset.isDist() = true means the caller provides the exact per-ra...
void ReadSharedRowsizeVector(const std::string &name, ssp< host_device_vector< rowsize > > &v, ArrayGlobalOffset &offset) override
void ReadIndex(const std::string &name, index &v) override
Read a scalar index into v.
void WriteRealVector(const std::string &name, const std::vector< real > &v, ArrayGlobalOffset offset) override
Write a real vector (collective for H5).
void WriteReal(const std::string &name, real v) override
Write a scalar real under name.
void ReadRowsizeVector(const std::string &name, std::vector< rowsize > &v, ArrayGlobalOffset &offset) override
void WriteIndex(const std::string &name, index v) override
Write a scalar index under name.
void GoToPath(const std::string &p) override
Navigate to an existing path. Supports / -separated segments.
void ReadReal(const std::string &name, real &v) override
Read a scalar real into v.
Host + optional device vector of trivially copyable T.
Definition Vector.hpp:217
std::vector< std::string > splitSString(const std::string &str, char delim)
Definition Defines.hpp:772
int64_t index
Global row / DOF index type (signed 64-bit; handles multi-billion-cell meshes).
Definition Defines.hpp:107
std::shared_ptr< T > ssp
Shortened alias for std::shared_ptr used pervasively in DNDSR.
Definition Defines.hpp:138
double real
Canonical floating-point scalar used throughout DNDSR (double precision).
Definition Defines.hpp:105
Eigen::Matrix< real, 5, 1 > v