2 * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the author nor the names of any co-contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
18 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 * this defines only for faster code
41 #define insert_full(val) do { \
44 (*(sobj->free))( tmp->value ); \
45 sobj->last = sobj->last->prev; /* current last */ \
47 curitem = sobj->last; \
48 curitem->next = tmp->prev = tmp->next = NULL; \
51 if ( (*(sobj->cmpr))( curitem->value, (val) ) <= 0 ) { \
52 tmp->next = curitem->next; \
53 tmp->prev = curitem; \
55 if ( curitem->next ) /* not last */ \
56 curitem->next->prev = tmp; \
59 curitem->next = tmp; \
62 curitem = curitem->prev; \
63 } while ( curitem ); \
64 /* insert to first position */ \
66 sobj->first->prev = tmp; \
67 tmp->next = sobj->first; \
72 #define insert_notfull( val ) do { \
73 tmp = &(sobj->buf[sobj->curlen]); \
76 curitem = sobj->first; \
78 if ( (*(sobj->cmpr))( curitem->value, tmp->value ) > 0 ) { \
79 tmp->next = curitem; \
80 curitem->prev = tmp; \
81 tmp->prev = previtem; \
83 previtem->next = tmp; \
85 sobj->first->prev = tmp; \
91 curitem = curitem->next; \
93 if ( ! tmp->next ) { /*not inserted*/ \
94 sobj->last->next = tmp; \
95 tmp->prev = sobj->last; \
104 * If input options are invalid, return -1
105 * if no memory return 1
106 * If success return 0
109 PS_init( SORT* sobj, int buflen, compare_sort func, ffree ffunc ) {
110 if ( ! sobj ) return -1;
111 if ( ! func ) return -1;
112 if ( buflen <= 0 ) return -1;
114 sobj->buf = (SORTITEM*)t0malloc( sizeof(SORTITEM)*buflen );
116 sobj->buflen = buflen;
121 sobj->first = sobj->last = sobj->buf;
122 sobj->curitem = NULL;
132 PS_clear( SORT* sobj ) {
135 for(i=0; i<sobj->curlen; i++ )
136 (*(sobj->free))( sobj->buf[i].value );
140 memset( (void*)sobj, 0, sizeof(SORT) );
144 * Reset sort object..
147 PS_reset( SORT* sobj ) {
151 for(i=0; i<sobj->curlen; i++ )
152 (*(sobj->free))( sobj->buf[i].value );
154 memset( (void*)sobj->buf, 0, sizeof(SORTITEM)*sobj->buflen );
156 sobj->first = sobj->last = sobj->buf;
157 sobj->curitem = NULL;
164 PS_insert( SORT* sobj, void* nobj ) {
165 SORTITEM *curitem, *previtem, *tmp;
167 /* first insertion */
168 if ( ! sobj->curlen ) {
169 sobj->first->value = nobj;
174 if ( sobj->curlen == sobj->buflen ) {
175 if ( (*(sobj->cmpr))( sobj->last->value, nobj ) > 0 ) {
176 if ( sobj->buflen == 1 ) {
178 (*(sobj->free))( sobj->last->value );
179 sobj->last->value = nobj;
185 insert_notfull( nobj );
193 static compare_sort compareobject;
194 static int highlevelcompare( const void *a, const void *b ) {
195 return (*compareobject)( *(void**)a, *(void**)b );
199 * Insert array, if defined free function,
200 * unused item will be freeed
203 #define RECOMMEND_M(N) ( ((N)<8000) ? ( 23.0+1.5*pow((N),0.6) ) : pow(( 8.05 * log((N)) - 53.53 ),2.0) )
205 PS_bulkinsert( SORT* sobj, void** nobjs, int len ) {
206 register SORTITEM *curitem, *tmp;
207 register void** ptr = nobjs;
209 if ( !sobj->curlen ) {
211 if ( len > sobj->buflen ) {
212 if ( sobj->buflen < RECOMMEND_M( len ) )
213 initlen = sobj->buflen;
215 curitem = sobj->first;
216 compareobject = sobj->cmpr;
218 qsort( nobjs, initlen, sizeof(void*), highlevelcompare );
220 while( ptr - nobjs < initlen && sobj->curlen != sobj->buflen ) {
221 curitem->value = *ptr;
222 if ( sobj->curlen ) {
223 curitem->prev = curitem - 1;
224 curitem->prev->next = curitem;
230 sobj->last = curitem-1;
232 if ( sobj->free && initlen != sobj->buflen ) {
233 while( ptr - nobjs < len ) {
234 (*(sobj->free))( *ptr );
240 while( ptr - nobjs < len && sobj->curlen != sobj->buflen ) {
241 PS_insert( sobj, *ptr ); /* buflen is very small, so we can use function call */
247 while( ptr - nobjs < len ) {
248 if ( (*(sobj->cmpr))( sobj->last->value, *ptr ) > 0 ) {
249 if ( sobj->buflen == 1 ) {
250 (*(sobj->free))( sobj->last->value );
251 sobj->last->value = *ptr;
255 (*(sobj->free))( *ptr );
259 while( ptr - nobjs < len ) {
260 if ( (*(sobj->cmpr))( sobj->last->value, *ptr ) > 0 ) {
261 if ( sobj->buflen == 1 )
262 sobj->last->value = *ptr;
272 * insert a-la qsort, require sobj->free = NULL
275 PS_bulkplain( SORT* sobj, void* nobjs, int size, int len ) {
276 register SORTITEM *curitem, *tmp;
277 register char* ptr = (char*)nobjs;
282 if ( !sobj->curlen ) {
284 if ( len > sobj->buflen ) {
285 if ( sobj->buflen < RECOMMEND_M( len ) )
286 initlen = sobj->buflen;
288 curitem = sobj->first;
290 qsort( nobjs, initlen, size, sobj->cmpr );
293 while( ptr - (char*)nobjs < initlen && sobj->curlen != sobj->buflen ) {
294 curitem->value = (void*)ptr;
295 if ( sobj->curlen ) {
296 curitem->prev = curitem - 1;
297 curitem->prev->next = curitem;
303 sobj->last = curitem-1;
306 while( ( ptr - (char*)nobjs )/size < len && sobj->curlen != sobj->buflen ) {
307 PS_insert( sobj, (void*)ptr ); /* buflen is very small, so we can use function call */
313 while( ptr - (char*)nobjs < len ) {
314 if ( (*(sobj->cmpr))( sobj->last->value, (void*)ptr ) > 0 ) {
315 if ( sobj->buflen == 1 )
316 sobj->last->value = (void*)ptr;
318 insert_full( (void*)ptr );
327 * init_iterator, return 0 if success
330 PS_init_iterator( SORT* sobj, int start ) {
331 if ( sobj->curlen <= 0 || start<0 || start >= sobj->curlen )
333 sobj->curitem = sobj->first;
335 sobj->curitem = sobj->curitem->next;
342 * return next sorted value or NULL
345 PS_getnext( SORT* sobj ) {
348 value = sobj->curitem->value;
352 sobj->curitem = ( sobj->curitem->next == NULL || sobj->curitem->next == sobj->first ) ? NULL : sobj->curitem->next;
358 PS_number( SORT* sobj ) {