|
11 | 11 |
|
12 | 12 | #include "pybind11.h"
|
13 | 13 | #include "detail/common.h"
|
| 14 | +#include "detail/descr.h" |
| 15 | +#include "detail/type_caster_base.h" |
14 | 16 |
|
15 | 17 | #include <deque>
|
16 | 18 | #include <initializer_list>
|
17 | 19 | #include <list>
|
18 | 20 | #include <map>
|
| 21 | +#include <memory> |
19 | 22 | #include <ostream>
|
20 | 23 | #include <set>
|
21 | 24 | #include <unordered_map>
|
@@ -349,36 +352,65 @@ struct type_caster<std::deque<Type, Alloc>> : list_caster<std::deque<Type, Alloc
|
349 | 352 | template <typename Type, typename Alloc>
|
350 | 353 | struct type_caster<std::list<Type, Alloc>> : list_caster<std::list<Type, Alloc>, Type> {};
|
351 | 354 |
|
| 355 | +template <typename ArrayType, typename V, size_t... I> |
| 356 | +ArrayType vector_to_array_impl(V &&v, index_sequence<I...>) { |
| 357 | + return {{std::move(v[I])...}}; |
| 358 | +} |
| 359 | + |
| 360 | +// Based on https://en.cppreference.com/w/cpp/container/array/to_array |
| 361 | +template <typename ArrayType, size_t N, typename V> |
| 362 | +ArrayType vector_to_array(V &&v) { |
| 363 | + return vector_to_array_impl<ArrayType, V>(std::forward<V>(v), make_index_sequence<N>{}); |
| 364 | +} |
| 365 | + |
352 | 366 | template <typename ArrayType, typename Value, bool Resizable, size_t Size = 0>
|
353 | 367 | struct array_caster {
|
354 | 368 | using value_conv = make_caster<Value>;
|
355 | 369 |
|
356 | 370 | private:
|
357 |
| - template <bool R = Resizable> |
358 |
| - bool require_size(enable_if_t<R, size_t> size) { |
359 |
| - if (value.size() != size) { |
360 |
| - value.resize(size); |
| 371 | + std::unique_ptr<ArrayType> value; |
| 372 | + |
| 373 | + template <bool R = Resizable, enable_if_t<R, int> = 0> |
| 374 | + bool convert_elements(handle seq, bool convert) { |
| 375 | + auto l = reinterpret_borrow<sequence>(seq); |
| 376 | + value.reset(new ArrayType{}); |
| 377 | + // Using `resize` to preserve the behavior exactly as it was before PR #5305 |
| 378 | + // For the `resize` to work, `Value` must be default constructible. |
| 379 | + // For `std::valarray`, this is a requirement: |
| 380 | + // https://en.cppreference.com/w/cpp/named_req/NumericType |
| 381 | + value->resize(l.size()); |
| 382 | + size_t ctr = 0; |
| 383 | + for (const auto &it : l) { |
| 384 | + value_conv conv; |
| 385 | + if (!conv.load(it, convert)) { |
| 386 | + return false; |
| 387 | + } |
| 388 | + (*value)[ctr++] = cast_op<Value &&>(std::move(conv)); |
361 | 389 | }
|
362 | 390 | return true;
|
363 | 391 | }
|
364 |
| - template <bool R = Resizable> |
365 |
| - bool require_size(enable_if_t<!R, size_t> size) { |
366 |
| - return size == Size; |
367 |
| - } |
368 | 392 |
|
| 393 | + template <bool R = Resizable, enable_if_t<!R, int> = 0> |
369 | 394 | bool convert_elements(handle seq, bool convert) {
|
370 | 395 | auto l = reinterpret_borrow<sequence>(seq);
|
371 |
| - if (!require_size(l.size())) { |
| 396 | + if (l.size() != Size) { |
372 | 397 | return false;
|
373 | 398 | }
|
374 |
| - size_t ctr = 0; |
375 |
| - for (const auto &it : l) { |
| 399 | + // The `temp` storage is needed to support `Value` types that are not |
| 400 | + // default-constructible. |
| 401 | + // Deliberate choice: no template specializations, for simplicity, and |
| 402 | + // because the compile time overhead for the specializations is deemed |
| 403 | + // more significant than the runtime overhead for the `temp` storage. |
| 404 | + std::vector<Value> temp; |
| 405 | + temp.reserve(l.size()); |
| 406 | + for (auto it : l) { |
376 | 407 | value_conv conv;
|
377 | 408 | if (!conv.load(it, convert)) {
|
378 | 409 | return false;
|
379 | 410 | }
|
380 |
| - value[ctr++] = cast_op<Value &&>(std::move(conv)); |
| 411 | + temp.emplace_back(cast_op<Value &&>(std::move(conv))); |
381 | 412 | }
|
| 413 | + value.reset(new ArrayType(vector_to_array<ArrayType, Size>(std::move(temp)))); |
382 | 414 | return true;
|
383 | 415 | }
|
384 | 416 |
|
@@ -416,12 +448,36 @@ struct array_caster {
|
416 | 448 | return l.release();
|
417 | 449 | }
|
418 | 450 |
|
419 |
| - PYBIND11_TYPE_CASTER(ArrayType, |
420 |
| - const_name<Resizable>(const_name(""), const_name("Annotated[")) |
421 |
| - + const_name("list[") + value_conv::name + const_name("]") |
422 |
| - + const_name<Resizable>(const_name(""), |
423 |
| - const_name(", FixedSize(") |
424 |
| - + const_name<Size>() + const_name(")]"))); |
| 451 | + // Code copied from PYBIND11_TYPE_CASTER macro. |
| 452 | + // Intentionally preserving the behavior exactly as it was before PR #5305 |
| 453 | + template <typename T_, enable_if_t<std::is_same<ArrayType, remove_cv_t<T_>>::value, int> = 0> |
| 454 | + static handle cast(T_ *src, return_value_policy policy, handle parent) { |
| 455 | + if (!src) { |
| 456 | + return none().release(); |
| 457 | + } |
| 458 | + if (policy == return_value_policy::take_ownership) { |
| 459 | + auto h = cast(std::move(*src), policy, parent); |
| 460 | + delete src; // WARNING: Assumes `src` was allocated with `new`. |
| 461 | + return h; |
| 462 | + } |
| 463 | + return cast(*src, policy, parent); |
| 464 | + } |
| 465 | + |
| 466 | + // NOLINTNEXTLINE(google-explicit-constructor) |
| 467 | + operator ArrayType *() { return &(*value); } |
| 468 | + // NOLINTNEXTLINE(google-explicit-constructor) |
| 469 | + operator ArrayType &() { return *value; } |
| 470 | + // NOLINTNEXTLINE(google-explicit-constructor) |
| 471 | + operator ArrayType &&() && { return std::move(*value); } |
| 472 | + |
| 473 | + template <typename T_> |
| 474 | + using cast_op_type = movable_cast_op_type<T_>; |
| 475 | + |
| 476 | + static constexpr auto name |
| 477 | + = const_name<Resizable>(const_name(""), const_name("Annotated[")) + const_name("list[") |
| 478 | + + value_conv::name + const_name("]") |
| 479 | + + const_name<Resizable>( |
| 480 | + const_name(""), const_name(", FixedSize(") + const_name<Size>() + const_name(")]")); |
425 | 481 | };
|
426 | 482 |
|
427 | 483 | template <typename Type, size_t Size>
|
|
0 commit comments