@@ -31,6 +31,7 @@ struct arraydescr {
31
31
int itemsize ;
32
32
PyObject * (* getitem )(struct arrayobject * , Py_ssize_t );
33
33
int (* setitem )(struct arrayobject * , Py_ssize_t , PyObject * );
34
+ int (* compareitems )(const void * , const void * , Py_ssize_t );
34
35
const char * formats ;
35
36
int is_integer_type ;
36
37
int is_signed ;
@@ -518,26 +519,48 @@ d_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
518
519
return 0 ;
519
520
}
520
521
522
+ #define DEFINE_COMPAREITEMS (code , type ) \
523
+ static int \
524
+ code##_compareitems(const void *lhs, const void *rhs, Py_ssize_t length) \
525
+ { \
526
+ const type *a = lhs, *b = rhs; \
527
+ for (Py_ssize_t i = 0; i < length; ++i) \
528
+ if (a[i] != b[i]) \
529
+ return a[i] < b[i] ? -1 : 1; \
530
+ return 0; \
531
+ }
532
+
533
+ DEFINE_COMPAREITEMS (b , signed char )
534
+ DEFINE_COMPAREITEMS (BB , unsigned char )
535
+ DEFINE_COMPAREITEMS (u , Py_UNICODE )
536
+ DEFINE_COMPAREITEMS (h , short )
537
+ DEFINE_COMPAREITEMS (HH , unsigned short )
538
+ DEFINE_COMPAREITEMS (i , int )
539
+ DEFINE_COMPAREITEMS (II , unsigned int )
540
+ DEFINE_COMPAREITEMS (l , long )
541
+ DEFINE_COMPAREITEMS (LL , unsigned long )
542
+ DEFINE_COMPAREITEMS (q , long long )
543
+ DEFINE_COMPAREITEMS (QQ , unsigned long long)
521
544
522
545
/* Description of types.
523
546
*
524
547
* Don't forget to update typecode_to_mformat_code() if you add a new
525
548
* typecode.
526
549
*/
527
550
static const struct arraydescr descriptors [] = {
528
- {'b' , 1 , b_getitem , b_setitem , "b" , 1 , 1 },
529
- {'B' , 1 , BB_getitem , BB_setitem , "B" , 1 , 0 },
530
- {'u' , sizeof (Py_UNICODE ), u_getitem , u_setitem , "u" , 0 , 0 },
531
- {'h' , sizeof (short ), h_getitem , h_setitem , "h" , 1 , 1 },
532
- {'H' , sizeof (short ), HH_getitem , HH_setitem , "H" , 1 , 0 },
533
- {'i' , sizeof (int ), i_getitem , i_setitem , "i" , 1 , 1 },
534
- {'I' , sizeof (int ), II_getitem , II_setitem , "I" , 1 , 0 },
535
- {'l' , sizeof (long ), l_getitem , l_setitem , "l" , 1 , 1 },
536
- {'L' , sizeof (long ), LL_getitem , LL_setitem , "L" , 1 , 0 },
537
- {'q' , sizeof (long long ), q_getitem , q_setitem , "q" , 1 , 1 },
538
- {'Q' , sizeof (long long ), QQ_getitem , QQ_setitem , "Q" , 1 , 0 },
539
- {'f' , sizeof (float ), f_getitem , f_setitem , "f" , 0 , 0 },
540
- {'d' , sizeof (double ), d_getitem , d_setitem , "d" , 0 , 0 },
551
+ {'b' , 1 , b_getitem , b_setitem , b_compareitems , "b" , 1 , 1 },
552
+ {'B' , 1 , BB_getitem , BB_setitem , BB_compareitems , "B" , 1 , 0 },
553
+ {'u' , sizeof (Py_UNICODE ), u_getitem , u_setitem , u_compareitems , "u" , 0 , 0 },
554
+ {'h' , sizeof (short ), h_getitem , h_setitem , h_compareitems , "h" , 1 , 1 },
555
+ {'H' , sizeof (short ), HH_getitem , HH_setitem , HH_compareitems , "H" , 1 , 0 },
556
+ {'i' , sizeof (int ), i_getitem , i_setitem , i_compareitems , "i" , 1 , 1 },
557
+ {'I' , sizeof (int ), II_getitem , II_setitem , II_compareitems , "I" , 1 , 0 },
558
+ {'l' , sizeof (long ), l_getitem , l_setitem , l_compareitems , "l" , 1 , 1 },
559
+ {'L' , sizeof (long ), LL_getitem , LL_setitem , LL_compareitems , "L" , 1 , 0 },
560
+ {'q' , sizeof (long long ), q_getitem , q_setitem , q_compareitems , "q" , 1 , 1 },
561
+ {'Q' , sizeof (long long ), QQ_getitem , QQ_setitem , QQ_compareitems , "Q" , 1 , 0 },
562
+ {'f' , sizeof (float ), f_getitem , f_setitem , NULL , "f" , 0 , 0 },
563
+ {'d' , sizeof (double ), d_getitem , d_setitem , NULL , "d" , 0 , 0 },
541
564
{'\0' , 0 , 0 , 0 , 0 , 0 , 0 } /* Sentinel */
542
565
};
543
566
@@ -664,6 +687,31 @@ array_richcompare(PyObject *v, PyObject *w, int op)
664
687
return res ;
665
688
}
666
689
690
+ if (va -> ob_descr == wa -> ob_descr && va -> ob_descr -> compareitems != NULL ) {
691
+ /* Fast path:
692
+ arrays with same types can have their buffers compared directly */
693
+ Py_ssize_t common_length = Py_MIN (Py_SIZE (va ), Py_SIZE (wa ));
694
+ int result = va -> ob_descr -> compareitems (va -> ob_item , wa -> ob_item ,
695
+ common_length );
696
+ if (result == 0 )
697
+ goto compare_sizes ;
698
+
699
+ int cmp ;
700
+ switch (op ) {
701
+ case Py_LT : cmp = result < 0 ; break ;
702
+ case Py_LE : cmp = result <= 0 ; break ;
703
+ case Py_EQ : cmp = result == 0 ; break ;
704
+ case Py_NE : cmp = result != 0 ; break ;
705
+ case Py_GT : cmp = result > 0 ; break ;
706
+ case Py_GE : cmp = result >= 0 ; break ;
707
+ default : return NULL ; /* cannot happen */
708
+ }
709
+ PyObject * res = cmp ? Py_True : Py_False ;
710
+ Py_INCREF (res );
711
+ return res ;
712
+ }
713
+
714
+
667
715
/* Search for the first index where items are different */
668
716
k = 1 ;
669
717
for (i = 0 ; i < Py_SIZE (va ) && i < Py_SIZE (wa ); i ++ ) {
@@ -685,14 +733,17 @@ array_richcompare(PyObject *v, PyObject *w, int op)
685
733
686
734
if (k ) {
687
735
/* No more items to compare -- compare sizes */
736
+ compare_sizes : ;
688
737
Py_ssize_t vs = Py_SIZE (va );
689
738
Py_ssize_t ws = Py_SIZE (wa );
690
739
int cmp ;
691
740
switch (op ) {
692
741
case Py_LT : cmp = vs < ws ; break ;
693
742
case Py_LE : cmp = vs <= ws ; break ;
694
- case Py_EQ : cmp = vs == ws ; break ;
695
- case Py_NE : cmp = vs != ws ; break ;
743
+ /* If the lengths were not equal,
744
+ the earlier fast-path check would have caught that. */
745
+ case Py_EQ : assert (vs == ws ); cmp = 1 ; break ;
746
+ case Py_NE : assert (vs == ws ); cmp = 0 ; break ;
696
747
case Py_GT : cmp = vs > ws ; break ;
697
748
case Py_GE : cmp = vs >= ws ; break ;
698
749
default : return NULL ; /* cannot happen */
0 commit comments