kDB: Knowledge DataBase
Loading...
Searching...
No Matches
BinaryInterface_write_p.h
1#include <arpa/inet.h>
2
3#include <knowCore/Array.h>
4#include <knowCore/BigNumber.h>
5#include <knowCore/Vector.h>
6
7#include <QJsonArray>
8#include <QJsonDocument>
9#include <QJsonObject>
10#include <QJsonValue>
11
12#include "postgresql_p.h"
13
14#include "BinaryInterface_traits_p.h"
15
16namespace kDB::Repository::DatabaseInterface::PostgreSQL::BinaryInterface
17{
18 template<typename _T_>
20 {
21 static inline std::size_t do_calculate_size(const _T_&) { return sizeof(_T_); }
22 };
23
24 template<typename _T_>
25 inline std::size_t calculate_size(const _T_& _v)
26 {
28 }
29
30 template<typename _T_>
31 inline void write(const _T_& _value, char* _data)
32 {
33 write_details<_T_>::do_write(_value, _data);
34 }
35
36 template<typename _T_>
37 inline void write(const _T_& _value, QByteArray* _array)
38 {
39 _array->resize(calculate_size<_T_>(_value));
40 write(_value, _array->data());
41 }
42 template<typename _T_>
43 inline QByteArray write(_T_ _value) Q_REQUIRED_RESULT;
44 template<typename _T_>
45 inline QByteArray write(_T_ _value)
46 {
47 QByteArray r;
48 write<_T_>(_value, &r);
49 return r;
50 }
51
52 template<>
53 inline void write<qint64>(const qint64& _value, char* _data)
54 {
55 qint32* h32 = (qint32*)_data;
56 qint32* l32 = (qint32*)(_data + 4);
57
58 *h32 = htonl(_value >> 32);
59 *l32 = htonl(_value & 0xFFFFFFFF);
60 }
61 template<>
62 inline void write<quint64>(const quint64& _value, char* _data)
63 {
64 write<qint64>(_value, _data);
65 }
66 template<>
67 inline void write<qint32>(const qint32& _value, char* _data)
68 {
69 *reinterpret_cast<qint32*>(_data) = htonl(_value);
70 }
71 template<>
72 inline void write<quint32>(const quint32& _value, char* _data)
73 {
74 write<qint32>(_value, _data);
75 }
76 template<>
77 inline void write<qint16>(const qint16& _value, char* _data)
78 {
79 *reinterpret_cast<qint16*>(_data) = htons(_value);
80 }
81 template<>
82 inline void write<quint16>(const quint16& _value, char* _data)
83 {
84 write<qint16>(_value, _data);
85 }
86 template<>
87 inline void write<bool>(const bool& _value, char* _data)
88 {
89 *_data = _value ? 1 : 0;
90 }
91
92 template<>
93 inline void write<float>(const float& _fl, char* data)
94 {
95 union
96 {
97 float f;
98 qint32 i;
99 } swap;
100 swap.f = _fl;
101 write<qint32>(swap.i, data);
102 }
103 template<>
104 inline void write<double>(const double& _fl, char* data)
105 {
106 union
107 {
108 double f;
109 qint64 i;
110 } swap;
111 swap.f = _fl;
112 write<qint64>(swap.i, data);
113 }
114 template<>
115 inline std::size_t calculate_size<knowCore::Timestamp>(const knowCore::Timestamp& _v)
116 {
117 Q_UNUSED(_v);
118 return calculate_size<qint64>(0);
119 }
120 template<>
121 inline void write<knowCore::Timestamp>(const knowCore::Timestamp& _dt, char* _data)
122 {
123 Q_UNUSED(_dt);
124 Q_UNUSED(_data);
125 qFatal("Unimplemented");
126 }
127 template<>
128 inline std::size_t calculate_size<QString>(const QString& _v)
129 {
130 return _v.toUtf8().size();
131 }
132 template<>
133 inline void write<QString>(const QString& _dt, char* data)
134 {
135 QByteArray r = _dt.toUtf8();
136 memcpy(data, r.data(), r.size());
137 }
138
139 template<>
140 inline std::size_t calculate_size<QByteArray>(const QByteArray& _v)
141 {
142 return _v.size();
143 }
144 template<>
145 inline void write<QByteArray>(const QByteArray& _dt, char* data)
146 {
147 std::copy(_dt.begin(), _dt.end(), data);
148 }
149
150 template<>
151 inline void write<knowCore::BigNumber>(const knowCore::BigNumber& _number, char* data)
152 {
153 write<quint16>(_number.digits().size(), data);
154 data += 2;
155 write<quint16>(_number.weight(), data);
156 data += 2;
157 quint16 sign = 0xC000;
158 switch(_number.sign())
159 {
160 case knowCore::BigNumber::Sign::Negative:
161 sign = 0x4000;
162 break;
163 case knowCore::BigNumber::Sign::Positive:
164 sign = 0x0000;
165 break;
166 case knowCore::BigNumber::Sign::NaN:
167 sign = 0xC000;
168 break;
169 case knowCore::BigNumber::Sign::PositiveInfinite:
170 sign = 0xD000;
171 break;
172 case knowCore::BigNumber::Sign::NegativeInfinite:
173 sign = 0xF000;
174 break;
175 }
176 write<quint16>(sign, data);
177 data += 2;
178 write<quint16>(_number.dscale(), data);
179 data += 2;
180
181 for(quint16 d : _number.digits())
182 {
183 write<quint16>(d, data);
184 data += 2;
185 }
186 }
187 template<>
188 inline std::size_t calculate_size<knowCore::BigNumber>(const knowCore::BigNumber& _number)
189 {
190 return (4 + _number.digits().size()) * sizeof(quint16);
191 }
192 namespace details
193 {
194 inline char* write_enum(const char* enum_name, char* data)
195 {
196 const std::size_t s = strlen(enum_name);
197 write<quint32>(s, data);
198 data += sizeof(quint32);
199 std::copy(enum_name, enum_name + s, data);
200 data += s;
201 return data;
202 }
203 inline char* write_empty(Oid _oid, char* data)
204 {
205 write<Oid>(_oid, data);
206 data += sizeof(Oid);
207 write<quint32>(0xFFFFFFFF, data);
208 data += sizeof(quint32);
209 return data;
210 }
211 template<typename _T_>
212 inline char* write_value(Oid _oid, const _T_& _value, char* data)
213 {
214 std::size_t s = calculate_size<_T_>(_value);
215 write<Oid>(_oid, data);
216 data += sizeof(Oid);
217 write<quint32>(s, data);
218 data += sizeof(quint32);
219 write<_T_>(_value, data);
220 data += s;
221 return data;
222 }
223 } // namespace details
224 template<typename _T_>
225 struct write_details<QList<_T_>>
226 {
227 static inline std::size_t do_calculate_size(const QList<_T_>& _val)
228 {
229 std::size_t s = 4 * 5;
230 for(const _T_& t : _val)
231 {
232 s += 4 + calculate_size<_T_>(t);
233 }
234 return s;
235 }
236 static inline void do_write(const QList<_T_>& _value, char* data)
237 {
238 write<quint32>(1, data);
239 data += 4; // ndim
240
241 write<quint32>(0, data);
242 data += 4; // has_null
243 write<quint32>(traits<_T_>::oid(), data);
244 data += 4;
245
246 write<quint32>(_value.size(), data);
247 data += 4;
248 write<quint32>(0, data);
249 data += 4; // lbound
250
251 for(int i = 0; i < _value.size(); ++i)
252 {
253 const _T_& val = _value[i];
254 std::size_t s = calculate_size<_T_>(val);
255 write<quint32>(s, data);
256 data += 4;
257 write<_T_>(val, data);
258 data += s;
259 }
260 }
261 };
262 template<typename _T_, std::size_t _dimension>
263 struct write_details<knowCore::Vector<_T_, _dimension>>
264 {
265 static inline std::size_t do_calculate_size(const knowCore::Vector<_T_, _dimension>& _val)
266 {
267 return 4 * 5 + _dimension * (4 + calculate_size<_T_>(_val[0]));
268 }
269 static inline void do_write(const knowCore::Vector<_T_, _dimension>& _value, char* data)
270 {
271 write<QList<_T_>>(_value, data);
272 }
273 };
274
275 template<typename _T_, std::size_t _dimension>
276 struct write_details<QList<knowCore::Vector<_T_, _dimension>>>
277 {
278 static inline std::size_t
279 do_calculate_size(const QList<knowCore::Vector<_T_, _dimension>>& _val)
280 {
281 std::size_t s = 4 * 7;
282 for(const knowCore::Vector<_T_, _dimension>& t : _val)
283 {
284 for(std::size_t j = 0; j < _dimension; ++j)
285 {
286 s += 4 + calculate_size<_T_>(t[j]);
287 }
288 }
289 return s;
290 }
291 static inline void do_write(const QList<knowCore::Vector<_T_, _dimension>>& _value, char* data)
292 {
293 write<quint32>(2, data);
294 data += 4; // ndim
295
296 write<quint32>(0, data);
297 data += 4; // has_null
298 write<quint32>(traits<_T_>::oid(), data);
299 data += 4;
300
301 write<quint32>(_value.size(), data);
302 data += 4;
303 write<quint32>(0, data);
304 data += 4; // lbound
305 write<quint32>(_dimension, data);
306 data += 4;
307 write<quint32>(0, data);
308 data += 4; // lbound
309
310 for(int i = 0; i < _value.size(); ++i)
311 {
312 const knowCore::Vector<_T_, _dimension>& v = _value[i];
313 for(std::size_t j = 0; j < _dimension; ++j)
314 {
315 std::size_t s = calculate_size<_T_>(v[j]);
316 write<quint32>(s, data);
317 data += 4;
318 write<_T_>(v[j], data);
319 data += s;
320 }
321 }
322 }
323 };
324 template<typename _T_>
325 struct write_details<knowCore::Array<_T_>>
326 {
327 static inline std::size_t do_calculate_size(const knowCore::Array<_T_>& _val)
328 {
329 std::size_t s = 4 * (3 + 2 * _val.dimensions().size());
330 for(const _T_& t : _val.data())
331 {
332 s += 4 + calculate_size<_T_>(t);
333 }
334 return s;
335 }
336 static inline void do_write(const knowCore::Array<_T_>& _value, char* data)
337 {
338 write<quint32>(_value.dimensions().size(), data);
339 data += 4; // ndim
340
341 write<quint32>(0, data);
342 data += 4; // has_null
343 write<quint32>(traits<_T_>::oid(), data);
344 data += 4;
345
346 for(int d : _value.dimensions())
347 {
348 write<quint32>(d, data);
349 data += 4;
350 write<quint32>(0, data);
351 data += 4; // lbound
352 }
353
354 for(const _T_& val : _value.data())
355 {
356 std::size_t s = calculate_size<_T_>(val);
357 write<quint32>(s, data);
358 data += 4;
359 write<_T_>(val, data);
360 data += s;
361 }
362 }
363 };
364
365 // Json
366 template<>
367 inline void write<QJsonDocument>(const QJsonDocument& _document, QByteArray* _array)
368 {
369 write(_document.toJson(QJsonDocument::Compact), _array);
370 }
371 template<>
372 inline void write<QJsonArray>(const QJsonArray& _value, QByteArray* _array)
373 {
374 QJsonDocument doc;
375 doc.setArray(_value);
376 write(doc, _array);
377 }
378 template<>
379 inline void write<QJsonObject>(const QJsonObject& _value, QByteArray* _array)
380 {
381 QJsonDocument doc;
382 doc.setObject(_value);
383 write(doc, _array);
384 }
385 template<>
386 inline void write<QJsonValue>(const QJsonValue& _value, QByteArray* _array)
387 {
388 switch(_value.type())
389 {
390 case QJsonValue::Null:
391 case QJsonValue::Undefined:
392 *_array = QByteArray();
393 break;
394 case QJsonValue::Bool:
395 case QJsonValue::Double:
396 case QJsonValue::String:
397 clog_fatal("Invalid type of QJsonValue: {}", _value);
398 case QJsonValue::Array:
399 write(_value.toArray(), _array);
400 break;
401 case QJsonValue::Object:
402 write(_value.toObject(), _array);
403 break;
404 }
405 }
406
407 namespace details
408 {
409 template<int _N_, typename... T>
411 {
412 static int do_calculate_size(const std::tuple<T...>& data)
413 {
415 + calculate_size(std::get<sizeof...(T) - _N_>(data)) + 4 /* oid */ + 4 /* size */;
416 }
417 static void do_write(const std::tuple<T...>& data, char* ptr)
418 {
419 auto v = std::get<sizeof...(T) - _N_>(data);
420 std::size_t s = calculate_size(v);
421 write(traits<decltype(v)>::oid(), ptr);
422 ptr += 4;
423 write(s);
424 ptr += 4;
425 write(v, ptr);
426 ptr += s;
428 }
429 };
430 template<typename... T>
431 struct struct_writer<0, T...>
432 {
433 static int do_calculate_size(std::tuple<T...> data)
434 {
435 Q_UNUSED(data);
436 return 4; // For the fields
437 }
438 static void do_write(const std::tuple<T...>& data, char* ptr)
439 {
440 Q_UNUSED(data);
441 Q_UNUSED(ptr);
442 }
443 };
444 } // namespace details
445
446 template<typename... T>
448 {
449 struct_writer(Oid oid, T... _t) : m_data(_t...), m_oid(oid) {}
450 int calculate_size() const
451 {
452 return details::struct_writer<sizeof...(T), T...>::do_calculate_size(m_data);
453 }
454 void write(char* ptr) const
455 {
456 BinaryInterface::write<quint32>(sizeof...(T), ptr);
457 ptr += 4;
459 }
460 Oid oid() const { return m_oid; }
461 private:
462 std::tuple<T...> m_data;
463 Oid m_oid;
464 };
465
466 template<typename... T>
468 {
469 static inline std::size_t do_calculate_size(const struct_writer<T...>& _t)
470 {
471 return _t.calculate_size();
472 }
473 static inline void write(const struct_writer<T...>& _value, char* _data)
474 {
475 _value.write(_data);
476 }
477 };
478} // namespace kDB::Repository::DatabaseInterface::PostgreSQL::BinaryInterface
Definition Revision.h:9
Definition Array.h:16
Class that can contains large numeric value.
Definition BigNumber.h:51
Definition Timestamp.h:39
Definition Vector.h:13