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