1 /*
2 * Copyright (c) 2015 NLNet Labs. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
19 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
21 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
23 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 */
26
27 #include "config.h"
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <errno.h>
31 #include <string.h>
32 #include "status.h"
33 #include "datastructure.h"
34
35 struct collection_class_struct {
36 FILE* store;
37 void* cargo;
38 int (*member_destroy)(void* cargo, void* member);
39 int (*member_dispose)(void* cargo, void* member, FILE*);
40 int (*member_restore)(void* cargo, void* member, FILE*);
41 };
42
43 struct collection_instance_struct {
44 struct collection_class_struct* method;
45 char* array; /** array with members */
46 size_t size; /** member size */
47 int iterator;
48 int count; /** number of members in array */
49 long location;
50 };
51
52 static int
swapin(collection_t collection)53 swapin(collection_t collection)
54 {
55 int i;
56 if(collection->count > 0) {
57 if(fseek(collection->method->store, collection->location, SEEK_SET))
58 return 1;
59 for(i=0; i<collection->count; i++) {
60 if(collection->method->member_restore(collection->method->cargo,
61 collection->array + collection->size * i, collection->method->store))
62 return 1;
63 }
64 }
65 return 0;
66 }
67
68 static int
swapout(collection_t collection)69 swapout(collection_t collection)
70 {
71 int i;
72 if(collection->count > 0) {
73 if(fseek(collection->method->store, 0, SEEK_END))
74 return 1;
75 collection->location = ftell(collection->method->store);
76 for(i=0; i<collection->count; i++) {
77 if(collection->method->member_dispose(collection->method->cargo,
78 collection->array + collection->size * i, collection->method->store))
79 return 1;
80 }
81 }
82 return 0;
83 }
84
85 void
collection_class_allocated(collection_class * klass,void * cargo,int (* member_destroy)(void * cargo,void * member))86 collection_class_allocated(collection_class* klass, void *cargo,
87 int (*member_destroy)(void* cargo, void* member))
88 {
89 CHECKALLOC(*klass = malloc(sizeof(struct collection_class_struct)));
90 (*klass)->cargo = cargo;
91 (*klass)->member_destroy = member_destroy;
92 (*klass)->member_dispose = NULL;
93 (*klass)->member_restore = NULL;
94 (*klass)->store = NULL;
95 }
96
97 void
collection_class_backed(collection_class * klass,char * fname,void * cargo,int (* member_destroy)(void * cargo,void * member),int (* member_dispose)(void * cargo,void * member,FILE *),int (* member_restore)(void * cargo,void * member,FILE *))98 collection_class_backed(collection_class* klass, char* fname, void *cargo,
99 int (*member_destroy)(void* cargo, void* member),
100 int (*member_dispose)(void* cargo, void* member, FILE*),
101 int (*member_restore)(void* cargo, void* member, FILE*))
102 {
103 CHECKALLOC(*klass = malloc(sizeof(struct collection_class_struct)));
104 (*klass)->cargo = cargo;
105 (*klass)->member_destroy = member_destroy;
106 (*klass)->member_dispose = member_dispose;
107 (*klass)->member_restore = member_restore;
108 (*klass)->store = fopen(fname, "w+");
109 }
110
111 void
collection_class_destroy(collection_class * klass)112 collection_class_destroy(collection_class* klass)
113 {
114 if (klass == NULL)
115 return;
116 free(*klass);
117 *klass = NULL;
118 }
119
120 void
collection_create_array(collection_t * collection,size_t membsize,collection_class klass)121 collection_create_array(collection_t* collection, size_t membsize,
122 collection_class klass)
123 {
124 CHECKALLOC(*collection = malloc(sizeof(struct collection_instance_struct)));
125 (*collection)->size = membsize;
126 (*collection)->count = 0;
127 (*collection)->array = NULL;
128 (*collection)->iterator = -1;
129 (*collection)->method = klass;
130 }
131
132 void
collection_destroy(collection_t * collection)133 collection_destroy(collection_t* collection)
134 {
135 int i;
136 if(collection == NULL)
137 return;
138 for (i=0; i < (*collection)->count; i++) {
139 (*collection)->method->member_destroy((*collection)->method->cargo,
140 &(*collection)->array[(*collection)->size * i]);
141 }
142 if((*collection)->array)
143 free((*collection)->array);
144 free(*collection);
145 *collection = NULL;
146 }
147
148 void
collection_add(collection_t collection,void * data)149 collection_add(collection_t collection, void *data)
150 {
151 void* ptr;
152 if(collection->method->store)
153 swapin(collection);
154 CHECKALLOC(ptr = realloc(collection->array, (collection->count+1)*collection->size));
155 collection->array = ptr;
156 memcpy(&collection->array[collection->size * collection->count], data, collection->size);
157 collection->count += 1;
158 if(collection->method->store)
159 swapout(collection);
160 }
161
162 void
collection_del_index(collection_t collection,int index)163 collection_del_index(collection_t collection, int index)
164 {
165 void* ptr;
166 if (index<0 || index >= collection->count)
167 return;
168 if(collection->method->store)
169 swapin(collection);
170 collection->method->member_destroy(collection->method->cargo, &collection->array[collection->size * index]);
171 collection->count -= 1;
172 memmove(&collection->array[collection->size * index], &collection->array[collection->size * (index + 1)], (collection->count - index) * collection->size);
173 if (collection->count > 0) {
174 CHECKALLOC(ptr = realloc(collection->array, collection->count * collection->size));
175 collection->array = ptr;
176 } else {
177 free(collection->array);
178 collection->array = NULL;
179 }
180 if(collection->method->store)
181 swapout(collection);
182 }
183
184 void
collection_del_cursor(collection_t collection)185 collection_del_cursor(collection_t collection)
186 {
187 collection_del_index(collection, collection->iterator);
188 }
189
190 void*
collection_iterator(collection_t collection)191 collection_iterator(collection_t collection)
192 {
193 if(collection->iterator < 0) {
194 if(collection->method->store)
195 swapin(collection);
196 collection->iterator = collection->count;
197 }
198 collection->iterator -= 1;
199 if(collection->iterator >= 0) {
200 return &collection->array[collection->iterator * collection->size];
201 } else {
202 if(collection->method->store)
203 swapout(collection);
204 return NULL;
205 }
206 }
207