1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
|
/* vector.c ..... store a vector of PPTP_CALL information and search it
* efficiently.
* C. Scott Ananian <cananian@alumni.princeton.edu>
*
* $Id: vector.c,v 1.4 2011/12/19 07:15:03 quozl Exp $
*/
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "pptp_ctrl.h"
#include "vector.h"
/* #define VECTOR_DEBUG */
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
struct vector_item {
int key;
PPTP_CALL *call;
};
struct vector_struct {
struct vector_item *item;
int size;
int alloc;
#ifdef VECTOR_DEBUG
int key_max;
#endif
};
static struct vector_item *binary_search(VECTOR *v, int key);
/*** vector_create ************************************************************/
VECTOR *vector_create(void)
{
const int INITIAL_SIZE = 4;
VECTOR *v = malloc(sizeof(*v));
if (v == NULL) return v;
v->size = 0;
v->alloc = INITIAL_SIZE;
v->item = malloc(sizeof(*(v->item)) * (v->alloc));
#ifdef VECTOR_DEBUG
v->key_max = -1;
#endif
if (v->item == NULL) { free(v); return NULL; }
else return v;
}
/*** vector_destroy ***********************************************************/
void vector_destroy(VECTOR *v)
{
free(v->item);
#ifdef VECTOR_DEBUG
v->item = NULL;
#endif
free(v);
}
/*** vector_size **************************************************************/
int vector_size(VECTOR *v)
{
assert(v != NULL);
return v->size;
}
/*** vector_insert*************************************************************
* nice thing about file descriptors is that we are assured by POSIX
* that they are monotonically increasing.
*/
int vector_insert(VECTOR *v, int key, PPTP_CALL * call)
{
int i;
assert(v != NULL && call != NULL);
assert(!vector_contains(v, key));
#ifdef VECTOR_DEBUG
assert(v->key_max < key);
#endif
if (!(v->size < v->alloc)) {
void *tmp = realloc(v->item, sizeof(*(v->item)) * 2 * v->alloc);
if (tmp != NULL) {
v->alloc *= 2;
v->item = tmp;
} else return FALSE; /* failed to alloc memory. */
}
assert(v->size < v->alloc);
/* for safety, we make this work in the general case;
* but this is optimized for adding call to the end of the vector.
*/
for(i = v->size - 1; i >= 0; i--)
if (v->item[i].key < key)
break;
/* insert after item i */
memmove(&v->item[i + 2], &v->item[i + 1],
(v->size - i - 1) * sizeof(*(v->item)));
v->item[i + 1].key = key;
v->item[i + 1].call = call;
v->size++;
#ifdef VECTOR_DEBUG
if (v->key_max < key) /* ie, always. */
v->key_max = key;
#endif
return TRUE;
}
/*** vector_remove ************************************************************/
int vector_remove(VECTOR *v, int key)
{
struct vector_item *tmp;
assert(v != NULL);
if ((tmp =binary_search(v,key)) == NULL) return FALSE;
assert(tmp >= v->item && tmp < v->item + v->size);
memmove(tmp, tmp + 1, (v->size - (tmp - v->item) - 1) * sizeof(*(v->item)));
v->size--;
return TRUE;
}
/*** vector_search ************************************************************/
int vector_search(VECTOR *v, int key, PPTP_CALL **call)
{
struct vector_item *tmp;
assert(v != NULL);
tmp = binary_search(v, key);
if (tmp ==NULL) return FALSE;
*call = tmp->call;
return TRUE;
}
/*** vector_contains **********************************************************/
int vector_contains(VECTOR *v, int key)
{
assert(v != NULL);
return (binary_search(v, key) != NULL);
}
/*** vector_item **************************************************************/
static struct vector_item *binary_search(VECTOR *v, int key)
{
int l,r,x;
l = 0;
r = v->size - 1;
while (r >= l) {
x = (l + r)/2;
if (key < v->item[x].key) r = x - 1; else l = x + 1;
if (key == v->item[x].key) return &(v->item[x]);
}
return NULL;
}
/*** vector_scan ***************************************************************
* Hmm. Let's be fancy and use a binary search for the first
* unused key, taking advantage of the list is stored sorted; ie
* we can look at pointers and keys at two different locations,
* and if (ptr1 - ptr2) = (key1 - key2) then all the slots
* between ptr1 and ptr2 are filled. Note that ptr1-ptr2 should
* never be greater than key1-key2 (no duplicate keys!)... we
* check for this.
*/
int vector_scan(VECTOR *v, int lo, int hi, int *key)
{
int l,r,x;
assert(v != NULL);
assert(key != NULL);
if ((v->size<1) || (lo < v->item[0].key)) { *key = lo; return TRUE; }
/* our array bounds */
l = 0; r = v->size - 1;
while (r > l) {
/* check for a free spot right after l */
if (v->item[l].key + 1 < v->item[l + 1].key) { /* found it! */
*key = v->item[l].key + 1;
return TRUE;
}
/* no dice. Let's see if the free spot is before or after the midpoint */
x = (l + r)/2;
/* Okay, we have right (r), left (l) and the probe (x). */
assert(x - l <= v->item[x].key - v->item[l].key);
assert(r - x <= v->item[r].key - v->item[x].key);
if (x - l < v->item[x].key - v->item[l].key)
/* room between l and x */
r = x;
else /* no room between l and x */
if (r - x < v->item[r].key - v->item[x].key)
/* room between x and r */
l = x;
else /* no room between x and r, either */
break; /* game over, man. */
}
/* no room found in already allocated space. Check to see if
* there's free space above allocated entries. */
if (v->item[v->size - 1].key < hi) {
*key = v->item[v->size - 1].key + 1;
return TRUE;
}
/* outta luck */
return FALSE;
}
/*** vector_get_Nth ***********************************************************/
PPTP_CALL * vector_get_Nth(VECTOR *v, int n)
{
assert(v != NULL);
assert(0 <= n && n < vector_size(v));
return v->item[n].call;
}
|