CC=gcc
AR=ar rcv
RANLIB=ranlib
-LD=ld -x -shared
+LD=ld -x -shared
INCLUDE=-I.
CFLAGS=-Wall -g -O2 -pedantic -ansi -DASSERT_CORE -D_GNU_SOURCE -DHAVE_POLL_H -DHAVE_SYS_POLL_H -DHAVE_HSTRERROR
-LIB=-L. -ltedtools
+LIB=-L. -ltedtools -lm
OBJS=tlog.o tmalloc.o tools.o prs_hmap.o sfxstr.o \
- regis.o prs_inf.o shmem.o tcp.o udp.o connpool.o
-PROGS=sfxtest hextest inftest kilter
+ regis.o prs_inf.o shmem.o tcp.o udp.o connpool.o \
+ psort.o
+PROGS=sfxtest hextest inftest kilter psortex
.SUFFIXES: .o.c
--- /dev/null
+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+#include "tmalloc.h"
+#include "psort.h"
+
+/*
+ * this defines only for faster code
+ */
+#define insert_full(val) do { \
+ tmp = sobj->last; \
+ if ( sobj->free ) \
+ (*(sobj->free))( tmp->value ); \
+ sobj->last = sobj->last->prev; /* current last */ \
+ tmp->value = (val); \
+ curitem = sobj->last; \
+ curitem->next = tmp->prev = tmp->next = NULL; \
+ \
+ do { \
+ if ( (*(sobj->cmpr))( curitem->value, (val) ) <= 0 ) { \
+ tmp->next = curitem->next; \
+ tmp->prev = curitem; \
+ \
+ if ( curitem->next ) /* not last */ \
+ curitem->next->prev = tmp; \
+ else \
+ sobj->last = tmp; \
+ curitem->next = tmp; \
+ break; \
+ } \
+ curitem = curitem->prev; \
+ } while ( curitem ); \
+ /* insert to first position */ \
+ if ( !tmp->prev ) { \
+ sobj->first->prev = tmp; \
+ tmp->next = sobj->first; \
+ sobj->first = tmp; \
+ } \
+} while(0)
+
+#define insert_notfull( val ) do { \
+ tmp = &(sobj->buf[sobj->curlen]); \
+ tmp->value = (val); \
+ previtem = NULL; \
+ curitem = sobj->first; \
+ do { \
+ if ( (*(sobj->cmpr))( curitem->value, tmp->value ) > 0 ) { \
+ tmp->next = curitem; \
+ curitem->prev = tmp; \
+ tmp->prev = previtem; \
+ if ( previtem ) \
+ previtem->next = tmp; \
+ else { \
+ sobj->first->prev = tmp; \
+ sobj->first = tmp; \
+ } \
+ break; \
+ } \
+ previtem = curitem; \
+ curitem = curitem->next; \
+ } while( curitem ); \
+ if ( ! tmp->next ) { /*not inserted*/ \
+ sobj->last->next = tmp; \
+ tmp->prev = sobj->last; \
+ sobj->last = tmp; \
+ } \
+} while(0)
+
+
+
+/*
+ * Initialization
+ * If input options are invalid, return -1
+ * if no memory return 1
+ * If success return 0
+ */
+int
+PS_init( SORT* sobj, int buflen, compare_sort func, ffree ffunc ) {
+ if ( ! sobj ) return -1;
+ if ( ! func ) return -1;
+ if ( buflen <= 0 ) return -1;
+
+ sobj->buf = (SORTITEM*)tmalloc( sizeof(SORTITEM)*buflen );
+
+ memset( (void*)sobj->buf, 0, sizeof(SORTITEM)*buflen );
+ sobj->buflen = buflen;
+ sobj->cmpr = func;
+ sobj->free = ffunc;
+ sobj->curlen = 0;
+
+ sobj->first = sobj->last = sobj->buf;
+ sobj->curitem = NULL;
+
+ return 0;
+}
+
+/*
+ * finish...
+ * clear memory
+ */
+void
+PS_clear( SORT* sobj ) {
+ if ( sobj->free ) {
+ int i;
+ for(i=0; i<sobj->curlen; i++ )
+ (*(sobj->free))( sobj->buf[i].value );
+ }
+ if ( sobj->buf )
+ tfree( sobj->buf );
+ memset( (void*)sobj, 0, sizeof(SORT) );
+}
+
+/*
+ * Reset sort object..
+ */
+void
+PS_reset( SORT* sobj ) {
+ int i;
+
+ if ( sobj->free ) {
+ for(i=0; i<sobj->curlen; i++ );
+ (*(sobj->free))( sobj->buf[i].value );
+ }
+ memset( (void*)sobj->buf, 0, sizeof(SORTITEM)*sobj->buflen );
+ sobj->curlen = 0;
+ sobj->first = sobj->last = sobj->buf;
+ sobj->curitem = NULL;
+}
+
+/*
+ * Insert
+ */
+int
+PS_insert( SORT* sobj, void* nobj ) {
+ SORTITEM *curitem, *previtem, *tmp;
+
+ /* first insertion */
+ if ( ! sobj->curlen ) {
+ sobj->first->value = nobj;
+ sobj->curlen++;
+ return 1;
+ }
+
+ if ( sobj->curlen == sobj->buflen ) {
+ if ( (*(sobj->cmpr))( sobj->last->value, nobj ) > 0 ) {
+ if ( sobj->buflen == 1 ) {
+ if ( sobj->free )
+ (*(sobj->free))( sobj->last->value );
+ sobj->last->value = nobj;
+ } else
+ insert_full( nobj );
+ return 1;
+ }
+ } else {
+ insert_notfull( nobj );
+ sobj->curlen++;
+ return 1;
+ }
+
+ return 0;
+}
+
+static compare_sort compareobject;
+static int highlevelcompare( const void *a, const void *b ) {
+ return (*compareobject)( *(void**)a, *(void**)b );
+}
+
+/*
+ * Insert array, if defined free function,
+ * unused item will be freeed
+ */
+
+#define RECOMMEND_M(N) ( ((N)<8000) ? ( 23.0+1.5*pow((N),0.6) ) : pow(( 8.05 * log((N)) - 53.53 ),2.0) )
+void
+PS_bulkinsert( SORT* sobj, void** nobjs, int len ) {
+ register SORTITEM *curitem, *tmp;
+ register void** ptr = nobjs;
+
+ if ( !sobj->curlen ) {
+ int initlen = len;
+ if ( len > sobj->buflen ) {
+ if ( sobj->buflen < RECOMMEND_M( len ) )
+ initlen = sobj->buflen;
+ }
+ curitem = sobj->first;
+ compareobject = sobj->cmpr;
+ if ( initlen > 1 )
+ qsort( nobjs, initlen, sizeof(void*), highlevelcompare );
+ ptr = nobjs;
+ while( ptr - nobjs < initlen && sobj->curlen != sobj->buflen ) {
+ curitem->value = *ptr;
+ if ( sobj->curlen ) {
+ curitem->prev = curitem - 1;
+ curitem->prev->next = curitem;
+ }
+ curitem++;
+ sobj->curlen++;
+ ptr++;
+ }
+ sobj->last = curitem-1;
+
+ if ( sobj->free && initlen != sobj->buflen ) {
+ while( ptr - nobjs < len ) {
+ (*(sobj->free))( *ptr );
+ ptr++;
+ }
+ return;
+ }
+ } else {
+ while( ptr - nobjs < len && sobj->curlen != sobj->buflen ) {
+ PS_insert( sobj, *ptr ); /* buflen is very small, so we can use function call */
+ ptr++;
+ }
+ }
+
+ if ( sobj->free ) {
+ while( ptr - nobjs < len ) {
+ if ( (*(sobj->cmpr))( sobj->last->value, *ptr ) > 0 ) {
+ if ( sobj->buflen == 1 ) {
+ (*(sobj->free))( sobj->last->value );
+ sobj->last->value = *ptr;
+ } else
+ insert_full( *ptr );
+ } else
+ (*(sobj->free))( *ptr );
+ ptr++;
+ }
+ } else {
+ while( ptr - nobjs < len ) {
+ if ( (*(sobj->cmpr))( sobj->last->value, *ptr ) > 0 ) {
+ if ( sobj->buflen == 1 )
+ sobj->last->value = *ptr;
+ else
+ insert_full( *ptr );
+ }
+ ptr++;
+ }
+ }
+}
+
+/*
+ * insert a-la qsort, require sobj->free = NULL
+ */
+int
+PS_bulkplain( SORT* sobj, void* nobjs, int size, int len ) {
+ register SORTITEM *curitem, *tmp;
+ register char* ptr = (char*)nobjs;
+
+ if ( sobj->free )
+ return 1;
+
+ if ( !sobj->curlen ) {
+ int initlen = len;
+ if ( len > sobj->buflen ) {
+ if ( sobj->buflen < RECOMMEND_M( len ) )
+ initlen = sobj->buflen;
+ }
+ curitem = sobj->first;
+ if ( initlen > 1 )
+ qsort( nobjs, initlen, size, sobj->cmpr );
+ ptr = (char*)nobjs;
+ initlen *= size;
+ while( ptr - (char*)nobjs < initlen && sobj->curlen != sobj->buflen ) {
+ curitem->value = (void*)ptr;
+ if ( sobj->curlen ) {
+ curitem->prev = curitem - 1;
+ curitem->prev->next = curitem;
+ }
+ curitem++;
+ sobj->curlen++;
+ ptr += size;
+ }
+ sobj->last = curitem-1;
+
+ } else {
+ while( ( ptr - (char*)nobjs )/size < len && sobj->curlen != sobj->buflen ) {
+ PS_insert( sobj, (void*)ptr ); /* buflen is very small, so we can use function call */
+ ptr += size;
+ }
+ }
+
+ len *= size;
+ while( ptr - (char*)nobjs < len ) {
+ if ( (*(sobj->cmpr))( sobj->last->value, (void*)ptr ) > 0 ) {
+ if ( sobj->buflen == 1 )
+ sobj->last->value = (void*)ptr;
+ else
+ insert_full( (void*)ptr );
+ }
+ ptr += size;
+ }
+
+ return 0;
+}
+
+/*
+ * init_iterator, return 0 if success
+ */
+int
+PS_init_iterator( SORT* sobj, int start ) {
+ if ( sobj->curlen <= 0 || start<0 || start >= sobj->curlen )
+ return 1;
+ sobj->curitem = sobj->first;
+ while ( start ) {
+ sobj->curitem = sobj->curitem->next;
+ start--;
+ }
+ return 0;
+}
+
+/*
+ * return next sorted value or NULL
+ */
+void*
+PS_getnext( SORT* sobj ) {
+ void *value = NULL;
+ if ( sobj->curitem )
+ value = sobj->curitem->value;
+ else
+ return NULL;
+
+ sobj->curitem = ( sobj->curitem->next == NULL || sobj->curitem->next == sobj->first ) ? NULL : sobj->curitem->next;
+
+ return value;
+}
+
+int
+PS_number( SORT* sobj ) {
+ return sobj->curlen;
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __PSORT_H__
+#define __PSORT_H__
+
+typedef int (*compare_sort)(const void*, const void*);
+typedef void (*ffree)(void*);
+
+typedef struct SORTITEM {
+ void* value;
+ struct SORTITEM *prev;
+ struct SORTITEM *next;
+} SORTITEM;
+
+typedef struct {
+ SORTITEM* buf; /* buffer */
+ int buflen; /* length of buffer in items */
+ int curlen; /* current number of items */
+ compare_sort cmpr; /* compare two items */
+ ffree free; /* free mem unused item, may be NULL */
+
+ /* pointer for sorting */
+ SORTITEM* first;
+ SORTITEM* last;
+
+ SORTITEM* curitem; /* current position for iterator */
+} SORT;
+
+/*
+ * init object
+ */
+int PS_init( SORT* sobj, int buflen, compare_sort func, ffree ffunc );
+/*
+ * reset sort object to initial state
+ */
+void PS_reset( SORT* sobj );
+/*
+ * clear sort object (after it it's need to call PS_init)
+ */
+void PS_clear( SORT* sobj );
+
+/*
+ * functions for go trought sorted array
+ */
+int PS_init_iterator( SORT* sobj, int start );
+void* PS_getnext( SORT* sobj );
+
+/*
+ * insert, return 1 if inserted
+ */
+int PS_insert( SORT* sobj, void* nobj );
+
+/*
+ * bulk insert
+ */
+void PS_bulkinsert( SORT* sobj, void** nobjs, int len );
+/*
+ * insert a-la qsort, require sobj->free = NULL
+ */
+int PS_bulkplain( SORT* sobj, void* nobjs, int size, int len );
+
+/*
+ * return number of result in buffer
+ */
+int PS_number( SORT* sobj );
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "psort.h"
+
+#define LENARR (1<<10)
+#define LIMIT 16
+
+/*
+ * Example of struct
+ */
+typedef struct {
+ int id;
+ char *value;
+} EXMPL;
+
+/*
+ * compare two struct
+ */
+static int
+exstr_cmp(const void *a, const void *b) {
+ return ((EXMPL*)a)->id - ((EXMPL*)b)->id;
+}
+
+/*
+ * free struct
+ */
+static void
+exstr_free( void *a ) {
+ if ( a ) {
+ if ( ((EXMPL*)a)->value ) free( ((EXMPL*)a)->value );
+ free( a );
+ }
+}
+
+int
+main(int argn, char *argv[]) {
+ int i;
+ EXMPL *ptr=NULL;
+ SORT sobj;
+ int inserted=0;
+ EXMPL **aptr;
+
+ if ( PS_init( &sobj, LIMIT, exstr_cmp, exstr_free ) ) {
+ fprintf(stderr,"No memory\n");
+ return 1;
+ }
+ srandom(1);
+ printf("Test insert:\n");
+ for(i=0;i<LENARR;i++) {
+ if ( ! ptr ) {
+ ptr = (EXMPL*)malloc( sizeof(EXMPL) );
+ if ( ! ptr ) {
+ fprintf(stderr,"No memory\n");
+ return 1;
+ }
+ ptr->value=(char*)malloc( 64 );
+ if ( ! ptr->value ) {
+ fprintf(stderr,"No memory\n");
+ return 1;
+ }
+ }
+ ptr->id = random() % LENARR;
+ sprintf( ptr->value, "Value: %d, startnum: %d", ptr->id, i );
+
+ if ( PS_insert( &sobj, (void*)ptr ) ) {
+ /* tuple has been inserted, in
+ other case we can reuse space :) */
+ ptr = NULL;
+ inserted++;
+ }
+ }
+
+ PS_init_iterator( &sobj, 0 );
+ i=1;
+ while( (ptr=(EXMPL*)PS_getnext( &sobj )) != NULL ) {
+ printf("%d: '%s'\n", i, ptr->value);
+ i++;
+ }
+ printf("Stat: total %d; limit %d; inserted %d;\n", LENARR, PS_number(&sobj) , inserted);
+ PS_reset( &sobj );
+
+ srandom(1);
+ printf("Test bulk insert:\n");
+ aptr = (EXMPL**)malloc( sizeof(EXMPL*) * LENARR );
+ if ( ! aptr ) {
+ fprintf(stderr,"No memory\n");
+ return 1;
+ }
+ for(i=0;i<LENARR;i++) {
+ aptr[i] = (EXMPL*)malloc( sizeof(EXMPL) );
+ if ( ! aptr[i] ) {
+ fprintf(stderr,"No memory\n");
+ return 1;
+ }
+ aptr[i]->value = (char*)malloc( 64 );
+ if ( ! aptr[i]->value ) {
+ fprintf(stderr,"No memory\n");
+ return 1;
+ }
+ aptr[i]->id = random() % LENARR;
+ sprintf( aptr[i]->value, "Value: %d, startnum: %d", aptr[i]->id, i );
+ }
+
+ PS_bulkinsert( &sobj, (void**)aptr, LENARR );
+
+ if ( PS_init_iterator( &sobj, 7 ) ) {
+ printf("ERROR\n");
+ } else {
+ i=8;
+ while( (ptr=(EXMPL*)PS_getnext( &sobj )) != NULL ) {
+ printf("%d: '%s'\n", i, ptr->value);
+ i++;
+ }
+ printf("Stat: total %d; limit %d;\n", LENARR, PS_number(&sobj));
+ }
+ PS_clear( &sobj );
+
+
+ srandom(1);
+ printf("Test bulk plain insert:\n");
+
+ if ( PS_init( &sobj, LIMIT, exstr_cmp, NULL ) ) {
+ fprintf(stderr,"No memory\n");
+ return 1;
+ }
+ ptr = (EXMPL*)malloc( sizeof(EXMPL) * LENARR );
+ if ( ! ptr ) {
+ fprintf(stderr,"No memory\n");
+ return 1;
+ }
+
+ for(i=0;i<LENARR;i++) {
+ ptr[i].value = (char*)malloc( 64 );
+ if ( ! ptr[i].value ) {
+ fprintf(stderr,"No memory\n");
+ return 1;
+ }
+ ptr[i].id = random() % LENARR;
+ sprintf( ptr[i].value, "Value: %d, startnum: %d", ptr[i].id, i );
+ }
+ PS_bulkplain( &sobj, (void*)ptr, sizeof(EXMPL), LENARR );
+ if ( PS_init_iterator( &sobj, 7 ) ) {
+ printf("ERROR\n");
+ } else {
+ i=8;
+ while( (ptr=(EXMPL*)PS_getnext( &sobj )) != NULL ) {
+ printf("%d: '%s'\n", i, ptr->value);
+ i++;
+ }
+ printf("Stat: total %d; limit %d;\n", LENARR, PS_number(&sobj));
+ }
+ PS_clear( &sobj );
+
+ return 0;
+}
+