quasardb 3.14.2.dev0__cp38-cp38-macosx_11_0_arm64.whl → 3.14.2.dev4__cp38-cp38-macosx_11_0_arm64.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/CMakeFiles/CMakeDirectoryInformation.cmake +1 -1
- quasardb/Makefile +20 -20
- quasardb/__init__.py +33 -4
- quasardb/cmake_install.cmake +7 -1
- quasardb/date/CMakeFiles/CMakeDirectoryInformation.cmake +1 -1
- quasardb/date/CMakeFiles/Export/a52b05f964b070ee926bcad51d3288af/dateTargets.cmake +13 -13
- quasardb/date/Makefile +20 -20
- quasardb/date/cmake_install.cmake +7 -1
- quasardb/date/dateConfigVersion.cmake +9 -2
- quasardb/date/dateTargets.cmake +4 -8
- quasardb/libqdb_api.dylib +0 -0
- quasardb/numpy/__init__.py +58 -10
- quasardb/pandas/__init__.py +58 -102
- quasardb/pybind11/CMakeFiles/CMakeDirectoryInformation.cmake +1 -1
- quasardb/pybind11/Makefile +20 -20
- quasardb/pybind11/cmake_install.cmake +7 -1
- quasardb/quasardb.cpython-38-darwin.so +0 -0
- quasardb/range-v3/CMakeFiles/CMakeDirectoryInformation.cmake +1 -1
- quasardb/range-v3/CMakeFiles/Export/d94ef200eca10a819b5858b33e808f5b/range-v3-targets.cmake +13 -13
- quasardb/range-v3/CMakeFiles/range.v3.headers.dir/DependInfo.cmake +6 -2
- quasardb/range-v3/CMakeFiles/range.v3.headers.dir/build.make +7 -4
- quasardb/range-v3/Makefile +20 -20
- quasardb/range-v3/cmake_install.cmake +19 -1
- quasardb/range-v3/range-v3-config-version.cmake +9 -2
- quasardb/range-v3/range-v3-config.cmake +4 -8
- {quasardb-3.14.2.dev0.dist-info → quasardb-3.14.2.dev4.dist-info}/METADATA +5 -8
- quasardb-3.14.2.dev4.dist-info/RECORD +45 -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 -109
- {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/numpy.hpp
DELETED
|
@@ -1,489 +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 "traits.hpp"
|
|
36
|
-
#include "qdb/ts.h"
|
|
37
|
-
#include <pybind11/chrono.h>
|
|
38
|
-
#include <pybind11/numpy.h>
|
|
39
|
-
#include <pybind11/pybind11.h>
|
|
40
|
-
#include <pybind11/pytypes.h>
|
|
41
|
-
#include <time.h>
|
|
42
|
-
|
|
43
|
-
// A datetime64 in numpy is modeled as a scalar array, which is not integrated
|
|
44
|
-
// into pybind's adapters of numpy.
|
|
45
|
-
//
|
|
46
|
-
// In order to still be able to natively create numpy datetime64 instances, the
|
|
47
|
-
// code below proxies the data structures that live inside the numpy code. This
|
|
48
|
-
// will allow us to interact with the objects natively.
|
|
49
|
-
//
|
|
50
|
-
// This works both ways: we can accepts numpy.datetime64 as arguments, but also
|
|
51
|
-
// create/return them.
|
|
52
|
-
//
|
|
53
|
-
// Sourced from:
|
|
54
|
-
// https://raw.githubusercontent.com/numpy/numpy/master/numpy/core/include/numpy/arrayscalars.h
|
|
55
|
-
// https://raw.githubusercontent.com/numpy/numpy/master/numpy/core/include/numpy/ndarraytypes.h
|
|
56
|
-
// https://github.com/numpy/numpy/blob/master/numpy/core/include/numpy/npy_common.h#L1077
|
|
57
|
-
//
|
|
58
|
-
// Begin numpy proxy
|
|
59
|
-
//
|
|
60
|
-
// From:
|
|
61
|
-
// https://raw.githubusercontent.com/numpy/numpy/master/numpy/core/include/numpy/ndarraytypes.h
|
|
62
|
-
typedef enum
|
|
63
|
-
{
|
|
64
|
-
/* Force signed enum type, must be -1 for code compatibility */
|
|
65
|
-
NPY_FR_ERROR = -1, /* error or undetermined */
|
|
66
|
-
|
|
67
|
-
/* Start of valid units */
|
|
68
|
-
NPY_FR_Y = 0, /* Years */
|
|
69
|
-
NPY_FR_M = 1, /* Months */
|
|
70
|
-
NPY_FR_W = 2, /* Weeks */
|
|
71
|
-
/* Gap where 1.6 NPY_FR_B (value 3) was */
|
|
72
|
-
NPY_FR_D = 4, /* Days */
|
|
73
|
-
NPY_FR_h = 5, /* hours */
|
|
74
|
-
NPY_FR_m = 6, /* minutes */
|
|
75
|
-
NPY_FR_s = 7, /* seconds */
|
|
76
|
-
NPY_FR_ms = 8, /* milliseconds */
|
|
77
|
-
NPY_FR_us = 9, /* microseconds */
|
|
78
|
-
NPY_FR_ns = 10, /* nanoseconds */
|
|
79
|
-
NPY_FR_ps = 11, /* picoseconds */
|
|
80
|
-
NPY_FR_fs = 12, /* femtoseconds */
|
|
81
|
-
NPY_FR_as = 13, /* attoseconds */
|
|
82
|
-
NPY_FR_GENERIC = 14 /* unbound units, can convert to anything */
|
|
83
|
-
} NPY_DATETIMEUNIT;
|
|
84
|
-
|
|
85
|
-
// From:
|
|
86
|
-
// https://raw.githubusercontent.com/numpy/numpy/master/numpy/core/include/numpy/ndarraytypes.h
|
|
87
|
-
typedef struct
|
|
88
|
-
{
|
|
89
|
-
NPY_DATETIMEUNIT base;
|
|
90
|
-
int num;
|
|
91
|
-
} PyArray_DatetimeMetaData;
|
|
92
|
-
|
|
93
|
-
// numpy uses their own npy_int64, the definition of which I would like to omit (probing
|
|
94
|
-
// these things is complex).
|
|
95
|
-
//
|
|
96
|
-
// For simplicity's sake, we typedef it as a std::int64_t, because the intention is for it
|
|
97
|
-
// to be a 64bit int anyway.
|
|
98
|
-
//
|
|
99
|
-
// See also:
|
|
100
|
-
// https://github.com/numpy/numpy/blob/master/numpy/core/include/numpy/npy_common.h#L1077
|
|
101
|
-
typedef std::int64_t npy_datetime;
|
|
102
|
-
|
|
103
|
-
// From:
|
|
104
|
-
// https://raw.githubusercontent.com/numpy/numpy/master/numpy/core/include/numpy/arrayscalars.h
|
|
105
|
-
typedef struct
|
|
106
|
-
{
|
|
107
|
-
PyObject_HEAD npy_datetime obval;
|
|
108
|
-
PyArray_DatetimeMetaData obmeta;
|
|
109
|
-
} PyDatetimeScalarObject;
|
|
110
|
-
|
|
111
|
-
// End numpy proxy
|
|
112
|
-
|
|
113
|
-
namespace qdb
|
|
114
|
-
{
|
|
115
|
-
namespace numpy
|
|
116
|
-
{
|
|
117
|
-
namespace detail
|
|
118
|
-
{
|
|
119
|
-
inline std::time_t mkgmtime(std::tm * t) noexcept
|
|
120
|
-
{
|
|
121
|
-
#ifdef _WIN32
|
|
122
|
-
return _mkgmtime(t);
|
|
123
|
-
#else
|
|
124
|
-
return ::timegm(t);
|
|
125
|
-
#endif
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
inline std::string to_string(py::dtype const & dt) noexcept
|
|
129
|
-
{
|
|
130
|
-
return dt.attr("name").cast<py::str>();
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
inline std::string to_string(py::type const & t) noexcept
|
|
134
|
-
{
|
|
135
|
-
return t.cast<py::str>();
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
}; // namespace detail
|
|
139
|
-
|
|
140
|
-
namespace py = pybind11;
|
|
141
|
-
|
|
142
|
-
static inline std::int64_t datetime64_to_int64(py::object v)
|
|
143
|
-
{
|
|
144
|
-
if (v.is_none())
|
|
145
|
-
{
|
|
146
|
-
throw qdb::invalid_argument_exception{"Unable to convert None object time datetime64"};
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
using namespace std::chrono;
|
|
150
|
-
try
|
|
151
|
-
{
|
|
152
|
-
// Starting version 3.8, Python does not allow implicit casting from numpy.datetime64
|
|
153
|
-
// to an int, so we explicitly do it here.
|
|
154
|
-
return v.cast<std::int64_t>();
|
|
155
|
-
}
|
|
156
|
-
catch (py::cast_error const & /*e*/)
|
|
157
|
-
{
|
|
158
|
-
throw qdb::invalid_datetime_exception{v};
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Takes a `py::dtype` and converts it to our own internal dtype tag
|
|
163
|
-
inline decltype(auto) dtype_object_to_tag(py::dtype dt){
|
|
164
|
-
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
// Everything below is custom code
|
|
168
|
-
namespace array
|
|
169
|
-
{
|
|
170
|
-
|
|
171
|
-
template <concepts::dtype T>
|
|
172
|
-
using value_type_t = typename T::value_type;
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Ensures that an array matches a certain dtype, raises an exception if not.
|
|
176
|
-
*/
|
|
177
|
-
template <concepts::dtype T>
|
|
178
|
-
py::array ensure(py::array const & xs)
|
|
179
|
-
{
|
|
180
|
-
py::dtype dt = xs.dtype();
|
|
181
|
-
|
|
182
|
-
if (T::is_dtype(dt) == false) [[unlikely]]
|
|
183
|
-
{
|
|
184
|
-
std::string msg = std::string{"Provided np.ndarray dtype '"} + detail::to_string(dt)
|
|
185
|
-
+ std::string{"' incompatbile with expected dtype '"}
|
|
186
|
-
+ detail::to_string(T::dtype()) + std::string{"'"};
|
|
187
|
-
throw qdb::incompatible_type_exception{msg};
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
return xs;
|
|
191
|
-
};
|
|
192
|
-
|
|
193
|
-
template <concepts::dtype T>
|
|
194
|
-
[[nodiscard]] py::array ensure(py::handle const & h)
|
|
195
|
-
{
|
|
196
|
-
if (py::isinstance<py::array>(h)) [[likely]]
|
|
197
|
-
{
|
|
198
|
-
return ensure<T>(py::array::ensure(h));
|
|
199
|
-
}
|
|
200
|
-
else if (py::isinstance<py::list>(h))
|
|
201
|
-
{
|
|
202
|
-
return ensure<T>(py::cast<py::array>(h));
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
throw qdb::incompatible_type_exception{
|
|
206
|
-
"Expected a numpy.ndarray or list, got: " + detail::to_string(py::type::of(h))};
|
|
207
|
-
};
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Fixed width dtypes, length is fixed based on the dtype. This does *not* mean that every
|
|
211
|
-
* dtype has the same width, it can still be that this loop is used for float16 and int64
|
|
212
|
-
* and whatnot.
|
|
213
|
-
*/
|
|
214
|
-
template <concepts::dtype T>
|
|
215
|
-
requires(concepts::fixed_width_dtype<T>)
|
|
216
|
-
inline value_type_t<T> * fill_with_mask(value_type_t<T> const * input,
|
|
217
|
-
bool const * mask,
|
|
218
|
-
std::size_t size,
|
|
219
|
-
std::size_t /* itemsize */,
|
|
220
|
-
value_type_t<T> fill_value,
|
|
221
|
-
value_type_t<T> * dst)
|
|
222
|
-
{
|
|
223
|
-
value_type_t<T> const * end = input + size;
|
|
224
|
-
|
|
225
|
-
// XXX(leon): *HOT* loop, can we get rid of the conditional branch?
|
|
226
|
-
for (auto cur = input; cur != end; ++cur, ++mask, ++dst)
|
|
227
|
-
{
|
|
228
|
-
*dst = *mask ? fill_value : *cur;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
return dst;
|
|
232
|
-
};
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Variable-length encoding: significantly more tricky, since every array has a different
|
|
236
|
-
* "length" for all items.
|
|
237
|
-
*/
|
|
238
|
-
template <concepts::dtype T>
|
|
239
|
-
requires(concepts::variable_width_dtype<T>)
|
|
240
|
-
inline value_type_t<T> * fill_with_mask(value_type_t<T> const * input,
|
|
241
|
-
bool const * mask,
|
|
242
|
-
std::size_t size,
|
|
243
|
-
std::size_t itemsize,
|
|
244
|
-
value_type_t<T> fill_value,
|
|
245
|
-
value_type_t<T> * dst)
|
|
246
|
-
{
|
|
247
|
-
// code_point == 4 for e.g. UTF-32, which implies "4 bytes per char". Because in such a
|
|
248
|
-
// case, we are iterating using a wchar_t (which is already 4 bytes), we need to reduce
|
|
249
|
-
// our "stride" size by this factor.
|
|
250
|
-
std::size_t stride_size = itemsize / T::code_point_size;
|
|
251
|
-
|
|
252
|
-
// pre-fill a vector with our fill value, which we will be copying into all the right
|
|
253
|
-
// places into the resulting data.
|
|
254
|
-
std::vector<value_type_t<T>> fill_value_(stride_size, fill_value);
|
|
255
|
-
|
|
256
|
-
value_type_t<T> const * cur = input;
|
|
257
|
-
|
|
258
|
-
// XXX(leon): *HOT* loop; is there a way to vectorize this stuff, and/or
|
|
259
|
-
// get rid of some branches?
|
|
260
|
-
//
|
|
261
|
-
// One simple approach would be to pre-fill the destination array with
|
|
262
|
-
// our fill value, so that we can get rid of a branch below.
|
|
263
|
-
//
|
|
264
|
-
// Is there a SIMD version possible here?
|
|
265
|
-
|
|
266
|
-
for (std::size_t i = 0; i < size; ++i, cur += stride_size, ++mask, dst += stride_size)
|
|
267
|
-
{
|
|
268
|
-
if (*mask == true)
|
|
269
|
-
{
|
|
270
|
-
// We could probably get away with *just* setting *dst to the fill value, instead
|
|
271
|
-
// of setting the whole range.
|
|
272
|
-
std::copy(std::cbegin(fill_value_), std::cend(fill_value_), dst);
|
|
273
|
-
}
|
|
274
|
-
else
|
|
275
|
-
{
|
|
276
|
-
std::copy(cur, cur + stride_size, dst);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
return dst;
|
|
281
|
-
};
|
|
282
|
-
|
|
283
|
-
template <concepts::dtype T>
|
|
284
|
-
inline py::array fill_with_mask(
|
|
285
|
-
py::array const & input, py::array const & mask, value_type_t<T> fill_value)
|
|
286
|
-
{
|
|
287
|
-
array::ensure<T>(input);
|
|
288
|
-
|
|
289
|
-
py::array::ShapeContainer shape{{input.size()}};
|
|
290
|
-
py::array ret{input.dtype(), shape};
|
|
291
|
-
|
|
292
|
-
assert(input.size() == mask.size());
|
|
293
|
-
assert(input.size() == ret.size());
|
|
294
|
-
|
|
295
|
-
fill_with_mask<T>(static_cast<value_type_t<T> const *>(input.data()),
|
|
296
|
-
static_cast<bool const *>(mask.data()), static_cast<std::size_t>(input.size()),
|
|
297
|
-
static_cast<std::size_t>(input.itemsize()), fill_value,
|
|
298
|
-
static_cast<value_type_t<T> *>(ret.mutable_data()));
|
|
299
|
-
return ret;
|
|
300
|
-
};
|
|
301
|
-
|
|
302
|
-
template <concepts::dtype T>
|
|
303
|
-
static inline py::array fill_with_mask(py::array const & input, py::array const & mask)
|
|
304
|
-
{
|
|
305
|
-
return fill_with_mask(input, mask, T::null_value());
|
|
306
|
-
};
|
|
307
|
-
|
|
308
|
-
template <typename ValueType>
|
|
309
|
-
static void fill(py::array & xs, ValueType x) noexcept
|
|
310
|
-
{
|
|
311
|
-
// For now, don't support multi-dimensional arrays (e.g. matrices) and
|
|
312
|
-
// only plain vanilla arrays. Apart from some additional wrestling with
|
|
313
|
-
// numpy / pybind APIs, it's possible to implement though.
|
|
314
|
-
assert(xs.ndim() == 1);
|
|
315
|
-
|
|
316
|
-
std::size_t n = xs.shape(0);
|
|
317
|
-
|
|
318
|
-
if (n > 0) [[likely]]
|
|
319
|
-
{
|
|
320
|
-
ValueType * y = xs.mutable_unchecked<ValueType>().mutable_data();
|
|
321
|
-
std::fill(y, y + n, x);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
// Create empty array, do not fill any values.
|
|
326
|
-
template <typename ValueType>
|
|
327
|
-
requires(std::is_trivial_v<ValueType>)
|
|
328
|
-
static py::array initialize(py::array::ShapeContainer shape) noexcept
|
|
329
|
-
{
|
|
330
|
-
return py::array(py::dtype::of<ValueType>(), shape);
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
// Create empty array, filled with `x`
|
|
334
|
-
template <typename ValueType>
|
|
335
|
-
requires(std::is_trivial_v<ValueType>)
|
|
336
|
-
static py::array initialize(py::array::ShapeContainer shape, ValueType x) noexcept
|
|
337
|
-
{
|
|
338
|
-
py::array xs = initialize<ValueType>(shape);
|
|
339
|
-
fill(xs, x);
|
|
340
|
-
return xs;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
// Create empty array, do not fill any values.
|
|
344
|
-
template <typename ValueType>
|
|
345
|
-
requires(std::is_trivial_v<ValueType>)
|
|
346
|
-
static py::array initialize(py::ssize_t size) noexcept
|
|
347
|
-
{
|
|
348
|
-
return initialize<ValueType>({size});
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// Create empty array, filled with `x`
|
|
352
|
-
template <typename ValueType>
|
|
353
|
-
requires(std::is_trivial_v<ValueType>)
|
|
354
|
-
static py::array initialize(py::ssize_t size, ValueType x) noexcept
|
|
355
|
-
{
|
|
356
|
-
return initialize<ValueType>(py::array::ShapeContainer{size}, x);
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
template <concepts::dtype T>
|
|
360
|
-
static py::array initialize(py::array::ShapeContainer shape, value_type_t<T> x) noexcept
|
|
361
|
-
{
|
|
362
|
-
py::array xs = py::array(T::dtype(), shape);
|
|
363
|
-
fill(xs, x);
|
|
364
|
-
|
|
365
|
-
return xs;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
template <concepts::dtype D>
|
|
369
|
-
static py::array initialize(py::ssize_t size, value_type_t<D> x) noexcept
|
|
370
|
-
{
|
|
371
|
-
return initialize<D>(py::array::ShapeContainer{size}, x);
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
template <concepts::dtype T>
|
|
375
|
-
requires(concepts::fixed_width_dtype<T>)
|
|
376
|
-
py::array of_list(py::list xs)
|
|
377
|
-
{
|
|
378
|
-
using value_type = typename T::value_type;
|
|
379
|
-
std::array<py::ssize_t, 1> shape{{static_cast<py::ssize_t>(xs.size())}};
|
|
380
|
-
py::array xs_(T::dtype(), shape);
|
|
381
|
-
value_type * xs__ = xs_.mutable_unchecked<value_type>().mutable_data();
|
|
382
|
-
|
|
383
|
-
std::transform(std::begin(xs), std::end(xs), xs__, [](py::handle x) -> value_type {
|
|
384
|
-
if (x.is_none())
|
|
385
|
-
{
|
|
386
|
-
return T::null_value();
|
|
387
|
-
}
|
|
388
|
-
else
|
|
389
|
-
{
|
|
390
|
-
return py::cast<value_type>(x);
|
|
391
|
-
};
|
|
392
|
-
});
|
|
393
|
-
|
|
394
|
-
return ensure<T>(xs_);
|
|
395
|
-
};
|
|
396
|
-
|
|
397
|
-
template <concepts::dtype T>
|
|
398
|
-
requires(concepts::fixed_width_dtype<T>)
|
|
399
|
-
std::pair<py::array, py::array> of_list_with_mask(py::list xs)
|
|
400
|
-
{
|
|
401
|
-
std::array<py::ssize_t, 1> shape{{static_cast<py::ssize_t>(xs.size())}};
|
|
402
|
-
|
|
403
|
-
py::array data = of_list<T>(xs);
|
|
404
|
-
py::array mask = py::array{py::dtype::of<bool>(), shape};
|
|
405
|
-
bool * mask_ = static_cast<bool *>(mask.mutable_data());
|
|
406
|
-
|
|
407
|
-
auto is_none = [](py::handle x) -> bool { return x.is_none(); };
|
|
408
|
-
|
|
409
|
-
std::transform(std::begin(xs), std::end(xs), mask_, is_none);
|
|
410
|
-
|
|
411
|
-
return std::make_pair(data, mask);
|
|
412
|
-
};
|
|
413
|
-
|
|
414
|
-
} // namespace array
|
|
415
|
-
|
|
416
|
-
namespace detail
|
|
417
|
-
{
|
|
418
|
-
|
|
419
|
-
inline static PyTypeObject * get_datetime64_type() noexcept
|
|
420
|
-
{
|
|
421
|
-
// Note that this type is not shipped with pybind by default, and we made
|
|
422
|
-
// local modifications to the pybind/numpy.hpp code to look up this
|
|
423
|
-
// type at runtime.
|
|
424
|
-
return py::detail::npy_api::get().PyDatetimeArrType_;
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
/**
|
|
428
|
-
* Allocate a new numpy.datetime64 python object. This invokes the numpy code
|
|
429
|
-
* dynamically loaded at runtime.
|
|
430
|
-
*/
|
|
431
|
-
inline static PyDatetimeScalarObject * new_datetime64()
|
|
432
|
-
{
|
|
433
|
-
PyTypeObject * type = detail::get_datetime64_type();
|
|
434
|
-
assert(type != nullptr);
|
|
435
|
-
|
|
436
|
-
// Allocate memory
|
|
437
|
-
PyObject * res = type->tp_alloc(type, 1);
|
|
438
|
-
// Call constructor.
|
|
439
|
-
|
|
440
|
-
// TODO(leon): this _might_ not be strictly necessary, as there might
|
|
441
|
-
// be a better way to allocate this object.
|
|
442
|
-
#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 8
|
|
443
|
-
PyObject * tmp = PyObject_INIT_VAR(res, type, sizeof(PyDatetimeScalarObject));
|
|
444
|
-
#else
|
|
445
|
-
PyVarObject * tmp = PyObject_INIT_VAR(res, type, sizeof(PyDatetimeScalarObject));
|
|
446
|
-
#endif
|
|
447
|
-
|
|
448
|
-
return reinterpret_cast<PyDatetimeScalarObject *>(tmp);
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
inline bool PyDatetime64_Check(PyObject * o)
|
|
452
|
-
{
|
|
453
|
-
// TODO(leon): validate that object is actually a PyDatetime64ScalarObject (how?)
|
|
454
|
-
return true;
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
/**
|
|
458
|
-
* Convert nanoseconds int64 to a numpy datetime. Returns a new reference to a PyObject *.
|
|
459
|
-
*/
|
|
460
|
-
inline static PyObject * to_datetime64(std::int64_t ts)
|
|
461
|
-
{
|
|
462
|
-
PyDatetimeScalarObject * res = detail::new_datetime64();
|
|
463
|
-
|
|
464
|
-
res->obmeta.num = 1; // refcount ?
|
|
465
|
-
res->obmeta.base = NPY_FR_ns; // our timestamps are always in ns
|
|
466
|
-
res->obval = ts;
|
|
467
|
-
|
|
468
|
-
// Ensure that we create a new reference for the caller
|
|
469
|
-
Py_INCREF(res);
|
|
470
|
-
|
|
471
|
-
return reinterpret_cast<PyObject *>(res);
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
} // namespace detail
|
|
475
|
-
|
|
476
|
-
class datetime64 : public py::object
|
|
477
|
-
{
|
|
478
|
-
public:
|
|
479
|
-
PYBIND11_OBJECT_DEFAULT(datetime64, object, detail::PyDatetime64_Check)
|
|
480
|
-
|
|
481
|
-
explicit datetime64(std::int64_t ts)
|
|
482
|
-
: py::object(py::reinterpret_steal<py::object>(detail::to_datetime64(ts)))
|
|
483
|
-
{}
|
|
484
|
-
|
|
485
|
-
explicit datetime64(qdb_timespec_t const & ts);
|
|
486
|
-
};
|
|
487
|
-
|
|
488
|
-
} // namespace numpy
|
|
489
|
-
} // namespace qdb
|