1 /* vector.c ..... store a vector of PPTP_CALL information and search it
3 * C. Scott Ananian <cananian@alumni.princeton.edu>
5 * $Id: vector.c,v 1.1.1.1 2002/07/25 06:52:39 honor Exp $
11 #include "pptp_ctrl.h"
14 /* #define VECTOR_DEBUG */
27 struct vector_struct
{
28 struct vector_item
*item
;
37 static struct vector_item
*binary_search(VECTOR
*v
, int key
);
39 VECTOR
*vector_create() {
40 const int INITIAL_SIZE
= 4;
42 VECTOR
*v
= malloc(sizeof(*v
));
43 if (v
==NULL
) return v
;
46 v
->alloc
= INITIAL_SIZE
;
47 v
->item
= malloc(sizeof(*(v
->item
))*(v
->alloc
));
53 if (v
->item
== NULL
) { free(v
); return NULL
; }
57 void vector_destroy(VECTOR
*v
) {
65 int vector_size(VECTOR
*v
) {
70 /* nice thing about file descriptors is that we are assured by POSIX
71 * that they are monotonically increasing.
73 int vector_insert(VECTOR
*v
, int key
, PPTP_CALL
* call
) {
75 assert(v
!=NULL
&& call
!= NULL
);
76 assert(!vector_contains(v
, key
));
78 assert(v
->key_max
< key
);
81 if (!(v
->size
< v
->alloc
)) {
82 void *tmp
= realloc(v
->item
, sizeof(*(v
->item
)) * 2 * v
->alloc
);
86 } else return FALSE
; /* failed to alloc memory. */
88 assert(v
->size
< v
->alloc
);
90 /* for safety, we make this work in the general case;
91 * but this is optimized for adding call to the end of the vector.
93 for(i
=v
->size
-1; i
>=0; i
--)
94 if (v
->item
[i
].key
< key
)
96 /* insert after item i */
97 memmove(&v
->item
[i
+2], &v
->item
[i
+1], (v
->size
-i
-1)*sizeof(*(v
->item
)));
98 v
->item
[i
+1].key
= key
;
99 v
->item
[i
+1].call
= call
;
103 if (v
->key_max
< key
) /* ie, always. */
110 int vector_remove(VECTOR
*v
, int key
) {
111 struct vector_item
*tmp
;
114 if ((tmp
=binary_search(v
,key
)) == NULL
) return FALSE
;
115 assert(tmp
>=v
->item
&& tmp
< v
->item
+v
->size
);
116 memmove(tmp
, tmp
+1, (v
->size
-(v
->item
-tmp
)-1)*sizeof(*(v
->item
)));
120 int vector_search(VECTOR
*v
, int key
, PPTP_CALL
**call
) {
121 struct vector_item
*tmp
= binary_search(v
, key
);
122 if (tmp
==NULL
) return FALSE
;
126 int vector_contains(VECTOR
*v
, int key
) {
128 return (binary_search(v
, key
)!=NULL
);
131 static struct vector_item
*binary_search(VECTOR
*v
, int key
) {
134 l
= 0; r
= v
->size
- 1;
138 if (key
< v
->item
[x
].key
) r
= x
- 1; else l
= x
+ 1;
139 if (key
== v
->item
[x
].key
) return &(v
->item
[x
]);
144 /* Hmm. Let's be fancy and use a binary search for the first
145 * unused key, taking advantage of the list is stored sorted; ie
146 * we can look at pointers and keys at two different locations,
147 * and if (ptr1 - ptr2) = (key1 - key2) then all the slots
148 * between ptr1 and ptr2 are filled. Note that ptr1-ptr2 should
149 * never be greater than key1-key2 (no duplicate keys!)... we
152 int vector_scan(VECTOR
*v
, int lo
, int hi
, int *key
) {
154 assert(v
!=NULL
); assert(key
!=NULL
);
156 if ((v
->size
<1) || (lo
< v
->item
[0].key
)) { *key
= lo
; return TRUE
; }
158 /* our array bounds */
159 l
= 0; r
= v
->size
- 1;
162 /* check for a free spot right after l */
163 if (v
->item
[l
].key
+ 1 < v
->item
[l
+1].key
) { /* found it! */
164 *key
= v
->item
[l
].key
+ 1;
167 /* no dice. Let's see if the free spot is before or after the midpoint */
169 /* Okay, we have right (r), left (l) and the probe (x). */
170 assert(x
-l
<= v
->item
[x
].key
-v
->item
[l
].key
);
171 assert(r
-x
<= v
->item
[r
].key
-v
->item
[x
].key
);
172 if (x
-l
< v
->item
[x
].key
- v
->item
[l
].key
) /* room between l and x */
174 else /* no room between l and x */
175 if (r
-x
< v
->item
[r
].key
- v
->item
[x
].key
) /* room between x and r */
177 else /* no room between x and r, either */
178 break; /* game over, man. */
180 /* no room found in already allocated space. Check to see if
181 * there's free space above allocated entries. */
182 if (v
->item
[v
->size
-1].key
< hi
) {
183 *key
= v
->item
[v
->size
-1].key
+1;
190 PPTP_CALL
* vector_get_Nth(VECTOR
*v
, int n
) {
192 assert(0 <= n
&& n
< vector_size(v
));
193 return v
->item
[n
].call
;