dbuffer.c
Go to the documentation of this file.00001
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "common.h"
00027 #include <SDL_thread.h>
00028
00029
00030 #define DBUFFER_ELEMENT_SIZE 4000
00031
00032 #ifdef DEBUG
00033 #define DBUFFER_ELEMENTS_FREE_THRESHOLD 0
00034 #define DBUFFER_FREE_THRESHOLD 0
00035 #else
00036 #define DBUFFER_ELEMENTS_FREE_THRESHOLD 1000
00037 #define DBUFFER_FREE_THRESHOLD 1000
00038 #endif
00039
00040 struct dbuffer_element {
00041 struct dbuffer_element *next;
00042 char data[DBUFFER_ELEMENT_SIZE];
00043 size_t space, len;
00044 };
00045
00046 static int free_elements = 0, allocated_elements = 0;
00047 static struct dbuffer_element *free_element_list = NULL;
00048
00049 static int free_dbuffers = 0, allocated_dbuffers = 0;
00050 static struct dbuffer *free_dbuffer_list = NULL;
00051
00052 static SDL_mutex *dbuf_lock;
00053
00057 static struct dbuffer_element * allocate_element (void)
00058 {
00059 struct dbuffer_element *e;
00060
00061 SDL_mutexP(dbuf_lock);
00062
00063 if (free_elements == 0) {
00064 struct dbuffer_element *newBuf = Mem_PoolAlloc(sizeof(struct dbuffer_element), com_genericPool, 0);
00065 newBuf->next = free_element_list;
00066 free_element_list = newBuf;
00067 free_elements++;
00068 allocated_elements++;
00069 }
00070 assert(free_element_list);
00071
00072 e = free_element_list;
00073 free_element_list = free_element_list->next;
00074 assert(free_elements > 0);
00075 free_elements--;
00076 e->space = DBUFFER_ELEMENT_SIZE;
00077 e->len = 0;
00078 e->next = NULL;
00079
00080 SDL_mutexV(dbuf_lock);
00081
00082 return e;
00083 }
00084
00088 static void free_element (struct dbuffer_element *e)
00089 {
00090 SDL_mutexP(dbuf_lock);
00091
00092 e->next = free_element_list;
00093 free_element_list = e;
00094 free_elements++;
00095 while (free_elements > DBUFFER_ELEMENTS_FREE_THRESHOLD) {
00096 e = free_element_list;
00097 free_element_list = e->next;
00098 Mem_Free(e);
00099 free_elements--;
00100 allocated_elements--;
00101 }
00102
00103 SDL_mutexV(dbuf_lock);
00104 }
00105
00111 struct dbuffer * new_dbuffer (void)
00112 {
00113 struct dbuffer *buf;
00114
00115 SDL_mutexP(dbuf_lock);
00116
00117 if (free_dbuffers == 0) {
00118 struct dbuffer *newBuf = Mem_PoolAlloc(sizeof(struct dbuffer), com_genericPool, 0);
00119 newBuf->next_free = free_dbuffer_list;
00120 free_dbuffer_list = newBuf;
00121 free_dbuffers++;
00122 allocated_dbuffers++;
00123 }
00124 assert(free_dbuffer_list);
00125
00126 buf = free_dbuffer_list;
00127 free_dbuffer_list = free_dbuffer_list->next_free;
00128 assert(free_dbuffers > 0);
00129 free_dbuffers--;
00130
00131 SDL_mutexV(dbuf_lock);
00132
00133 buf->len = 0;
00134 buf->space = DBUFFER_ELEMENT_SIZE;
00135 buf->head = buf->tail = allocate_element();
00136 buf->start = buf->end = &buf->head->data[0];
00137
00138 return buf;
00139 }
00140
00146 void free_dbuffer (struct dbuffer *buf)
00147 {
00148 struct dbuffer_element *e;
00149 if (!buf)
00150 return;
00151 while ((e = buf->head)) {
00152 buf->head = e->next;
00153 free_element(e);
00154 }
00155
00156 SDL_mutexP(dbuf_lock);
00157
00158 buf->next_free = free_dbuffer_list;
00159 free_dbuffer_list = buf;
00160 free_dbuffers++;
00161
00162
00163 while (free_dbuffers > DBUFFER_FREE_THRESHOLD) {
00164 buf = free_dbuffer_list;
00165 free_dbuffer_list = buf->next_free;
00166 Mem_Free(buf);
00167 free_dbuffers--;
00168 allocated_dbuffers--;
00169 }
00170
00171 SDL_mutexV(dbuf_lock);
00172 }
00173
00181 static inline void dbuffer_grow (struct dbuffer *buf, size_t len)
00182 {
00183 struct dbuffer_element *e;
00184 while (buf->space <= len) {
00185 e = allocate_element();
00186 e->next = NULL;
00187 buf->tail->next = e;
00188 buf->tail = e;
00189 buf->space += DBUFFER_ELEMENT_SIZE;
00190 }
00191 }
00192
00201 struct dbuffer *dbuffer_merge (struct dbuffer *old, struct dbuffer *old2)
00202 {
00203
00204 const struct dbuffer_element *e;
00205 struct dbuffer *buf = new_dbuffer();
00206 const char *p;
00207
00208 e = old->head;
00209 p = old->start;
00210 while (e && (e->len > 0)) {
00211 dbuffer_add(buf, p, e->len);
00212 e = e->next;
00213 p = &e->data[0];
00214 }
00215
00216 e = old2->head;
00217 p = old2->start;
00218 while (e && (e->len > 0)) {
00219 dbuffer_add(buf, p, e->len);
00220 e = e->next;
00221 p = &e->data[0];
00222 }
00223
00224 return buf;
00225 }
00226
00236 struct dbuffer *dbuffer_prepend (struct dbuffer *old, const char *data, size_t len)
00237 {
00238
00239 const struct dbuffer_element *e;
00240 struct dbuffer *buf = new_dbuffer();
00241 const char *p;
00242
00243 dbuffer_add(buf, data, len);
00244
00245 e = old->head;
00246 p = old->start;
00247 while (e && (e->len > 0)) {
00248 dbuffer_add(buf, p, e->len);
00249 e = e->next;
00250 p = &e->data[0];
00251 }
00252
00253 return buf;
00254 }
00255
00263 void dbuffer_add (struct dbuffer *buf, const char *data, size_t len)
00264 {
00265 struct dbuffer_element *e;
00266
00267 if (!buf || !data || !len)
00268 return;
00269
00270 e = buf->tail;
00271
00272
00273
00274 if (len >= buf->space)
00275 dbuffer_grow(buf, len);
00276
00277 assert(len < buf->space);
00278 while (len > 0) {
00279 size_t l = (len < e->space) ? len : e->space;
00280 memcpy(buf->end, data, l);
00281 data += l;
00282 len -= l;
00283 e->space -= l;
00284 e->len += l;
00285 buf->end += l;
00286 buf->len += l;
00287 buf->space -=l;
00288 if (e->space == 0) {
00289 e = e->next;
00290 assert(e != NULL);
00291 buf->end = &e->data[0];
00292 }
00293 }
00294 }
00295
00310 size_t dbuffer_get (const struct dbuffer *buf, char *data, size_t len)
00311 {
00312 size_t read = 0;
00313
00314 const struct dbuffer_element *e;
00315
00316 const void *p;
00317
00318 if (!buf || !data || !len)
00319 return 0;
00320
00321 e = buf->head;
00322 p = buf->start;
00323 while (len > 0 && e && e->len > 0) {
00324 const size_t l = (len < e->len) ? len : e->len;
00325 memcpy(data, p, l);
00326 data += l;
00327 len -= l;
00328 e = e->next;
00329 p = &e->data[0];
00330 read += l;
00331 }
00332 return read;
00333 }
00334
00350 size_t dbuffer_get_at (const struct dbuffer *buf, size_t offset, char *data, size_t len)
00351 {
00352 size_t read = 0;
00353
00354 const struct dbuffer_element *e;
00355
00356 const char *p;
00357
00358 if (!buf || !data || !len)
00359 return 0;
00360
00361 e = buf->head;
00362 p = buf->start;
00363
00364 while (offset > 0 && e && offset >= e->len) {
00365 offset -= e->len;
00366 e = e->next;
00367 p = &e->data[0];
00368 }
00369
00370 if (e == NULL || e->len <= 0)
00371 return 0;
00372
00373 while (len > 0 && e && e->len > 0) {
00374 size_t l = e->len - offset;
00375 if (len < l)
00376 l = len;
00377 p += offset;
00378 memcpy(data, p, l);
00379 data += l;
00380 len -= l;
00381 offset = 0;
00382 e = e->next;
00383 p = &e->data[0];
00384 read += l;
00385 }
00386
00387 return read;
00388 }
00389
00397 struct dbuffer *dbuffer_dup (struct dbuffer *old)
00398 {
00399
00400 const struct dbuffer_element *e;
00401 struct dbuffer *buf = new_dbuffer();
00402 const char *p;
00403
00404 e = old->head;
00405 p = old->start;
00406 while (e && (e->len > 0)) {
00407 dbuffer_add(buf, p, e->len);
00408 e = e->next;
00409 p = &e->data[0];
00410 }
00411
00412 return buf;
00413 }
00414
00421 size_t dbuffer_remove (struct dbuffer *buf, size_t len)
00422 {
00423 size_t removed = 0;
00424
00425 if (!buf || !len)
00426 return 0;
00427
00428 while (len > 0 && buf->len > 0) {
00429 const size_t l = (len < buf->head->len) ? len : buf->head->len;
00430 struct dbuffer_element *e = buf->head;
00431 buf->len -= l;
00432 buf->space += l;
00433 len -= l;
00434 e->len -= l;
00435 e->space += l;
00436 removed += l;
00437 buf->start += l;
00438 if (e->len == 0) {
00439 if (e->next) {
00440 buf->head = e->next;
00441 free_element(e);
00442 buf->space -= DBUFFER_ELEMENT_SIZE;
00443 } else {
00444 assert(buf->len == 0);
00445 buf->end = &buf->head->data[0];
00446 }
00447 buf->start = &buf->head->data[0];
00448 }
00449 }
00450 return removed;
00451 }
00452
00471 size_t dbuffer_extract (struct dbuffer *buf, char *data, size_t len)
00472 {
00473 size_t extracted = 0;
00474 if (!buf || !data || !len)
00475 return 0;
00476 while (len > 0 && buf->len > 0) {
00477 const size_t l = (len < buf->head->len) ? len : buf->head->len;
00478 struct dbuffer_element *e = buf->head;
00479 memcpy(data, buf->start, l);
00480 data += l;
00481 len -= l;
00482 buf->len -= l;
00483 buf->space += l;
00484 e->len -= l;
00485 e->space += l;
00486 extracted += l;
00487 buf->start += l;
00488 if (e->len == 0) {
00489 if (e->next) {
00490 buf->head = e->next;
00491 free_element(e);
00492 buf->space -= DBUFFER_ELEMENT_SIZE;
00493 } else {
00494 assert(buf->len == 0);
00495 buf->end = &buf->head->data[0];
00496 }
00497 buf->start = &buf->head->data[0];
00498 }
00499 }
00500 return extracted;
00501 }
00502
00503 void dbuffer_init (void)
00504 {
00505 dbuf_lock = SDL_CreateMutex();
00506 }
00507
00508 void dbuffer_shutdown (void)
00509 {
00510 SDL_DestroyMutex(dbuf_lock);
00511 }