48
48
*
49
49
* We could allow setting the output descriptors specifically to simplify
50
50
* this step.
51
+ *
52
+ * Note that the default version will indicate that the cast can be done
53
+ * as using `arr.view(new_dtype)` if the default cast-safety is
54
+ * set to "no-cast". This default function cannot be used if a view may
55
+ * be sufficient for casting but the cast is not always "no-cast".
51
56
*/
52
57
static NPY_CASTING
53
58
default_resolve_descriptors (
54
59
PyArrayMethodObject * method ,
55
60
PyArray_DTypeMeta * * dtypes ,
56
61
PyArray_Descr * * input_descrs ,
57
- PyArray_Descr * * output_descrs )
62
+ PyArray_Descr * * output_descrs ,
63
+ npy_intp * view_offset )
58
64
{
59
65
int nin = method -> nin ;
60
66
int nout = method -> nout ;
@@ -76,6 +82,13 @@ default_resolve_descriptors(
76
82
* abstract ones or unspecified outputs). We can use the common-dtype
77
83
* operation to provide a default here.
78
84
*/
85
+ if (method -> casting == NPY_NO_CASTING ) {
86
+ /*
87
+ * By (current) definition no-casting should imply viewable. This
88
+ * is currently indicated for example for object to object cast.
89
+ */
90
+ * view_offset = 0 ;
91
+ }
79
92
return method -> casting ;
80
93
81
94
fail :
@@ -102,9 +115,10 @@ is_contiguous(
102
115
/**
103
116
* The default method to fetch the correct loop for a cast or ufunc
104
117
* (at the time of writing only casts).
105
- * The default version can return loops explicitly registered during method
106
- * creation. It does specialize contiguous loops, although has to check
107
- * all descriptors itemsizes for this.
118
+ * Note that the default function provided here will only indicate that a cast
119
+ * can be done as a view (i.e., arr.view(new_dtype)) when this is trivially
120
+ * true, i.e., for cast safety "no-cast". It will not recognize view as an
121
+ * option for other casts (e.g., viewing '>i8' as '>i4' with an offset of 4).
108
122
*
109
123
* @param context
110
124
* @param aligned
@@ -166,7 +180,7 @@ validate_spec(PyArrayMethod_Spec *spec)
166
180
"not exceed %d. (method: %s)" , NPY_MAXARGS , spec -> name );
167
181
return -1 ;
168
182
}
169
- switch (spec -> casting & ~ _NPY_CAST_IS_VIEW ) {
183
+ switch (spec -> casting ) {
170
184
case NPY_NO_CASTING :
171
185
case NPY_EQUIV_CASTING :
172
186
case NPY_SAFE_CASTING :
@@ -495,8 +509,9 @@ boundarraymethod_dealloc(PyObject *self)
495
509
496
510
497
511
/*
498
- * Calls resolve_descriptors() and returns the casting level and the resolved
499
- * descriptors as a tuple. If the operation is impossible returns (-1, None).
512
+ * Calls resolve_descriptors() and returns the casting level, the resolved
513
+ * descriptors as a tuple, and a possible view-offset (integer or None).
514
+ * If the operation is impossible returns (-1, None, None).
500
515
* May raise an error, but usually should not.
501
516
* The function validates the casting attribute compared to the returned
502
517
* casting level.
@@ -551,14 +566,15 @@ boundarraymethod__resolve_descripors(
551
566
}
552
567
}
553
568
569
+ npy_intp view_offset = NPY_MIN_INTP ;
554
570
NPY_CASTING casting = self -> method -> resolve_descriptors (
555
- self -> method , self -> dtypes , given_descrs , loop_descrs );
571
+ self -> method , self -> dtypes , given_descrs , loop_descrs , & view_offset );
556
572
557
573
if (casting < 0 && PyErr_Occurred ()) {
558
574
return NULL ;
559
575
}
560
576
else if (casting < 0 ) {
561
- return Py_BuildValue ("iO" , casting , Py_None );
577
+ return Py_BuildValue ("iO" , casting , Py_None , Py_None );
562
578
}
563
579
564
580
PyObject * result_tuple = PyTuple_New (nin + nout );
@@ -570,9 +586,22 @@ boundarraymethod__resolve_descripors(
570
586
PyTuple_SET_ITEM (result_tuple , i , (PyObject * )loop_descrs [i ]);
571
587
}
572
588
589
+ PyObject * view_offset_obj ;
590
+ if (view_offset == NPY_MIN_INTP ) {
591
+ Py_INCREF (Py_None );
592
+ view_offset_obj = Py_None ;
593
+ }
594
+ else {
595
+ view_offset_obj = PyLong_FromSsize_t (view_offset );
596
+ if (view_offset_obj == NULL ) {
597
+ Py_DECREF (result_tuple );
598
+ return NULL ;
599
+ }
600
+ }
601
+
573
602
/*
574
- * The casting flags should be the most generic casting level (except the
575
- * cast-is-view flag. If no input is parametric, it must match exactly.
603
+ * The casting flags should be the most generic casting level.
604
+ * If no input is parametric, it must match exactly.
576
605
*
577
606
* (Note that these checks are only debugging checks.)
578
607
*/
@@ -584,14 +613,15 @@ boundarraymethod__resolve_descripors(
584
613
}
585
614
}
586
615
if (self -> method -> casting != -1 ) {
587
- NPY_CASTING cast = casting & ~ _NPY_CAST_IS_VIEW ;
616
+ NPY_CASTING cast = casting ;
588
617
if (self -> method -> casting !=
589
618
PyArray_MinCastSafety (cast , self -> method -> casting )) {
590
619
PyErr_Format (PyExc_RuntimeError ,
591
620
"resolve_descriptors cast level did not match stored one. "
592
621
"(set level is %d, got %d for method %s)" ,
593
622
self -> method -> casting , cast , self -> method -> name );
594
623
Py_DECREF (result_tuple );
624
+ Py_DECREF (view_offset_obj );
595
625
return NULL ;
596
626
}
597
627
if (!parametric ) {
@@ -608,12 +638,13 @@ boundarraymethod__resolve_descripors(
608
638
"(set level is %d, got %d for method %s)" ,
609
639
self -> method -> casting , cast , self -> method -> name );
610
640
Py_DECREF (result_tuple );
641
+ Py_DECREF (view_offset_obj );
611
642
return NULL ;
612
643
}
613
644
}
614
645
}
615
646
616
- return Py_BuildValue ("iN " , casting , result_tuple );
647
+ return Py_BuildValue ("iNN " , casting , result_tuple , view_offset_obj );
617
648
}
618
649
619
650
@@ -694,8 +725,9 @@ boundarraymethod__simple_strided_call(
694
725
return NULL ;
695
726
}
696
727
728
+ npy_intp view_offset = NPY_MIN_INTP ;
697
729
NPY_CASTING casting = self -> method -> resolve_descriptors (
698
- self -> method , self -> dtypes , descrs , out_descrs );
730
+ self -> method , self -> dtypes , descrs , out_descrs , & view_offset );
699
731
700
732
if (casting < 0 ) {
701
733
PyObject * err_type = NULL , * err_value = NULL , * err_traceback = NULL ;
0 commit comments