From: teodor Date: Wed, 22 Sep 2004 16:19:55 +0000 (+0000) Subject: Add psort library X-Git-Url: http://sigaev.ru/git/gitweb.cgi?a=commitdiff_plain;h=293d7a6b2b40d102f9e1155ed7a9bef76ee137b1;p=tedtools.git Add psort library --- diff --git a/Makefile b/Makefile index cdd4683..c10b9ed 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,16 @@ 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 diff --git a/psort.c b/psort.c new file mode 100644 index 0000000..f61221c --- /dev/null +++ b/psort.c @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2004 Teodor Sigaev + * 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 +#include +#include +#include + +#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; icurlen; 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; icurlen; 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; +} + diff --git a/psort.h b/psort.h new file mode 100644 index 0000000..09399d1 --- /dev/null +++ b/psort.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2004 Teodor Sigaev + * 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 diff --git a/psortex.c b/psortex.c new file mode 100644 index 0000000..fedd701 --- /dev/null +++ b/psortex.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2004 Teodor Sigaev + * 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 +#include + +#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;ivalue=(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;ivalue = (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;ivalue); + i++; + } + printf("Stat: total %d; limit %d;\n", LENARR, PS_number(&sobj)); + } + PS_clear( &sobj ); + + return 0; +} +