From 99f4aa39ec3df1a9e2b03e2e835f8f57db4a91dd Mon Sep 17 00:00:00 2001 From: ahl27 Date: Mon, 6 Jan 2025 19:40:58 -0500 Subject: [PATCH 1/3] Adds backend code to find order of non-int arrays, called in XVector to support order() calls --- inst/include/S4Vectors_interface.h | 12 ++++ inst/include/_S4Vectors_stubs.c | 5 ++ src/R_init_S4Vectors.c | 1 + src/S4Vectors.h | 12 ++++ src/sort_utils.c | 90 ++++++++++++++++++++++++++++++ 5 files changed, 120 insertions(+) diff --git a/inst/include/S4Vectors_interface.h b/inst/include/S4Vectors_interface.h index 45a1ce2..14f16bc 100644 --- a/inst/include/S4Vectors_interface.h +++ b/inst/include/S4Vectors_interface.h @@ -75,6 +75,18 @@ int sort_ints( int *rxbuf2 ); +int sort_void_array( + int *base, + int base_len, + const void *x, + size_t elem_size, + int desc, + int use_double_compar, + int use_radix, + unsigned short int *rxbuf1, + int *rxbuf2 +); + void get_order_of_int_pairs( const int *a, const int *b, diff --git a/inst/include/_S4Vectors_stubs.c b/inst/include/_S4Vectors_stubs.c index ce2e8ef..bcb7b59 100644 --- a/inst/include/_S4Vectors_stubs.c +++ b/inst/include/_S4Vectors_stubs.c @@ -85,6 +85,11 @@ DEFINE_CCALLABLE_STUB(int, sort_ints, ( base, base_len, x, desc, use_radix, rxbuf1, rxbuf2) ) +DEFINE_CCALLABLE_STUB(int, sort_void_array, + (int *base, int base_len, const void *x, size_t elem_size, int desc, int use_double_compar, int use_radix, unsigned short int *rxbuf1, int *rxbuf2), + ( base, base_len, x, elem_size, desc, use_double_compar, use_radix, rxbuf1, rxbuf2) +) + DEFINE_NOVALUE_CCALLABLE_STUB(get_order_of_int_pairs, (const int *a, const int *b, int nelt, int a_desc, int b_desc, int *out, int out_shift), ( a, b, nelt, a_desc, b_desc, out, out_shift) diff --git a/src/R_init_S4Vectors.c b/src/R_init_S4Vectors.c index b7fc6ec..c42a923 100644 --- a/src/R_init_S4Vectors.c +++ b/src/R_init_S4Vectors.c @@ -129,6 +129,7 @@ void R_init_S4Vectors(DllInfo *info) REGISTER_CCALLABLE(_get_matches_of_ordered_int_pairs); REGISTER_CCALLABLE(_get_order_of_int_quads); REGISTER_CCALLABLE(_get_matches_of_ordered_int_quads); + REGISTER_CCALLABLE(_sort_void_array); /* hash_utils.c */ REGISTER_CCALLABLE(_new_htab); diff --git a/src/S4Vectors.h b/src/S4Vectors.h index 02d7fc4..2d0e577 100644 --- a/src/S4Vectors.h +++ b/src/S4Vectors.h @@ -195,6 +195,18 @@ void _get_matches_of_ordered_int_quads( int out_shift ); +int _sort_void_array( + int *base, + int base_len, + const void *x, + size_t elem_size, + int desc, + int use_double_compar, + int use_radix, + unsigned short int *rxbuf1, + int *rxbuf2 +); + /* hash_utils.c */ diff --git a/src/sort_utils.c b/src/sort_utils.c index d2a3af8..3e0d647 100644 --- a/src/sort_utils.c +++ b/src/sort_utils.c @@ -13,6 +13,8 @@ static const int *aa, *bb, *cc, *dd; static int aa_desc, bb_desc, cc_desc, dd_desc; +static size_t byte_elem_size; +static const unsigned char *global_byte_array; #define COMPARE_TARGET_INTS(target, i1, i2, desc) \ ((desc) ? (target)[(i2)] - (target)[(i1)] \ @@ -86,6 +88,27 @@ static int compar4_stable(const void *p1, const void *p2) return i1 - i2; } +static int comparbyte_stable(const void *p1, const void *p2){ + int i1, i2, ret; + i1 = *((const int *) p1); + i2 = *((const int *) p2); + ret = memcmp(&(global_byte_array[i1*byte_elem_size]), &(global_byte_array[i2*byte_elem_size]), byte_elem_size); + if(aa_desc) ret *= -1; + return ret == 0 ? i1 - i2 : ret; +} + +static int compardouble_stable(const void *p1, const void *p2){ + // can't use memcmp for doubles unfortunately + int i1, i2, ret; + i1 = *((const int *) p1); + i2 = *((const int *) p2); + double v1 = ((double*)global_byte_array)[i1]; + double v2 = ((double*)global_byte_array)[i2]; + ret = (v1 > v2) - (v1 < v2); + if(aa_desc) ret *= -1; + return ret == 0 ? i1 - i2 : ret; +} + static void qsort1(int *base, int base_len, const int *a, int a_desc) { aa = a; @@ -93,6 +116,18 @@ static void qsort1(int *base, int base_len, const int *a, int a_desc) qsort(base, base_len, sizeof(int), compar1_stable); } +static void qsort_void(int *base, int base_len, const void *a, size_t a_size, + int a_desc, int use_double_compar){ + // have to cast to bytes so we can index + global_byte_array = (const unsigned char*)a; + aa_desc = a_desc; + byte_elem_size = a_size; + if(!use_double_compar) + qsort(base, base_len, sizeof(int), comparbyte_stable); + else + qsort(base, base_len, sizeof(int), compardouble_stable); +} + static void qsort2(int *base, int base_len, const int *a, const int *b, int a_desc, int b_desc) @@ -1350,3 +1385,58 @@ void _get_matches_of_ordered_int_quads( return; } +/**************************************************************************** + * Getting the order of a void* array using memcmp + * + */ + +/* base: 0-based indices into 'x'. + rxbuf1, rxbuf2: NULL or user-allocated buffers of length 'base_len'. + Returns 0 if nothing to sort, that is, if 'base' is already sorted with + respect to 'x'. Otherwise returns 1, or a negative value if an error + occurred. Has a dedicated switch for sorting float/double...it's clunky, + but I couldn't think of a better way. Primary use-case is XRaw anyway, + so it should be a huge deal. */ +int _sort_void_array(int *base, int base_len, + const void *x, size_t elem_size, + int desc, int use_double_compar, + int use_radix, unsigned short int *rxbuf1, int *rxbuf2) +{ + // will add this in eventually, not critical for functionality + /* + int qsort_cutoff, ret, auto_rxbuf1, auto_rxbuf2; + + rxtargets[0] = x; + rxdescs[0] = desc; + + qsort_cutoff = (use_radix && can_use_rxsort()) ? 1024 : base_len; + ret = lucky_sort_targets(base, base_len, rxtargets, rxdescs, 1, qsort_cutoff); + if (ret != 0) + return ret != 1; + + auto_rxbuf1 = rxbuf1 == NULL; + if (auto_rxbuf1) { + rxbuf1 = alloc_rxbuf1(base_len); + if (rxbuf1 == NULL) + return -1; + } + auto_rxbuf2 = rxbuf2 == NULL; + if (auto_rxbuf2) { + rxbuf2 = alloc_rxbuf2(base_len, rxbuf1, auto_rxbuf1); + if (rxbuf2 == NULL) + return -2; + } + + last_rxlevel = 1; + base_uidx_buf = rxbuf1; + rxsort_rec(base, base_len, rxbuf2, 0, 0); + + if (auto_rxbuf2) + free(rxbuf2); + if (auto_rxbuf1) + free(rxbuf1); + */ + + qsort_void(base, base_len, x, elem_size, desc, use_double_compar); + return 1; +} From a6fe1b757d64f31c4a01df69d1e4b12cdd0f6dd7 Mon Sep 17 00:00:00 2001 From: ahl27 Date: Wed, 8 Jan 2025 10:32:28 -0500 Subject: [PATCH 2/3] fix ordering of function declarations --- inst/include/S4Vectors_interface.h | 24 ++++++++++++------------ inst/include/_S4Vectors_stubs.c | 10 +++++----- src/sort_utils.c | 2 ++ 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/inst/include/S4Vectors_interface.h b/inst/include/S4Vectors_interface.h index 14f16bc..1ab272d 100644 --- a/inst/include/S4Vectors_interface.h +++ b/inst/include/S4Vectors_interface.h @@ -75,18 +75,6 @@ int sort_ints( int *rxbuf2 ); -int sort_void_array( - int *base, - int base_len, - const void *x, - size_t elem_size, - int desc, - int use_double_compar, - int use_radix, - unsigned short int *rxbuf1, - int *rxbuf2 -); - void get_order_of_int_pairs( const int *a, const int *b, @@ -171,6 +159,18 @@ void get_matches_of_ordered_int_quads( int out_shift ); +int sort_void_array( + int *base, + int base_len, + const void *x, + size_t elem_size, + int desc, + int use_double_compar, + int use_radix, + unsigned short int *rxbuf1, + int *rxbuf2 +); + /* * Hash table management. * (see hash_utils.c) diff --git a/inst/include/_S4Vectors_stubs.c b/inst/include/_S4Vectors_stubs.c index bcb7b59..8599975 100644 --- a/inst/include/_S4Vectors_stubs.c +++ b/inst/include/_S4Vectors_stubs.c @@ -85,11 +85,6 @@ DEFINE_CCALLABLE_STUB(int, sort_ints, ( base, base_len, x, desc, use_radix, rxbuf1, rxbuf2) ) -DEFINE_CCALLABLE_STUB(int, sort_void_array, - (int *base, int base_len, const void *x, size_t elem_size, int desc, int use_double_compar, int use_radix, unsigned short int *rxbuf1, int *rxbuf2), - ( base, base_len, x, elem_size, desc, use_double_compar, use_radix, rxbuf1, rxbuf2) -) - DEFINE_NOVALUE_CCALLABLE_STUB(get_order_of_int_pairs, (const int *a, const int *b, int nelt, int a_desc, int b_desc, int *out, int out_shift), ( a, b, nelt, a_desc, b_desc, out, out_shift) @@ -120,6 +115,11 @@ DEFINE_NOVALUE_CCALLABLE_STUB(get_matches_of_ordered_int_quads, ( a1, b1, c1, d1, o1, nelt1, a2, b2, c2, d2, o2, nelt2, nomatch, out, out_shift) ) +DEFINE_CCALLABLE_STUB(int, sort_void_array, + (int *base, int base_len, const void *x, size_t elem_size, int desc, int use_double_compar, int use_radix, unsigned short int *rxbuf1, int *rxbuf2), + ( base, base_len, x, elem_size, desc, use_double_compar, use_radix, rxbuf1, rxbuf2) +) + /* * Stubs for callables defined in hash_utils.c */ diff --git a/src/sort_utils.c b/src/sort_utils.c index 3e0d647..8f1fa63 100644 --- a/src/sort_utils.c +++ b/src/sort_utils.c @@ -1403,6 +1403,8 @@ int _sort_void_array(int *base, int base_len, int use_radix, unsigned short int *rxbuf1, int *rxbuf2) { // will add this in eventually, not critical for functionality + // Below section is copied from _sort_int_array, will need to be adapted + // Until this is incorporated, use_radix, rxbuf1, and rxbuf2 are not used /* int qsort_cutoff, ret, auto_rxbuf1, auto_rxbuf2; From 2f0a0e1ddae92ab24e3a44bd2c2522e82af4752d Mon Sep 17 00:00:00 2001 From: ahl27 Date: Wed, 8 Jan 2025 10:37:49 -0500 Subject: [PATCH 3/3] minor update to comment --- src/sort_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sort_utils.c b/src/sort_utils.c index 8f1fa63..e1db74a 100644 --- a/src/sort_utils.c +++ b/src/sort_utils.c @@ -1396,7 +1396,7 @@ void _get_matches_of_ordered_int_quads( respect to 'x'. Otherwise returns 1, or a negative value if an error occurred. Has a dedicated switch for sorting float/double...it's clunky, but I couldn't think of a better way. Primary use-case is XRaw anyway, - so it should be a huge deal. */ + so it shouldn't be a huge deal. */ int _sort_void_array(int *base, int base_len, const void *x, size_t elem_size, int desc, int use_double_compar,