Add psort library
authorteodor <teodor>
Wed, 22 Sep 2004 16:19:55 +0000 (16:19 +0000)
committerteodor <teodor>
Wed, 22 Sep 2004 16:19:55 +0000 (16:19 +0000)
Makefile
psort.c [new file with mode: 0644]
psort.h [new file with mode: 0644]
psortex.c [new file with mode: 0644]

index cdd4683..c10b9ed 100644 (file)
--- 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 (file)
index 0000000..f61221c
--- /dev/null
+++ b/psort.c
@@ -0,0 +1,362 @@
+/*
+ * 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;
+}
+
diff --git a/psort.h b/psort.h
new file mode 100644 (file)
index 0000000..09399d1
--- /dev/null
+++ b/psort.h
@@ -0,0 +1,93 @@
+/*
+ * 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
diff --git a/psortex.c b/psortex.c
new file mode 100644 (file)
index 0000000..fedd701
--- /dev/null
+++ b/psortex.c
@@ -0,0 +1,186 @@
+/*
+ * 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;
+}
+