--- /dev/null
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "hashvector.h"
+
+typedef struct _ipslot {
+ int family;
+ unsigned char data[32];
+ unsigned int bits;
+} ipslot;
+
+static int voidp_hashcode(void *key) {
+ unsigned char *p = (unsigned char *) key;
+ int value = 5381;
+ int i = 0;
+ for ( ; i < sizeof( ipslot ); i++ ) {
+ value += ( value << 5 ) + *(p++);
+ }
+ return value;
+}
+
+static void* voidp_itemkey(void *item) {
+ return item;
+}
+
+static int voidp_haskey(void *item,void *key) {
+ return memcmp( item, key, sizeof( ipslot ) ) == 0;
+}
+
+static struct {
+ hashvector hv;
+ int fill;
+} table = {
+ .hv = {
+ .table = { 12000, 0 },
+ .fill = 0,
+ .holes = 0,
+ .keyhashcode = voidp_hashcode,
+ .itemkey = voidp_itemkey,
+ .haskey = voidp_haskey
+ },
+ .fill = 0
+};
+
+#define BUFSZ 10000
+static struct {
+ char data[ BUFSZ ];
+ int cur;
+ int end;
+} stream;
+
+static int readline(int fd,char **outp) {
+ for ( ;; ) {
+ char *curp = stream.data + stream.cur;
+ char *endp = stream.data + stream.end;
+ char *top = curp;
+ while ( curp < endp ) {
+ if ( *(curp++) == '\n' ) {
+ stream.cur = curp - stream.data;
+ (*outp) = top;
+ return curp - top;
+ }
+ }
+ if ( top != stream.data ) {
+ curp = stream.data;
+ while ( top < endp ) {
+ *(curp++) = *(top++);
+ }
+ endp = curp;
+ stream.end = endp - stream.data;
+ }
+ stream.cur = 0;
+ ssize_t n = read( fd, endp, BUFSZ - stream.end );
+ if ( n <= 0 ) {
+ if ( stream.end == 0 ) {
+ return -1; // No more data
+ }
+ (*outp) = stream.data;
+ return stream.end;
+ }
+ stream.end += n;
+ }
+ //unreachable
+}
+
+// Scan to NUL, CR or c. Return pointer not including character.
+static char *scanto(char *p, char c) {
+ while ( *p && *p != '\n' && *p != c ) {
+ p++;
+ }
+ return p;
+}
+
+static int parse_addr(char *line,ipslot *addr) {
+ char *end = scanto( line, '\n' );
+ char *slash = scanto( line, '/' );
+ *slash = 0;
+ *end = 0;
+ if ( inet_pton( AF_INET6, line, addr->data ) == 1 ) {
+ addr->bits = 128;
+ addr->family = AF_INET6;
+ } else if ( inet_pton( AF_INET, line, addr->data ) == 1 ) {
+ addr->bits = 32;
+ addr->family = AF_INET;
+ } else {
+ return 1;
+ }
+ if ( slash != end && sscanf( slash+1, "%u", &addr->bits ) != 1 ) {
+ return 2;
+ }
+ return 0;
+}
+
+
+static void add_entry(ipslot *tmp) {
+ ipslot *p = (ipslot *) malloc( sizeof( ipslot ) );
+ memmove( p, tmp, sizeof( ipslot ) );
+ hashvector_add( &table.hv, p );
+ table.fill++;
+#if 0
+ pvector *pv = &table.hv.table;
+ if ( pv->size == table.fill ) {
+ (void) pvector_resize( pv, table.fill + 256, 0, 0 );
+ }
+ pvector_set( pv, table.fill++, p );
+#endif
+}
+
+static void load_file(const char *filename) {
+ int fd = open( filename, O_RDONLY );
+ if ( fd < 0 ) {
+ perror( filename );
+ exit( errno );
+ }
+ char *line;
+ int n;
+ while ( ( n = readline( fd, &line ) ) >= 0 ) {
+ ipslot addr;
+ if ( parse_addr( line, &addr ) ) {
+ fprintf( stderr, "Bad address: %s\n", line );
+ continue;
+ }
+ add_entry( &addr );
+ }
+}
+
+static int int_reclaim(pvector *pv,unsigned long index,void *item,void *data) {
+ return 0;
+}
+
+static int dumpitem(unsigned long index,void *item) {
+ fprintf( stdout, "[%ld] %p\n", index, item );
+ return 0;
+}
+
+static int dump_ipslot(unsigned long index,void *item) {
+ static char buffer[100];
+ ipslot *ip = (ipslot*) item;
+ const char *p = inet_ntop( ip->family, ip->data, buffer, 100 );
+ fprintf( stdout, "[%ld] %s/%d\n", index, p, ip->bits );
+ return 0;
+}
+
+static int compare_ipslot(void *ax,void *bx) {
+ ipslot *a = (ipslot *) ax;
+ ipslot *b = (ipslot *) bx;
+ int x = b->family - a->family;
+ if ( x ) {
+ return ( x > 0 )? 1 : -1;
+ }
+ x = a->bits < b->bits? a->bits : b->bits;
+ unsigned char *ap = a->data;
+ unsigned char *bp = b->data;
+ int d;
+ for ( ; x >= 8; x -= 8 ) {
+ d = *(bp++) - *(ap++);
+ if ( d ) {
+ return ( d > 0 )? 1 : -1;
+ }
+ }
+ if ( x ) {
+ x = 7 - x;
+ d = ( (*bp) >> x ) - ( (*ap) >> x );
+ if ( d ) {
+ return ( d > 0 )? 1 : -1;
+ }
+ }
+ x = b->bits - a->bits;
+ if ( x ) {
+ return ( x > 0 )? 1 : -1;
+ }
+ return 0;
+}
+
+int main(int argc,char **argv) {
+ pvector test = { 0 };
+ pvector_resize( &test, 100, 0, 0 );
+ pvector_set( &test, 5, (void*) 500 );
+ pvector_set( &test, 55, (void*) 600 );
+ //pvector_set( &test, 550, (void*) 800 );
+ pvector_resize( &test, 300, 0, 0 );
+ pvector_set( &test, 55, (void*) 650 );
+ pvector_resize( &test, 30000, 0, 0 );
+ pvector_set( &test, 22255, (void*) 26 );
+ pvector_dump( &test, dumpitem );
+ pvector_resize( &test, 100, int_reclaim, 0 );
+ pvector_set( &test, 5, (void*) 2 );
+ pvector_dump( &test, dumpitem );
+ pvector_resize( &test, 0, int_reclaim, 0 ); // clear out the pvector
+
+ int i;
+ for ( i = 1; i < argc; i++ ) {
+ load_file( argv[ i ] );
+ }
+ pvector_dump( &table.hv.table, dump_ipslot );
+ fprintf( stdout, "--------------\n" );
+ if ( hashvector_pack( &table.hv, &test ) < 0 ) {
+ fprintf( stdout, "test is not empty\n" );
+ }
+ pvector_dump( &test, dump_ipslot );
+ fprintf( stdout, "--------------\n" );
+ pvector_qsort( &test, compare_ipslot );
+ pvector_dump( &test, dump_ipslot );
+ return 0;
+}
--- /dev/null
+#include "hashvector.h"
+
+// Find the slot for the keyed element, and return pointer to it.
+static void **hashvector_find_slot(hashvector *hv,void *key) {
+ unsigned int index = hv->keyhashcode( key ) % hv->table.size;
+ unsigned int i = index;
+ void **hole = 0;
+ for ( ;; ) {
+ void **p = pvector_entry(&hv->table, i);
+ if ( p == 0 ) {
+ return 0;
+ }
+ if ( *p ) {
+ if ( (*p) != HV_HOLE ) {
+ if ( hv->haskey( *p, key ) ) {
+ return p;
+ }
+ } else {
+ if ( hole == 0 ) {
+ hole = p;
+ }
+ if ( ++i == hv->table.size ) {
+ i = 0;
+ }
+ if ( i != index ) {
+ continue;
+ }
+ }
+ }
+ return ( hole )? hole : p;
+ }
+}
+
+// Find the keyed element, and assign the x pointer, or assign 0.
+// Returns 1 if element is found and 0 otherwise.
+int hashvector_find(hashvector *hv,void *key,void **x) {
+ void **p = hashvector_find_slot( hv, key );
+ if ( p && *p && *p != HV_HOLE ) {
+ *x = *p;
+ return 1;
+ }
+ return 0;
+}
+
+static int capture_item(pvector *pv,unsigned long ix,void *item,void *data) {
+ if ( item != HV_HOLE ) {
+ hashvector_add( (hashvector *) data, item );
+ }
+ return 0;
+}
+
+static void hashvector_resize(hashvector *hv,unsigned int new_size) {
+ hashvector tmp = *hv;
+ hv->table.size = new_size;
+ hv->table.entries = 0;
+ hv->fill = 0;
+ hv->holes = 0;
+ pvector_resize( &tmp.table, 0, capture_item, hv );
+}
+
+// Add the given element.
+void hashvector_add(hashvector *hv,void *item) {
+ void **p = hashvector_find_slot( hv, hv->itemkey( item ) );
+ if ( p ) {
+ if ( *p ) {
+ if ( *p != HV_HOLE ) {
+ return;
+ }
+ hv->holes--;
+ }
+ *p = item;
+ hv->fill++;
+ if ( hv->fill + hv->holes > hv->table.size / 2 ) {
+ hashvector_resize( hv, hv->table.size * 2 );
+ }
+ }
+}
+
+// Return the next element starting at i, or 0 if there are no more.
+// Also increment the index to be of the element + 1, or -1 if there
+// are no more elements.
+//unsigned char *htnext(htable *table,int *i);
+
+// Delete the given element.
+void hashvector_delete(hashvector *hv,void *item) {
+ void **p = hashvector_find_slot( hv, hv->itemkey( item ) );
+ if ( p && *p && *p != HV_HOLE ) {
+ *p = HV_HOLE;
+ hv->holes++;
+ if ( hv->table.size > 256 ) {
+ if ( hv->fill < hv->table.size / 2 ) {
+ hashvector_resize( hv, hv->table.size / 2 );
+ }
+ }
+ }
+}
+
+// Copy items into a pvector. Returns 0 on success and -1 on failure.
+int hashvector_pack(hashvector *hv,pvector *pv) {
+ if ( pvector_resize( pv, hv->fill, 0, 0 ) ) {
+ return -1;
+ }
+ unsigned long from = 0;
+ unsigned long to = 0;
+ while ( to < hv->fill ) {
+ void **slot = pvector_next_used( &hv->table, &from, 0, 0 );
+ if ( slot ) {
+ if ( *slot != HV_HOLE ) {
+ pvector_set( pv, to++, *slot );
+ }
+ from++;
+ } else {
+ break;
+ }
+ }
+ return 0;
+}
--- /dev/null
+#ifndef hashvector_H
+#define hashvector_H
+
+#ifdef USE_PTHREAD
+#define __USE_GNU 1
+#include <pthread.h>
+#endif
+
+#include "pvector.h"
+
+typedef struct _hashvector {
+ pvector table;
+ unsigned int fill; // number of added elements
+ unsigned int holes; // number of deleted
+ int (*keyhashcode)(void *key);
+ void *(*itemkey)(void *item);
+ int (*haskey)(void *item,void *key);
+#ifdef USE_PTHREAD
+ pthread_mutex_t lock;
+#endif
+} hashvector;
+
+#define HV_HOLE ((void*) 1)
+
+// Find the keyed element, and assign the x pointer, or assign 0.
+// Returns 1 if element is found and 0 otherwise.
+int hashvector_find(hashvector *hv,void *key,void **x);
+
+// Add the given element.
+void hashvector_add(hashvector *hv,void *p);
+
+// Return the next element starting at i, or 0 if there are no more.
+// Also increment the index to be of the element + 1, or -1 if there
+// are no more elements.
+//unsigned char *htnext(htable *table,int *i);
+
+// Delete the given element.
+void hashvector_delete(hashvector *hv,void *p);
+
+// Copy content items into pvector, which must be empty.
+int hashvector_pack(hashvector *hv,pvector *pv);
+
+#endif