aboutsummaryrefslogtreecommitdiff
path: root/contrib/intarray/_int.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/intarray/_int.c')
-rw-r--r--contrib/intarray/_int.c300
1 files changed, 300 insertions, 0 deletions
diff --git a/contrib/intarray/_int.c b/contrib/intarray/_int.c
index d956543af5f..1c0de0bce80 100644
--- a/contrib/intarray/_int.c
+++ b/contrib/intarray/_int.c
@@ -2217,3 +2217,303 @@ querytree(PG_FUNCTION_ARGS) {
PG_RETURN_POINTER( res );
}
+
+/*
+** Additional array functions
+*/
+static int32 intarray_match_first(ArrayType *a, int32 elem);
+static ArrayType *intarray_add_elem(ArrayType *a, int32 elem);
+static ArrayType *intarray_concat_arrays(ArrayType *a, ArrayType *b);
+static ArrayType *int_to_intset(int32 elem);
+
+PG_FUNCTION_INFO_V1( intset );
+PG_FUNCTION_INFO_V1( icount );
+PG_FUNCTION_INFO_V1( sort );
+PG_FUNCTION_INFO_V1( sort_asc );
+PG_FUNCTION_INFO_V1( sort_desc );
+PG_FUNCTION_INFO_V1( uniq );
+PG_FUNCTION_INFO_V1( idx );
+PG_FUNCTION_INFO_V1( subarray );
+PG_FUNCTION_INFO_V1( intarray_push_elem );
+PG_FUNCTION_INFO_V1( intarray_push_array );
+PG_FUNCTION_INFO_V1( intarray_del_elem );
+PG_FUNCTION_INFO_V1( intset_union_elem );
+PG_FUNCTION_INFO_V1( intset_subtract );
+Datum intset(PG_FUNCTION_ARGS);
+Datum icount(PG_FUNCTION_ARGS);
+Datum sort(PG_FUNCTION_ARGS);
+Datum sort_asc(PG_FUNCTION_ARGS);
+Datum sort_desc(PG_FUNCTION_ARGS);
+Datum uniq(PG_FUNCTION_ARGS);
+Datum idx(PG_FUNCTION_ARGS);
+Datum subarray(PG_FUNCTION_ARGS);
+Datum intarray_push_elem(PG_FUNCTION_ARGS);
+Datum intarray_push_array(PG_FUNCTION_ARGS);
+Datum intarray_del_elem(PG_FUNCTION_ARGS);
+Datum intset_union_elem(PG_FUNCTION_ARGS);
+Datum intset_subtract(PG_FUNCTION_ARGS);
+
+static int32
+intarray_match_first(ArrayType *a, int32 elem) {
+ int32 *aa, c, i;
+ c = (ARRISVOID(a)) ? 0 : ARRNELEMS(a);
+ aa = ARRPTR(a);
+ for (i = 0; i < c; i++)
+ if (aa[i] == elem) return (i + 1);
+ return 0;
+}
+
+static ArrayType *
+intarray_add_elem(ArrayType *a, int32 elem) {
+ ArrayType *result;
+ int32 *r;
+ int32 c = (ARRISVOID(a)) ? 0 : ARRNELEMS(a);
+ result = new_intArrayType(c + 1);
+ r = ARRPTR(result);
+ if (c > 0) memcpy(r, ARRPTR(a), c * sizeof(int32));
+ r[c] = elem;
+ return result;
+}
+
+static ArrayType *
+intarray_concat_arrays(ArrayType *a, ArrayType *b) {
+ ArrayType *result;
+ int32 ac = (ARRISVOID(a)) ? 0 : ARRNELEMS(a);
+ int32 bc = (ARRISVOID(b)) ? 0 : ARRNELEMS(b);
+ result = new_intArrayType(ac+bc);
+ if ( ac )
+ memcpy(ARRPTR(result), ARRPTR(a), ac * sizeof(int32));
+ if ( bc )
+ memcpy(ARRPTR(result) + ac, ARRPTR(b), bc * sizeof(int32));
+ return result;
+}
+
+static ArrayType *
+int_to_intset(int32 n) {
+ ArrayType *result;
+ int32 *aa;
+ result = new_intArrayType(1);
+ aa = ARRPTR(result);
+ aa[0] = n;
+ return result;
+}
+
+static int
+compASC(const void *a, const void *b) {
+ if ( *(int4*)a == *(int4*)b ) return 0;
+ return ( *(int4*)a > *(int4*)b ) ? 1 : -1;
+}
+
+static int
+compDESC(const void *a, const void *b) {
+ if ( *(int4*)a == *(int4*)b ) return 0;
+ return ( *(int4*)a < *(int4*)b ) ? 1 : -1;
+}
+
+#define QSORT(a, direction) \
+if (ARRNELEMS(a) > 1) \
+ qsort((void*)ARRPTR(a), ARRNELEMS(a),sizeof(int4), \
+ (direction) ? compASC : compDESC )
+
+#define UNIX_UNIQ(a) a = resize_intArrayType(a, unix_uniq(ARRPTR(a), ARRNELEMS(a)))
+
+static int32
+unix_uniq(int32 *array, int32 count) {
+ register int32 i, k = 0;
+ for (i = 1; i < count; i++)
+ if (array[k] != array[i]) {
+ k++;
+ if (i > k) array[k] = array[i];
+ }
+ return (k+1);
+}
+
+Datum
+intset(PG_FUNCTION_ARGS) {
+ PG_RETURN_POINTER(int_to_intset(PG_GETARG_INT32(0)));
+}
+
+Datum
+icount(PG_FUNCTION_ARGS) {
+ ArrayType *a = (ArrayType*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));
+ int32 count = (ARRISVOID(a)) ? 0 : ARRNELEMS(a);
+ PG_FREE_IF_COPY(a, 0);
+ PG_RETURN_INT32(count);
+}
+
+Datum
+sort(PG_FUNCTION_ARGS) {
+ ArrayType *a = (ArrayType*)DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0)));
+ text *dirstr = ( fcinfo->nargs==2 ) ? PG_GETARG_TEXT_P(1) : NULL;
+ int32 dc = ( dirstr ) ? VARSIZE(dirstr)-VARHDRSZ : 0;
+ char *d = ( dirstr ) ? VARDATA(dirstr) : NULL;
+ int dir = -1;
+ if (ARRISVOID(a) || ARRNELEMS(a) < 2) PG_RETURN_POINTER(a);
+
+ if (dirstr==NULL || (dc == 3
+ && (d[0] == 'A' || d[0] == 'a')
+ && (d[1] == 'S' || d[1] == 's')
+ && (d[2] == 'C' || d[2] == 'c')))
+ dir = 1;
+ else if (dc == 4
+ && (d[0] == 'D' || d[0] == 'd')
+ && (d[1] == 'E' || d[1] == 'e')
+ && (d[2] == 'S' || d[2] == 's')
+ && (d[3] == 'C' || d[3] == 'c'))
+ dir = 0;
+ if (dir == -1)
+ elog(ERROR, "Invalid second parameter in function sort. It must be 'ASC' or 'DESC'.");
+ QSORT(a, dir);
+ PG_RETURN_POINTER(a);
+}
+
+Datum
+sort_asc(PG_FUNCTION_ARGS) {
+ ArrayType *a = (ArrayType*)DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0)));
+ if (ARRISVOID(a)) PG_RETURN_POINTER(a);
+ QSORT(a, 1);
+ PG_RETURN_POINTER(a);
+}
+
+Datum
+sort_desc(PG_FUNCTION_ARGS) {
+ ArrayType *a = (ArrayType*)DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0)));
+ if (ARRISVOID(a)) PG_RETURN_POINTER(a);
+ QSORT(a, 0);
+ PG_RETURN_POINTER(a);
+}
+
+Datum
+uniq(PG_FUNCTION_ARGS) {
+ ArrayType *a = (ArrayType*)DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0)));
+ if (ARRISVOID(a) || ARRNELEMS(a) < 2) PG_RETURN_POINTER(a);
+ UNIX_UNIQ(a);
+ PG_RETURN_POINTER(a);
+}
+
+Datum
+idx(PG_FUNCTION_ARGS) {
+ ArrayType *a = (ArrayType*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));
+ int32 result = (ARRISVOID(a)) ? 0 : ARRNELEMS(a);
+ if (result) result = intarray_match_first(a, PG_GETARG_INT32(1));
+ PG_FREE_IF_COPY(a, 0);
+ PG_RETURN_INT32(result);
+}
+
+Datum
+subarray(PG_FUNCTION_ARGS) {
+ ArrayType *a = (ArrayType*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));
+ ArrayType *result;
+ int32 start = ( PG_GETARG_INT32(1) > 0 ) ? PG_GETARG_INT32(1)-1 : PG_GETARG_INT32(1);
+ int32 len = ( fcinfo->nargs==3 ) ? PG_GETARG_INT32(2) : 0;
+ int32 end = 0;
+ int32 c;
+
+ if ( ARRISVOID(a) ) {
+ PG_FREE_IF_COPY(a, 0);
+ PG_RETURN_POINTER( new_intArrayType(0) );
+ }
+
+ c = ARRNELEMS(a);
+
+ if ( start < 0 )
+ start = c + start;
+
+ if ( len < 0 )
+ end = c + len;
+ else if ( len == 0 )
+ end = c;
+ else
+ end = start + len;
+
+ if ( end > c )
+ end = c;
+
+ if ( start < 0 )
+ start = 0;
+
+ if ( start >= end || end <= 0 ) {
+ PG_FREE_IF_COPY(a, 0);
+ PG_RETURN_POINTER( new_intArrayType(0) );
+ }
+
+
+ result = new_intArrayType(end-start);
+ if (end-start > 0)
+ memcpy(ARRPTR(result), ARRPTR(a) + start, (end-start) * sizeof(int32));
+ PG_FREE_IF_COPY(a, 0);
+ PG_RETURN_POINTER(result);
+}
+
+Datum
+intarray_push_elem(PG_FUNCTION_ARGS) {
+ ArrayType *a = (ArrayType*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));
+ ArrayType *result;
+ result = intarray_add_elem(a, PG_GETARG_INT32(1));
+ PG_FREE_IF_COPY(a, 0);
+ PG_RETURN_POINTER(result);
+}
+
+Datum
+intarray_push_array(PG_FUNCTION_ARGS) {
+ ArrayType *a = (ArrayType*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));
+ ArrayType *b = (ArrayType*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(1)));
+ ArrayType *result;
+ result = intarray_concat_arrays(a, b);
+ PG_FREE_IF_COPY(a, 0);
+ PG_FREE_IF_COPY(b, 1);
+ PG_RETURN_POINTER(result);
+}
+
+Datum
+intarray_del_elem(PG_FUNCTION_ARGS) {
+ ArrayType *a = (ArrayType*)DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0)));
+ int32 c = (ARRISVOID(a)) ? 0 : ARRNELEMS(a);
+ int32 *aa = ARRPTR(a);
+ int32 n = 0, i;
+ int32 elem = PG_GETARG_INT32(1);
+ for (i = 0; i < c; i++)
+ if (aa[i] != elem) {
+ if (i > n) aa[n++] = aa[i];
+ else n++;
+ }
+ if (c > 0) a = resize_intArrayType(a, n);
+ PG_RETURN_POINTER(a);
+}
+
+Datum
+intset_union_elem(PG_FUNCTION_ARGS) {
+ ArrayType *a = (ArrayType*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));
+ ArrayType *result;
+ result = intarray_add_elem(a, PG_GETARG_INT32(1));
+ PG_FREE_IF_COPY(a, 0);
+ QSORT(result, 1);
+ UNIX_UNIQ(result);
+ PG_RETURN_POINTER(result);
+}
+
+Datum
+intset_subtract(PG_FUNCTION_ARGS) {
+ ArrayType *a = (ArrayType*)DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0)));
+ ArrayType *b = (ArrayType*)DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1)));
+ ArrayType *result;
+ int32 ca = ARRISVOID(a);
+ int32 cb = ARRISVOID(b);
+ int32 *aa, *bb, *r;
+ int32 n = 0, i = 0, k = 0;
+ QSORT(a, 1); UNIX_UNIQ(a); ca = ARRNELEMS(a);
+ QSORT(b, 1); UNIX_UNIQ(b); cb = ARRNELEMS(b);
+ result = new_intArrayType(ca);
+ aa = ARRPTR(a);
+ bb = ARRPTR(b);
+ r = ARRPTR(result);
+ while (i < ca) {
+ if (k == cb || aa[i] < bb[k]) r[n++] = aa[i++];
+ else if (aa[i] == bb[k]) { i++; k++; }
+ else k++;
+ }
+ result = resize_intArrayType(result, n);
+ pfree(a); pfree(b);
+ PG_RETURN_POINTER(result);
+}
+