quasardb 3.14.2.dev3__cp312-cp312-win32.whl → 3.14.2.dev5__cp312-cp312-win32.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of quasardb might be problematic. Click here for more details.

Files changed (105) hide show
  1. quasardb/INSTALL.vcxproj +5 -4
  2. quasardb/__init__.py +21 -7
  3. quasardb/cmake_install.cmake +6 -0
  4. quasardb/date/ALL_BUILD.vcxproj +9 -8
  5. quasardb/date/CMakeFiles/Export/df49adab93b9e0c10c64f72458b31971/dateTargets.cmake +2 -2
  6. quasardb/date/CMakeFiles/generate.stamp.depend +4 -4
  7. quasardb/date/INSTALL.vcxproj +5 -4
  8. quasardb/date/cmake_install.cmake +6 -0
  9. quasardb/date/dateTargets.cmake +2 -2
  10. quasardb/extensions/writer.py +59 -61
  11. quasardb/firehose.py +24 -22
  12. quasardb/numpy/__init__.py +181 -120
  13. quasardb/pandas/__init__.py +145 -95
  14. quasardb/pool.py +13 -2
  15. quasardb/pybind11/ALL_BUILD.vcxproj +9 -8
  16. quasardb/pybind11/CMakeFiles/generate.stamp.depend +14 -14
  17. quasardb/pybind11/INSTALL.vcxproj +5 -4
  18. quasardb/pybind11/cmake_install.cmake +6 -0
  19. quasardb/qdb_api.dll +0 -0
  20. quasardb/quasardb.cp312-win32.pyd +0 -0
  21. quasardb/range-v3/ALL_BUILD.vcxproj +9 -8
  22. quasardb/range-v3/CMakeFiles/Export/d94ef200eca10a819b5858b33e808f5b/range-v3-targets.cmake +2 -2
  23. quasardb/range-v3/CMakeFiles/generate.stamp.depend +11 -11
  24. quasardb/range-v3/INSTALL.vcxproj +5 -4
  25. quasardb/range-v3/cmake_install.cmake +6 -0
  26. quasardb/range-v3/range-v3-config.cmake +2 -2
  27. quasardb/range-v3/range.v3.headers.vcxproj +9 -8
  28. quasardb/stats.py +92 -80
  29. quasardb/table_cache.py +5 -1
  30. {quasardb-3.14.2.dev3.dist-info → quasardb-3.14.2.dev5.dist-info}/METADATA +13 -8
  31. quasardb-3.14.2.dev5.dist-info/RECORD +54 -0
  32. {quasardb-3.14.2.dev3.dist-info → quasardb-3.14.2.dev5.dist-info}/WHEEL +1 -1
  33. quasardb/CMakeLists.txt +0 -517
  34. quasardb/batch_column.hpp +0 -80
  35. quasardb/batch_inserter.hpp +0 -248
  36. quasardb/blob.hpp +0 -150
  37. quasardb/cluster.cpp +0 -102
  38. quasardb/cluster.hpp +0 -593
  39. quasardb/concepts.hpp +0 -322
  40. quasardb/continuous.cpp +0 -199
  41. quasardb/continuous.hpp +0 -109
  42. quasardb/convert/array.hpp +0 -299
  43. quasardb/convert/point.hpp +0 -330
  44. quasardb/convert/range.hpp +0 -282
  45. quasardb/convert/unicode.hpp +0 -598
  46. quasardb/convert/util.hpp +0 -22
  47. quasardb/convert/value.hpp +0 -782
  48. quasardb/convert.hpp +0 -38
  49. quasardb/detail/invoke.hpp +0 -0
  50. quasardb/detail/qdb_resource.hpp +0 -129
  51. quasardb/detail/retry.cpp +0 -30
  52. quasardb/detail/retry.hpp +0 -147
  53. quasardb/detail/sleep.hpp +0 -53
  54. quasardb/detail/ts_column.hpp +0 -224
  55. quasardb/detail/writer.cpp +0 -440
  56. quasardb/detail/writer.hpp +0 -550
  57. quasardb/direct_blob.hpp +0 -108
  58. quasardb/direct_handle.hpp +0 -83
  59. quasardb/direct_integer.hpp +0 -94
  60. quasardb/dispatch.hpp +0 -157
  61. quasardb/double.hpp +0 -87
  62. quasardb/entry.hpp +0 -273
  63. quasardb/error.hpp +0 -393
  64. quasardb/handle.cpp +0 -29
  65. quasardb/handle.hpp +0 -98
  66. quasardb/integer.hpp +0 -88
  67. quasardb/logger.cpp +0 -106
  68. quasardb/logger.hpp +0 -228
  69. quasardb/masked_array.hpp +0 -658
  70. quasardb/metrics.cpp +0 -103
  71. quasardb/metrics.hpp +0 -112
  72. quasardb/module.cpp +0 -92
  73. quasardb/module.hpp +0 -24
  74. quasardb/node.hpp +0 -132
  75. quasardb/numpy.cpp +0 -6
  76. quasardb/numpy.hpp +0 -489
  77. quasardb/object_tracker.hpp +0 -282
  78. quasardb/options.hpp +0 -273
  79. quasardb/perf.hpp +0 -336
  80. quasardb/properties.cpp +0 -41
  81. quasardb/properties.hpp +0 -85
  82. quasardb/pytypes.hpp +0 -221
  83. quasardb/query.cpp +0 -420
  84. quasardb/query.hpp +0 -92
  85. quasardb/reader.cpp +0 -282
  86. quasardb/reader.hpp +0 -256
  87. quasardb/remove_cvref.hpp +0 -31
  88. quasardb/string.hpp +0 -160
  89. quasardb/table.cpp +0 -257
  90. quasardb/table.hpp +0 -366
  91. quasardb/tag.hpp +0 -77
  92. quasardb/timestamp.hpp +0 -97
  93. quasardb/traits.hpp +0 -642
  94. quasardb/ts_iterator.hpp +0 -193
  95. quasardb/utils/blob_deque.hpp +0 -96
  96. quasardb/utils/ostream.hpp +0 -17
  97. quasardb/utils/permutation.hpp +0 -50
  98. quasardb/utils/stable_sort.hpp +0 -25
  99. quasardb/utils/unzip_view.hpp +0 -89
  100. quasardb/utils.cpp +0 -28
  101. quasardb/utils.hpp +0 -174
  102. quasardb/writer.hpp +0 -354
  103. quasardb-3.14.2.dev3.dist-info/RECORD +0 -124
  104. {quasardb-3.14.2.dev3.dist-info → quasardb-3.14.2.dev5.dist-info}/LICENSE.md +0 -0
  105. {quasardb-3.14.2.dev3.dist-info → quasardb-3.14.2.dev5.dist-info}/top_level.txt +0 -0
@@ -1,782 +0,0 @@
1
- /*
2
- *
3
- * Official Python API
4
- *
5
- * Copyright (c) 2009-2024, quasardb SAS. All rights reserved.
6
- * All rights reserved.
7
- *
8
- * Redistribution and use in source and binary forms, with or without
9
- * modification, are permitted provided that the following conditions are met:
10
- *
11
- * * Redistributions of source code must retain the above copyright
12
- * notice, this list of conditions and the following disclaimer.
13
- * * Redistributions in binary form must reproduce the above copyright
14
- * notice, this list of conditions and the following disclaimer in the
15
- * documentation and/or other materials provided with the distribution.
16
- * * Neither the name of quasardb nor the names of its contributors may
17
- * be used to endorse or promote products derived from this software
18
- * without specific prior written permission.
19
- *
20
- * THIS SOFTWARE IS PROVIDED BY QUASARDB AND CONTRIBUTORS ``AS IS'' AND ANY
21
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
- * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
24
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
- */
31
- #pragma once
32
-
33
- #include "../concepts.hpp"
34
- #include "../error.hpp"
35
- #include "../numpy.hpp"
36
- #include "../object_tracker.hpp"
37
- #include "../pytypes.hpp"
38
- #include "../traits.hpp"
39
- #include "unicode.hpp"
40
- #include <qdb/ts.h>
41
- #include <date/date.h> // We cannot use <chrono> until we upgrade to at least GCC11 (ARM).
42
- #include <pybind11/pybind11.h>
43
- #include <range/v3/algorithm/copy.hpp>
44
- #include <range/v3/algorithm/for_each.hpp>
45
- #include <range/v3/range/concepts.hpp>
46
- #include <range/v3/view/counted.hpp>
47
- #include <chrono>
48
- #include <cstring>
49
-
50
- namespace qdb::convert::detail
51
- {
52
-
53
- namespace py = pybind11;
54
- typedef std::remove_cvref<decltype(qdb_string_t::data[0])>::type qdb_char_type;
55
-
56
- ////////////////////////////////////////////////////////////////////////////////
57
- //
58
- // VALUE CONVERTERS
59
- //
60
- ///////////////////
61
- //
62
- // These converters operate on individual values, with various degrees of
63
- // complexity.
64
- //
65
- ////////////////////////////////////////////////////////////////////////////////
66
-
67
- template <typename From, typename To>
68
- struct value_converter;
69
-
70
- template <typename From, typename To>
71
- requires(std::is_same_v<From, To>)
72
- struct value_converter<From, To>
73
- {
74
- inline To operator()(From const & x) const
75
- {
76
- static_assert(sizeof(To) >= sizeof(From));
77
- // Default implementation for "simple" conversions allowed by the compiler,
78
- // e.g. int32 to int64.
79
- return x;
80
- }
81
- };
82
-
83
- template <typename To>
84
- struct value_converter<traits::int64_dtype, To> : public value_converter<std::int64_t, To>
85
- {};
86
-
87
- template <typename To>
88
- struct value_converter<traits::int32_dtype, To> : public value_converter<std::int32_t, To>
89
- {};
90
-
91
- template <typename To>
92
- struct value_converter<traits::int16_dtype, To> : public value_converter<std::int16_t, To>
93
- {};
94
-
95
- template <typename From>
96
- struct value_converter<From, traits::int64_dtype> : public value_converter<From, std::int64_t>
97
- {};
98
-
99
- template <typename From>
100
- struct value_converter<From, traits::int32_dtype> : public value_converter<From, std::int32_t>
101
- {};
102
-
103
- template <typename From>
104
- struct value_converter<From, traits::int16_dtype> : public value_converter<From, std::int16_t>
105
- {};
106
-
107
- template <typename To>
108
- struct value_converter<traits::float64_dtype, To> : public value_converter<double, To>
109
- {};
110
-
111
- template <typename To>
112
- struct value_converter<traits::float32_dtype, To> : public value_converter<float, To>
113
- {};
114
-
115
- template <typename From>
116
- struct value_converter<From, traits::float64_dtype> : public value_converter<From, double>
117
- {};
118
-
119
- template <typename From>
120
- struct value_converter<From, traits::float32_dtype> : public value_converter<From, float>
121
- {};
122
-
123
- template <typename From>
124
- struct value_converter<From, traits::pyobject_dtype> : public value_converter<From, py::object>
125
- {};
126
-
127
- ////////////////////////////////////////////////////////////////////////////////
128
- //
129
- // qdb_timespec_t converters
130
- //
131
- ///////////////////
132
- //
133
- // These converters focus on converting qdb_timespec_t to/from other types.
134
- //
135
- /////
136
-
137
- using clock_t = std::chrono::system_clock;
138
-
139
- // Explicitly specifying the durations here, rather than relying on type
140
- // inference of the integer type, avoids pitfalls like Python using an
141
- // `int` to represent seconds which isn't enough for chrono.
142
- using nanoseconds_t = std::chrono::duration<std::int64_t, std::nano>;
143
- using microseconds_t = std::chrono::duration<std::int64_t, std::micro>;
144
- using milliseconds_t = std::chrono::duration<std::int64_t, std::milli>;
145
- using seconds_t = std::chrono::duration<std::int64_t>;
146
- using minutes_t = std::chrono::duration<std::int32_t, std::ratio<60>>;
147
- using hours_t = std::chrono::duration<std::int32_t, std::ratio<3600>>;
148
- using days_t = std::chrono::duration<std::int32_t, std::ratio<86400>>;
149
- using weeks_t = std::chrono::duration<std::int32_t, std::ratio<604800>>;
150
- using months_t = std::chrono::duration<std::int32_t, std::ratio<2629746>>;
151
- using years_t = std::chrono::duration<std::int32_t, std::ratio<31556952>>;
152
-
153
- /**
154
- * datetime.timedelta -> std::chrono::duration
155
- *
156
- * Useful for converting a datetime timezone offset to a chrono duration, among others.
157
- */
158
- template <>
159
- struct value_converter<qdb::pytimedelta, clock_t::duration>
160
- {
161
- inline std::chrono::system_clock::duration operator()(pytimedelta const & x) const
162
- {
163
- assert(x.is_none() == false);
164
-
165
- static_assert(sizeof(decltype(x.days())) <= sizeof(days_t::rep));
166
- static_assert(sizeof(decltype(x.seconds())) <= sizeof(seconds_t::rep));
167
- static_assert(sizeof(decltype(x.microseconds())) <= sizeof(microseconds_t::rep));
168
-
169
- return days_t{x.days()} + seconds_t{x.seconds()} + microseconds_t{x.microseconds()};
170
- }
171
- };
172
-
173
- /**
174
- * datetime.datetime -> std::chrono::time_point
175
- *
176
- * Takes the input datetime, and converts it to a time point. ensures that the timezone
177
- * offset of datetime is taken into account, and output time_point is in UTC.
178
- */
179
-
180
- template <>
181
- struct value_converter<qdb::pydatetime, clock_t::time_point>
182
- {
183
- value_converter<qdb::pytimedelta, clock_t::duration> offset_convert_{};
184
-
185
- inline clock_t::time_point operator()(qdb::pydatetime const & x) const
186
-
187
- {
188
- // Construct the date
189
- date::year_month_day ymd{
190
- date::year{x.year()}, date::month{(unsigned)x.month()}, date::day{(unsigned)x.day()}};
191
-
192
- // Calculate the number of days since epoch
193
- date::sys_days days_since_epoch{ymd};
194
-
195
- static_assert(sizeof(decltype(x.hour())) <= sizeof(hours_t::rep));
196
- static_assert(sizeof(decltype(x.second())) <= sizeof(seconds_t::rep));
197
- static_assert(sizeof(decltype(x.microsecond())) <= sizeof(microseconds_t::rep));
198
-
199
- // Calculate the time of day as a duration
200
- clock_t::duration time_of_day{hours_t{x.hour()} + minutes_t{x.minute()} + seconds_t{x.second()}
201
- + microseconds_t{x.microsecond()}};
202
-
203
- // Adjust for UTC
204
- clock_t::duration tz_offset = offset_convert_(x.utcoffset());
205
-
206
- // Compose the whole thing together
207
- return clock_t::time_point(days_since_epoch) + time_of_day - tz_offset;
208
- }
209
- };
210
-
211
- template <>
212
- struct value_converter<std::int64_t, qdb_timespec_t>
213
- {
214
- inline constexpr qdb_timespec_t operator()(std::int64_t const & x) const
215
- {
216
- if (x < 0) [[unlikely]]
217
- {
218
- return qdb_timespec_t{qdb_min_time, qdb_min_time};
219
- }
220
-
221
- constexpr std::int64_t ns = 1'000'000'000ull;
222
- std::int64_t tv_nsec = x % ns;
223
- std::int64_t tv_sec = (x - tv_nsec) / ns;
224
-
225
- return qdb_timespec_t{tv_sec, tv_nsec};
226
- }
227
- };
228
-
229
- /**
230
- * chrono time_point -> qdb_timespec_t
231
- *
232
- * First converts timepoint to nanos since epoch, then delegates to another converter.
233
- */
234
- template <>
235
- struct value_converter<clock_t::time_point, qdb_timespec_t>
236
- {
237
- value_converter<std::int64_t, qdb_timespec_t> delegate_{};
238
-
239
- inline constexpr qdb_timespec_t operator()(clock_t::time_point const & x) const
240
- {
241
- auto nanos = std::chrono::duration_cast<nanoseconds_t>(x.time_since_epoch());
242
-
243
- return delegate_(nanos.count());
244
- }
245
- };
246
-
247
- /**
248
- * clock_t::time_point -> qdb_time_t
249
- *
250
- * Returns the qdb_time_t representation of a time_point; qdb_time_t is assumed
251
- * to be using milliseconds.
252
- */
253
- template <>
254
- struct value_converter<clock_t::time_point, qdb_time_t>
255
- {
256
- inline qdb_time_t operator()(clock_t::time_point const & x) const
257
- {
258
- auto time_since_epoch = x.time_since_epoch();
259
-
260
- return static_cast<qdb_time_t>(
261
- std::chrono::duration_cast<milliseconds_t>(time_since_epoch).count());
262
- }
263
- };
264
-
265
- /**
266
- * datetime.datetime -> qdb_time_t
267
- */
268
- template <>
269
- struct value_converter<qdb::pydatetime, qdb_time_t>
270
- {
271
- value_converter<qdb::pydatetime, clock_t::time_point> dt_to_tp_{};
272
- value_converter<clock_t::time_point, qdb_time_t> tp_to_qt_{};
273
-
274
- inline qdb_time_t operator()(pydatetime const & x) const
275
- {
276
- if (x.is_none())
277
- {
278
-
279
- return qdb_time_t{0};
280
- }
281
- else
282
- {
283
- return tp_to_qt_(dt_to_tp_(x));
284
- }
285
- }
286
- };
287
-
288
- /**
289
- * qdb_timespec_t -> std::chrono::time_point
290
- */
291
-
292
- template <>
293
- struct value_converter<qdb_timespec_t, clock_t::time_point>
294
- {
295
- inline clock_t::time_point operator()(qdb_timespec_t const & x) const
296
- {
297
- // We *could* feed chrono the nanoseconds_t directly, but:
298
- // - python is not able to represent nanoseconds;
299
- // - some architectures are unable to represent the system_clock with
300
- // nanosecond precision; it requires some pretty big integers.
301
- //
302
- // As such, let's first truncate things to milliseconds
303
- milliseconds_t millis{x.tv_nsec / 1'000'000};
304
- seconds_t seconds{x.tv_sec};
305
-
306
- return clock_t::time_point(millis + seconds);
307
- }
308
- };
309
-
310
- /**
311
- * std::chrono::time_point -> datetime.datetime
312
- *
313
- * time point is assumed to be UTC.
314
- */
315
- template <>
316
- struct value_converter<clock_t::time_point, qdb::pydatetime>
317
- {
318
- inline qdb::pydatetime operator()(clock_t::time_point const & tp) const
319
- {
320
- date::sys_days dp = date::floor<days_t>(tp);
321
- date::year_month_day ymd{dp};
322
- date::hh_mm_ss hms{date::floor<seconds_t>(tp - dp)};
323
-
324
- // We get the 'microseconds' part by simply calculating the total amount of seconds since
325
- // epoch, and then substracting that from the time point; whatever is left, is guaranteed
326
- // to be the fraction after the second.
327
- //
328
- // Similar appproach as here: https://stackoverflow.com/a/27137475
329
-
330
- auto since_epoch = tp.time_since_epoch();
331
- auto seconds = std::chrono::duration_cast<seconds_t>(since_epoch);
332
- since_epoch -= seconds;
333
-
334
- // Round it to microseconds, because that's what pydatetime uses as max precision
335
- auto micros = std::chrono::duration_cast<microseconds_t>(since_epoch);
336
-
337
- return qdb::pydatetime::from_date_and_time(static_cast<int>(ymd.year()),
338
- static_cast<unsigned>(ymd.month()), static_cast<unsigned>(ymd.day()),
339
- static_cast<int>(hms.hours().count()), static_cast<int>(hms.minutes().count()),
340
- static_cast<int>(hms.seconds().count()), static_cast<int>(micros.count()));
341
- }
342
- };
343
-
344
- /**
345
- * qdb_timespec_t -> datetime.datetime
346
- *
347
- * composes two converters to convert a timespec into a datetime.datetime object in one
348
- * swoop:
349
- *
350
- * - first convert the qdb_timespec_t to a (utc) time point;
351
- * - use the utc time point to create a datetime object
352
- */
353
- template <>
354
- struct value_converter<qdb_timespec_t, qdb::pydatetime>
355
- {
356
- value_converter<qdb_timespec_t, clock_t::time_point> ts_to_tp_{};
357
- value_converter<clock_t::time_point, qdb::pydatetime> tp_to_dt_{};
358
-
359
- inline qdb::pydatetime operator()(qdb_timespec_t const & x) const
360
- {
361
- return tp_to_dt_(ts_to_tp_(x));
362
- }
363
- };
364
-
365
- /**
366
- * datetime.datetime -> qdb_timespec_t
367
- *
368
- * composes two converters to convert a datetime.datetime into a timespec in one
369
- * swoop.
370
- */
371
- template <>
372
- struct value_converter<qdb::pydatetime, qdb_timespec_t>
373
- {
374
- value_converter<qdb::pydatetime, clock_t::time_point> dt_to_tp_{};
375
- value_converter<clock_t::time_point, qdb_timespec_t> tp_to_ts_{};
376
-
377
- inline qdb_timespec_t operator()(qdb::pydatetime const & x) const
378
- {
379
- return tp_to_ts_(dt_to_tp_(x));
380
- }
381
- };
382
-
383
- /**
384
- * Creates a numpy datetime64[ns] out of a nanosecond-precision int64
385
- */
386
- template <>
387
- struct value_converter<std::int64_t, qdb::numpy::datetime64>
388
- {
389
- inline qdb::numpy::datetime64 operator()(std::int64_t const & x) const
390
- {
391
- return qdb::numpy::datetime64{x};
392
- }
393
- };
394
-
395
- /**
396
- * Creates a nanosecond precision int64 out of a qdb_timespec_t. The resulting
397
- * integer represents the amount of nanoseconds since epoch, which is the
398
- * same representation numpy uses internally.
399
- */
400
- template <>
401
- struct value_converter<qdb_timespec_t, std::int64_t>
402
- {
403
- inline std::int64_t operator()(qdb_timespec_t const & x) const
404
- {
405
- // XXX(leon): potential overflow
406
- return x.tv_nsec + x.tv_sec * 1'000'000'000ull;
407
- }
408
- };
409
-
410
- /**
411
- * Convenience wrapper which directly converts timespecs to numpy datetime64
412
- */
413
- template <>
414
- struct value_converter<qdb_timespec_t, qdb::numpy::datetime64>
415
- {
416
- value_converter<std::int64_t, qdb::numpy::datetime64> int64_to_datetime64_{};
417
- value_converter<qdb_timespec_t, std::int64_t> ts_to_int64_{};
418
-
419
- inline qdb::numpy::datetime64 operator()(qdb_timespec_t const & x) const
420
- {
421
- return int64_to_datetime64_(ts_to_int64_(x));
422
- }
423
- };
424
-
425
- template <>
426
- struct value_converter<qdb_timespec_t, traits::datetime64_ns_dtype>
427
- : public value_converter<qdb_timespec_t, std::int64_t>
428
- {};
429
-
430
- template <>
431
- struct value_converter<traits::datetime64_ns_dtype, qdb_timespec_t>
432
- : public value_converter<std::int64_t, qdb_timespec_t>
433
- {};
434
-
435
- ////////////////////////////////////////////////////////////////////////////////
436
- //
437
- // qdb_blob_t/qdb_string_t converters
438
- //
439
- ///////////////////
440
- //
441
- // These converters focus on converting qdb_blob_t or qdb_string_t to/from
442
- // other types. They *may* allocate free pointers on the heap, in which case
443
- // those are tracked using the qdb::object_tracker
444
- //
445
- /////
446
-
447
- template <>
448
- struct value_converter<traits::bytestring_dtype, qdb_string_t>
449
- {
450
- using char_t = std::string::value_type;
451
-
452
- template <concepts::input_range_t<char_t> R>
453
- requires(ranges::sized_range<R> && ranges::contiguous_range<R>)
454
- inline qdb_string_t operator()(R && x) const
455
- {
456
- std::size_t n_chars = ranges::size(x);
457
- std::size_t n_bytes = (n_chars + 1) * sizeof(char_t);
458
- char_t const * x_ = ranges::data(x);
459
- char_t * tmp = qdb::object_tracker::alloc<char_t>(n_bytes);
460
-
461
- std::memcpy((void *)(tmp), x_, n_bytes);
462
-
463
- // For safety purposes, always null-terminate the output string.
464
- tmp[n_chars] = '\0';
465
- assert(tmp[n_chars] == '\0');
466
-
467
- return qdb_string_t{tmp, n_chars};
468
- }
469
- };
470
-
471
- template <>
472
- struct value_converter<std::string, qdb_string_t>
473
- {
474
- value_converter<traits::bytestring_dtype, qdb_string_t> delegate_{};
475
-
476
- inline qdb_string_t operator()(std::string const & x) const
477
- {
478
- return delegate_(x);
479
- }
480
- };
481
-
482
- template <>
483
- struct value_converter<qdb_string_t, std::string>
484
- {
485
- inline std::string operator()(qdb_string_t const & x) const
486
- {
487
- return {x.data, x.length};
488
- }
489
- };
490
-
491
- template <>
492
- struct value_converter<traits::unicode_dtype, qdb_string_t>
493
- {
494
- typedef std::u32string::value_type in_char_type;
495
- typedef qdb_char_type out_char_type;
496
-
497
- template <concepts::input_range_t<in_char_type> R>
498
- requires(ranges::sized_range<R> && ranges::contiguous_range<R>)
499
- inline qdb_string_t operator()(R && x) const
500
- {
501
- // std::cout << "+ input" << std::endl;
502
- // ranges::for_each(x, [](auto && x) { printf("%08X\n", x); });
503
- // std::cout << "- /input" << std::endl;
504
-
505
- // Calculate total size of output buffer; we *could* do it more
506
- // accurately by first scanning everything and then filling it,
507
- // but trades memory efficiency for performance.
508
- //
509
- // As such, we just allocate the maximum amount of theoretical bytes.
510
- std::size_t n_codepoints = ranges::size(x);
511
- std::size_t max_bytes_out = n_codepoints * sizeof(in_char_type);
512
-
513
- // std::cout << "input size, n_codepoints = " << n_codepoints << std::endl;
514
- // std::cout << "input size, max_bytes_out = " << max_bytes_out << std::endl;
515
-
516
- // Note: we allocate the buffer on our object_tracker heap!
517
- out_char_type * out = qdb::object_tracker::alloc<out_char_type>(max_bytes_out);
518
-
519
- // Get some range representation for this output buffer
520
- auto out_ = ranges::views::counted(out, max_bytes_out);
521
- auto out_begin = ranges::begin(out_);
522
-
523
- // Project our input data (in UTF32 / code points) to UTF8
524
- auto codepoints = unicode::utf32::decode_view(std::move(x));
525
- auto encoded = unicode::utf8::encode_view(std::move(codepoints));
526
-
527
- // std::cout << "encoded size = " << ranges::size(encoded) << std::endl;
528
-
529
- // Copy everything and keep track of the end
530
- auto [in_end, out_end] = ranges::copy(encoded, out_begin);
531
-
532
- // We can use the position of the output iterator to calculate
533
- // the length of the generated string.
534
- qdb_size_t n = static_cast<qdb_size_t>(std::distance(out_begin, out_end));
535
- // std::cout << "n = " << n << std::endl;
536
- // std::cout << "ranges::size(encoded) = " << ranges::size(encoded) << std::endl;
537
-
538
- // std::cout << "+ output: " << std::endl;
539
- // ranges::for_each(encoded, [](auto && x) { printf("%02X\n", x); });
540
- // std::cout << "- /output " << std::endl;
541
-
542
- // Sanity check: we expect to have written exactly as many bytes as our range claims it is
543
- assert(n == ranges::size(encoded));
544
-
545
- // UTF32->UTF8 we always expect at least as many items
546
- // assert(n >= n_codepoints);
547
-
548
- return qdb_string_t{out, n};
549
- }
550
- };
551
-
552
- template <>
553
- struct value_converter<py::bytes, qdb_blob_t>
554
- {
555
- using dtype = traits::object_dtype<py::bytes>;
556
-
557
- inline qdb_blob_t operator()(py::bytes const & x) const
558
- {
559
- assert(dtype::is_null(x) == false);
560
- assert(dtype::is_null(x) == x.is_none());
561
-
562
- qdb_blob_t ret{nullptr, 0};
563
-
564
- if (PYBIND11_BYTES_AS_STRING_AND_SIZE(
565
- x.ptr(), (char **)(&ret.content), (Py_ssize_t *)(&ret.content_length))) [[unlikely]]
566
- {
567
- throw qdb::incompatible_type_exception{"Unable to interpret object as bytes and size: "};
568
- }
569
-
570
- return ret;
571
- }
572
- };
573
-
574
- template <>
575
- struct value_converter<traits::pyobject_dtype, qdb_blob_t>
576
- : public value_converter<py::bytes, qdb_blob_t>
577
- {};
578
-
579
- template <>
580
- struct value_converter<qdb_blob_t, py::bytes>
581
- {
582
- inline py::bytes operator()(qdb_blob_t const & x) const
583
- {
584
- // Again, if we're already at the point that we're sure we can cast it to py::bytes,
585
- // it implies it is guaranteed not to be null.
586
- assert(traits::is_null(x) == false);
587
-
588
- return py::bytes(static_cast<char const *>(x.content), x.content_length);
589
- }
590
- };
591
-
592
- template <>
593
- struct value_converter<qdb_blob_t, py::object>
594
- {
595
- using dtype = traits::pyobject_dtype;
596
-
597
- value_converter<qdb_blob_t, py::bytes> delegate_{};
598
-
599
- inline py::object operator()(qdb_blob_t const & x) const
600
- {
601
- if (traits::is_null(x))
602
- {
603
- return dtype::null_value();
604
- }
605
-
606
- return delegate_(x);
607
- }
608
- };
609
-
610
- template <>
611
- struct value_converter<qdb_string_t, py::str>
612
- {
613
- inline py::str operator()(qdb_string_t const & x) const
614
- {
615
- // Again, if we're already at the point that we're sure we can cast it to py::bytes,
616
- // it implies it is guaranteed not to be null.
617
- assert(traits::is_null(x) == false);
618
-
619
- return py::str(x.data, x.length);
620
- }
621
- };
622
-
623
- template <>
624
- struct value_converter<qdb_string_t, py::object>
625
- {
626
- using dtype = traits::pyobject_dtype;
627
-
628
- value_converter<qdb_string_t, py::str> delegate_{};
629
-
630
- inline py::object operator()(qdb_string_t const & x) const
631
- {
632
- if (traits::is_null(x))
633
- {
634
- return dtype::null_value();
635
- }
636
-
637
- return delegate_(x);
638
- }
639
- };
640
-
641
- using qdb_string_view = ranges::counted_view<qdb_char_type const *>;
642
-
643
- template <>
644
- struct value_converter<qdb_string_t, qdb_string_view>
645
- {
646
- inline qdb_string_view operator()(qdb_string_t const & x) const
647
- {
648
- return qdb_string_view(x.data, static_cast<std::size_t>(x.length));
649
- }
650
- };
651
-
652
- template <>
653
- struct value_converter<qdb_string_t, traits::unicode_dtype>
654
- {
655
- value_converter<qdb_string_t, qdb_string_view> delegate_{};
656
-
657
- inline auto operator()(qdb_string_t const & x) const
658
- {
659
- return unicode::utf32::encode_view(unicode::utf8::decode_view(delegate_(x)));
660
- }
661
- };
662
-
663
- template <>
664
- struct value_converter<qdb_ts_range_t, py::tuple>
665
- {
666
- value_converter<qdb_timespec_t, qdb::numpy::datetime64> delegate_{};
667
-
668
- inline py::tuple operator()(qdb_ts_range_t const & x) const
669
- {
670
- return py::make_tuple(delegate_(x.begin), delegate_(x.end));
671
- }
672
- };
673
-
674
- template <>
675
- struct value_converter<py::object, qdb_blob_t>
676
- {
677
- using dtype = traits::object_dtype<py::object>;
678
-
679
- value_converter<py::bytes, qdb_blob_t> delegate_{};
680
-
681
- inline qdb_blob_t operator()(py::object const & x) const
682
- {
683
- if (dtype::is_null(x))
684
- {
685
- return traits::null_value<qdb_blob_t>();
686
- }
687
-
688
- return delegate_(x);
689
- }
690
- };
691
-
692
- template <>
693
- struct value_converter<py::object, qdb_timespec_t>
694
- {
695
- using dtype = traits::object_dtype<py::object>;
696
-
697
- value_converter<std::int64_t, qdb_timespec_t> delegate_{};
698
-
699
- inline qdb_timespec_t operator()(py::object const & x) const
700
- {
701
- if (dtype::is_null(x))
702
- {
703
- return traits::null_value<qdb_timespec_t>();
704
- }
705
-
706
- try
707
- {
708
- return delegate_(x.cast<std::int64_t>());
709
- }
710
- catch (py::cast_error const & /* e */)
711
- {
712
- throw qdb::invalid_datetime_exception{x};
713
- }
714
- }
715
- };
716
-
717
- template <>
718
- struct value_converter<py::tuple, qdb_ts_range_t>
719
- {
720
- using dtype = traits::object_dtype<py::object>;
721
-
722
- value_converter<py::object, qdb_timespec_t> delegate_{};
723
-
724
- inline qdb_ts_range_t operator()(py::tuple const & x) const
725
- {
726
- if (x.is_none()) [[unlikely]]
727
- {
728
- throw qdb::invalid_argument_exception{
729
- std::string{"Expected a Tuple of datetime, got None"}};
730
- }
731
- else if (x.size() != 2) [[unlikely]]
732
- {
733
- throw qdb::invalid_argument_exception{
734
- std::string{"A time range should be a Tuple with 2 datetimes, got "
735
- + std::to_string(x.size()) + " items in tuple"}};
736
- }
737
-
738
- qdb_timespec_t begin = delegate_(x[0]);
739
- qdb_timespec_t end = delegate_(x[1]);
740
-
741
- return qdb_ts_range_t{begin, end};
742
- }
743
- };
744
-
745
- template <>
746
- struct value_converter<traits::bytestring_dtype, qdb_blob_t>
747
- {
748
- value_converter<traits::bytestring_dtype, qdb_string_t> delegate_{};
749
-
750
- template <ranges::input_range R>
751
- inline qdb_blob_t operator()(R && x) const
752
- {
753
- qdb_string_t s = delegate_(std::forward<R &&>(x));
754
-
755
- return qdb_blob_t{static_cast<void const *>(s.data), s.length};
756
- }
757
- };
758
- } // namespace qdb::convert::detail
759
-
760
- namespace qdb::convert
761
- {
762
-
763
- ////////////////////////////////////////////////////////////////////////////////
764
- //
765
- // PUBLIC API
766
- //
767
- ///////////////////
768
- //
769
- // Functions below define the public API. Their intent to handle boilerplate and
770
- // and easier-to-use interface than the lower-level converters defined above.
771
- //
772
- ////////////////////////////////////////////////////////////////////////////////
773
-
774
- // any -> any
775
- template <typename From, typename To>
776
- static inline constexpr To value(From const & x)
777
- {
778
- detail::value_converter<From, To> c{};
779
- return c(x);
780
- }
781
-
782
- } // namespace qdb::convert