@@ -31,6 +31,7 @@ struct arraydescr {
3131 int itemsize ;
3232 PyObject * (* getitem )(struct arrayobject * , Py_ssize_t );
3333 int (* setitem )(struct arrayobject * , Py_ssize_t , PyObject * );
34+ int (* compareitems )(const void * , const void * , Py_ssize_t );
3435 const char * formats ;
3536 int is_integer_type ;
3637 int is_signed ;
@@ -518,26 +519,48 @@ d_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
518519 return 0 ;
519520}
520521
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)
521544
522545/* Description of types.
523546 *
524547 * Don't forget to update typecode_to_mformat_code() if you add a new
525548 * typecode.
526549 */
527550static 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 },
541564 {'\0' , 0 , 0 , 0 , 0 , 0 , 0 } /* Sentinel */
542565};
543566
@@ -664,6 +687,31 @@ array_richcompare(PyObject *v, PyObject *w, int op)
664687 return res ;
665688 }
666689
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+
667715 /* Search for the first index where items are different */
668716 k = 1 ;
669717 for (i = 0 ; i < Py_SIZE (va ) && i < Py_SIZE (wa ); i ++ ) {
@@ -685,14 +733,17 @@ array_richcompare(PyObject *v, PyObject *w, int op)
685733
686734 if (k ) {
687735 /* No more items to compare -- compare sizes */
736+ compare_sizes : ;
688737 Py_ssize_t vs = Py_SIZE (va );
689738 Py_ssize_t ws = Py_SIZE (wa );
690739 int cmp ;
691740 switch (op ) {
692741 case Py_LT : cmp = vs < ws ; break ;
693742 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 ;
696747 case Py_GT : cmp = vs > ws ; break ;
697748 case Py_GE : cmp = vs >= ws ; break ;
698749 default : return NULL ; /* cannot happen */
0 commit comments