]> rtime.felk.cvut.cz Git - ulut.git/blob - ulut/ul_cbuff.h
Fix non-typesafe/void * variant of GAVL to support non-unique keys.
[ulut.git] / ulut / ul_cbuff.h
1 /*******************************************************************
2   uLan Utilities Library - C library of basic reusable constructions
3
4   ul_cbuff.h    - circular buffer
5
6   (C) Copyright 2006 by Pavel Pisa - Originator
7
8   The uLan utilities library can be used, copied and modified under
9   next licenses
10     - GPL - GNU General Public License
11     - LGPL - GNU Lesser General Public License
12     - MPL - Mozilla Public License
13     - and other licenses added by project originators
14   Code can be modified and re-distributed under any combination
15   of the above listed licenses. If contributor does not agree with
16   some of the licenses, he/she can delete appropriate line.
17   Warning, if you delete all lines, you are not allowed to
18   distribute source code and/or binaries utilizing code.
19
20   See files COPYING and README for details.
21
22  *******************************************************************/
23
24 #ifndef _UL_CBUFF_H
25 #define _UL_CBUFF_H
26
27 #include "ul_utdefs.h"
28
29 #include <string.h>
30
31 #ifdef __cplusplus
32 extern "C" {
33 #endif
34
35 #define UL_CBUFF_NO_INLINE
36
37 #ifndef UL_CBUFF_NO_INLINE
38 #define UL_CBUFF_INLINE
39 #endif
40
41 #ifndef ul_cbuff_inline
42 #ifdef UL_CBUFF_INLINE
43 #define ul_cbuff_inline static inline
44 #else
45 #define ul_cbuff_inline
46 #endif
47 #endif
48
49 #define ul_cbuff_align(x) (((x)+3)&~3)
50
51 typedef unsigned int ul_cbuff_loc_t;
52
53 typedef struct ul_cbuff_msg_head_t {
54   unsigned short flags;
55   unsigned short length;
56 } ul_cbuff_msg_head_t;
57
58 #define UL_CBUFF_MSG_READY    0x8000
59 #define UL_CBUFF_MSG_OVERFLOW 0x4000
60 #define UL_CBUFF_MSG_READERS  0x3fff
61
62 #define ul_cbuff_msg_head_size (ul_cbuff_align(sizeof(ul_cbuff_msg_head_t)))
63
64 typedef struct ul_cbuff_state_t {
65   ul_cbuff_loc_t buff_size;
66   ul_cbuff_loc_t head;
67   ul_cbuff_loc_t lasttail;
68   ul_cbuff_loc_t firsttail;
69   unsigned int   cycles;
70   unsigned int   readers;
71   ul_cbuff_loc_t rear_size;
72 } ul_cbuff_state_t;
73
74 typedef struct ul_cbuff_t {
75   unsigned char    *buff_start;
76   ul_cbuff_state_t *state;
77 } ul_cbuff_t;
78
79 typedef struct ul_cbuff_data_info_t {
80   unsigned char *ptr;
81   unsigned char *wrap_ptr;
82   unsigned int  cont_len;
83   unsigned int  wrap_len;
84 } ul_cbuff_data_info_t;
85
86 typedef struct ul_cbuff_put_info_t {
87   ul_cbuff_data_info_t data;
88   ul_cbuff_msg_head_t *msg_head;
89 } ul_cbuff_put_info_t;
90
91 typedef struct ul_cbuff_tail_info_t {
92   ul_cbuff_data_info_t data;
93   ul_cbuff_msg_head_t *msg_head;
94 } ul_cbuff_tail_info_t;
95
96 #if !defined(UL_CBUFF_INLINE)
97
98 void ul_cbuff_mark_ready(ul_cbuff_msg_head_t *msg);
99 int ul_cbuff_is_ready(const ul_cbuff_msg_head_t *msg);
100 int ul_cbuff_head_alloc(ul_cbuff_t *buff, ul_cbuff_put_info_t *put_info, unsigned int size, unsigned int flags);
101 int ul_cbuff_head_put(ul_cbuff_t *buff, ul_cbuff_put_info_t *put_info);
102 ul_cbuff_loc_t ul_cbuff_head_loc(const ul_cbuff_t *buff, const ul_cbuff_msg_head_t *msg_head);
103 ul_cbuff_loc_t ul_cbuff_next_loc(const ul_cbuff_t *buff, const ul_cbuff_msg_head_t *msg_head);
104 int ul_cbuff_msg_head2data(const ul_cbuff_t *buff, ul_cbuff_data_info_t *data, const ul_cbuff_msg_head_t *msg_head);
105 int ul_cbuff_tail_attach(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info, int mode);
106 int ul_cbuff_tail_incontact(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info);
107 int ul_cbuff_tail_test(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info);
108 int ul_cbuff_tail_release(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info);
109 int ul_cbuff_tail_next(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info);
110 int ul_cbuff_tail_state_update(ul_cbuff_t *buff, int release_result, ul_cbuff_loc_t loc, ul_cbuff_loc_t loc_next);
111 int ul_cbuff_tail_detach_onestep(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info);
112 void ul_cbuff_data_do_wrap(ul_cbuff_data_info_t *data_info);
113 int ul_cbuff_data_at_once(ul_cbuff_data_info_t *data_info, void **pptr, int size);
114 int ul_cbuff_put_data(ul_cbuff_data_info_t *data_info, const void *data, int size);
115 int ul_cbuff_get_data(ul_cbuff_data_info_t *data_info, void *data, int size);
116 void *ul_cbuff_get_rear_ptr(ul_cbuff_t *buff, ul_cbuff_msg_head_t *msg_head);
117 void *ul_cbuff_prev_rear_ptr(ul_cbuff_t *buff, ul_cbuff_loc_t loc);
118
119 #endif /* UL_CBUFF_INLINE */
120
121 #if defined(UL_CBUFF_INLINE) || defined(UL_CBUFF_INCLUDE_INTERNAL)
122
123 ul_cbuff_inline void
124 ul_cbuff_mark_ready(ul_cbuff_msg_head_t *msg)
125 {
126   msg->flags|=UL_CBUFF_MSG_READY;
127 }
128
129 ul_cbuff_inline int
130 ul_cbuff_is_ready(const ul_cbuff_msg_head_t *msg)
131 {
132   return msg->flags&UL_CBUFF_MSG_READY;
133 }
134
135 ul_cbuff_inline int
136 ul_cbuff_head_alloc(ul_cbuff_t *buff, ul_cbuff_put_info_t *put_info, unsigned int size, unsigned int flags)
137 {
138   ul_cbuff_state_t *state=buff->state;
139   unsigned int length=size;
140
141   size=ul_cbuff_align(size+state->rear_size)+ul_cbuff_msg_head_size;
142
143   if((state->lasttail > state->head) &&
144      (state->lasttail-state->head <= size))
145       return -1;
146
147   if((state->lasttail > state->head) ||
148      (state->buff_size-state->head > size)){
149     put_info->msg_head=(ul_cbuff_msg_head_t *)(buff->buff_start+state->head);
150
151     put_info->data.ptr=(buff->buff_start+state->head+ul_cbuff_msg_head_size);
152     put_info->data.cont_len=length;
153     put_info->data.wrap_ptr=NULL;
154     put_info->data.wrap_len=0;
155
156     state->head+=size;
157   }else{
158     ul_cbuff_loc_t res_size=state->buff_size-state->head;
159     if(size-res_size >= state->lasttail)
160       return -1;
161
162     put_info->msg_head=(ul_cbuff_msg_head_t *)(buff->buff_start+state->head);
163
164     if(res_size != ul_cbuff_msg_head_size){
165       put_info->data.ptr=(buff->buff_start+state->head+ul_cbuff_msg_head_size);
166       put_info->data.cont_len=res_size-ul_cbuff_msg_head_size;
167       if(put_info->data.cont_len<length){
168         put_info->data.wrap_ptr=buff->buff_start;
169         put_info->data.wrap_len=length-put_info->data.cont_len;
170       }else{
171         put_info->data.wrap_ptr=NULL;
172         put_info->data.wrap_len=0;
173       }
174     }else{
175       put_info->data.ptr=buff->buff_start;
176       put_info->data.cont_len=length;
177       put_info->data.wrap_ptr=NULL;
178       put_info->data.wrap_len=0;
179     }
180
181     state->cycles++;
182     state->head=size-res_size;
183   }
184
185   ((ul_cbuff_msg_head_t *)(buff->buff_start+state->head))->flags=0;
186
187   flags&=~(UL_CBUFF_MSG_READY|UL_CBUFF_MSG_READERS);
188
189   put_info->msg_head->flags|=flags;
190   if(buff->state->readers>0)
191     put_info->msg_head->flags+=buff->state->readers;
192   else if (buff->state->readers==0)
193     put_info->msg_head->flags+=1;
194
195   put_info->msg_head->length=length;
196
197   return 0;
198 }
199
200 ul_cbuff_inline int
201 ul_cbuff_head_put(ul_cbuff_t *buff, ul_cbuff_put_info_t *put_info)
202 {
203   ul_cbuff_mark_ready(put_info->msg_head);
204   put_info->msg_head=NULL;
205   return 0;
206 }
207
208 ul_cbuff_inline ul_cbuff_loc_t
209 ul_cbuff_head_loc(const ul_cbuff_t *buff, const ul_cbuff_msg_head_t *msg_head)
210 {
211   return (unsigned char*)msg_head-buff->buff_start;
212 }
213
214 ul_cbuff_inline ul_cbuff_loc_t
215 ul_cbuff_next_loc(const ul_cbuff_t *buff, const ul_cbuff_msg_head_t *msg_head)
216 {
217   ul_cbuff_loc_t loc;
218   unsigned int size;
219
220   size=ul_cbuff_align(msg_head->length+buff->state->rear_size)+ul_cbuff_msg_head_size;
221
222   loc=(unsigned char*)msg_head-buff->buff_start;
223   if(buff->state->buff_size-loc > size)
224     loc+=size;
225   else
226     loc=size-(buff->state->buff_size-loc);
227
228   return loc;
229 }
230
231 ul_cbuff_inline int
232 ul_cbuff_msg_head2data(const ul_cbuff_t *buff, ul_cbuff_data_info_t *data, const ul_cbuff_msg_head_t *msg_head)
233 {
234   ul_cbuff_loc_t res_size;
235   unsigned int length;
236   ul_cbuff_loc_t msg_loc=(unsigned char *)msg_head-buff->buff_start;
237
238   res_size=buff->state->buff_size-msg_loc;
239   length=msg_head->length;
240
241   if(res_size > ul_cbuff_msg_head_size){
242     data->ptr=(unsigned char*)msg_head+ul_cbuff_msg_head_size;
243     if(res_size-ul_cbuff_msg_head_size >= length){
244       data->cont_len=length;
245       data->wrap_ptr=NULL;
246       data->wrap_len=0;
247     }else{
248       data->cont_len=res_size-ul_cbuff_msg_head_size;
249       data->wrap_ptr=buff->buff_start;
250       data->wrap_len=length-(res_size-ul_cbuff_msg_head_size);
251     }
252   } else {
253     data->ptr=buff->buff_start;
254     data->cont_len=length;
255     data->wrap_ptr=NULL;
256     data->wrap_len=0;
257   }
258   return msg_head->flags;
259 }
260
261 ul_cbuff_inline int
262 ul_cbuff_tail_attach(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info, int mode)
263 {
264   ul_cbuff_state_t *state=buff->state;
265   ul_cbuff_msg_head_t *msg_head;
266
267   if(state->readers>0)
268     msg_head=(ul_cbuff_msg_head_t *)(buff->buff_start+state->head);
269   else if(state->readers==0)
270     msg_head=(ul_cbuff_msg_head_t *)(buff->buff_start+state->lasttail);
271   if(state->readers>=0)
272     state->readers++;
273   tail_info->msg_head=msg_head;
274   tail_info->data.ptr=NULL;
275   return 0;
276 }
277
278 ul_cbuff_inline int
279 ul_cbuff_tail_incontact(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info)
280 {
281   if(tail_info->msg_head==NULL){
282     return 0;
283   }
284   return 1;
285 }
286
287 ul_cbuff_inline int
288 ul_cbuff_tail_test(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info)
289 {
290   ul_cbuff_msg_head_t *msg_head=tail_info->msg_head;
291
292   if(!msg_head)
293     return -1;
294
295   if(!ul_cbuff_is_ready(msg_head))
296     return 0;
297
298   return ul_cbuff_msg_head2data(buff, &tail_info->data, msg_head);
299 }
300
301 ul_cbuff_inline int
302 ul_cbuff_tail_release(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info)
303 {
304   ul_cbuff_msg_head_t *msg_head=tail_info->msg_head;
305   unsigned msg_readers;
306
307   if(!ul_cbuff_is_ready(msg_head))
308     return -1;
309
310   if(buff->state->readers<=0)
311     return 1;
312
313   msg_readers=msg_head->flags&UL_CBUFF_MSG_READERS;
314   if(msg_readers)
315     msg_head->flags--;
316
317   return msg_readers<=1?1:0;
318 }
319
320 ul_cbuff_inline int
321 ul_cbuff_tail_next(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info)
322 {
323   ul_cbuff_msg_head_t *msg_head=tail_info->msg_head;
324
325   if(!ul_cbuff_is_ready(msg_head))
326     return -1;
327
328   tail_info->msg_head=(ul_cbuff_msg_head_t *)(buff->buff_start+
329                         ul_cbuff_next_loc(buff, msg_head));
330   return 0;
331 }
332
333 ul_cbuff_inline int
334 ul_cbuff_tail_state_update(ul_cbuff_t *buff, int release_result, ul_cbuff_loc_t loc, ul_cbuff_loc_t loc_next)
335 {
336   if(loc==buff->state->firsttail)
337     buff->state->firsttail=loc_next;
338
339   if(release_result<=0)
340     return 0;
341
342   if(loc==buff->state->lasttail){
343     buff->state->lasttail=loc_next;
344     return 1;
345   }else{
346     return -1;
347   }
348 }
349
350 ul_cbuff_inline int
351 ul_cbuff_tail_detach_onestep(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info)
352 {
353   ul_cbuff_state_t *state=buff->state;
354   ul_cbuff_loc_t loc;
355   ul_cbuff_loc_t loc_next;
356   unsigned msg_readers;
357
358   if(tail_info->msg_head==NULL)
359     return 0;
360
361   loc = ul_cbuff_head_loc(buff, tail_info->msg_head);
362
363   if(loc!=state->head) {
364     if(!ul_cbuff_is_ready(tail_info->msg_head))
365       return 2;
366     msg_readers=tail_info->msg_head->flags&UL_CBUFF_MSG_READERS;
367     loc_next=ul_cbuff_next_loc(buff, tail_info->msg_head);
368     if(msg_readers)
369       tail_info->msg_head->flags--;
370     tail_info->msg_head=(ul_cbuff_msg_head_t *)(buff->buff_start+loc_next);
371     ul_cbuff_tail_state_update(buff, msg_readers<=1? 1: 0, loc, loc_next);
372     return 1;
373   }
374
375   if(state->readers>0)
376     state->readers--;
377   tail_info->msg_head=NULL;
378   tail_info->data.ptr=NULL;
379   return 0;
380 }
381
382
383 ul_cbuff_inline void
384 ul_cbuff_data_do_wrap(ul_cbuff_data_info_t *data_info)
385 {
386   data_info->ptr=data_info->wrap_ptr;
387   data_info->cont_len=data_info->wrap_len;
388   data_info->wrap_ptr=NULL;
389   data_info->wrap_len=0;
390 }
391
392 ul_cbuff_inline int
393 ul_cbuff_data_at_once(ul_cbuff_data_info_t *data_info, void **pptr, int size)
394 {
395   int cont_len;
396
397   *pptr=data_info->ptr;
398   if(!data_info->ptr)
399     return 0;
400   cont_len=data_info->cont_len;
401   if(cont_len>size){
402     cont_len=size;
403     data_info->ptr+=size;
404     data_info->cont_len-=cont_len;
405   }else{
406     ul_cbuff_data_do_wrap(data_info);
407   }
408   return cont_len;
409 }
410
411 ul_cbuff_inline int
412 ul_cbuff_put_data(ul_cbuff_data_info_t *data_info, const void *data, int size)
413 {
414   void *ptr;
415   int count;
416   int cont_len;
417
418   ptr=data_info->ptr;
419   if(!ptr)
420     return 0;
421   cont_len=data_info->cont_len;
422   if(cont_len>size){
423     cont_len=size;
424     data_info->ptr+=size;
425     data_info->cont_len-=cont_len;
426   }else{
427     ul_cbuff_data_do_wrap(data_info);
428   }
429   if(cont_len<=0)
430     return 0;
431   memcpy(ptr,data,cont_len);
432   count=cont_len;
433   cont_len=size-cont_len;
434   if(!cont_len)
435     return count;
436
437   ptr=data_info->ptr;
438   if(!ptr)
439     return count;
440   data=(char*)data+count;
441   if(cont_len>data_info->cont_len)
442     cont_len=data_info->cont_len;
443   data_info->ptr+=cont_len;
444   data_info->cont_len-=cont_len;
445   memcpy(ptr,data,cont_len);
446
447   return cont_len+count;
448 }
449
450 ul_cbuff_inline int
451 ul_cbuff_get_data(ul_cbuff_data_info_t *data_info, void *data, int size)
452 {
453   void *ptr;
454   int count;
455   int cont_len;
456
457   ptr=data_info->ptr;
458   if(!ptr)
459     return 0;
460   cont_len=data_info->cont_len;
461   if(cont_len>size){
462     cont_len=size;
463     data_info->ptr+=size;
464     data_info->cont_len-=cont_len;
465   }else{
466     ul_cbuff_data_do_wrap(data_info);
467   }
468   if(cont_len<=0)
469     return 0;
470   memcpy(data,ptr,cont_len);
471   count=cont_len;
472   cont_len=size-cont_len;
473   if(!cont_len)
474     return count;
475
476   ptr=data_info->ptr;
477   if(!ptr)
478     return count;
479   data=(char*)data+count;
480   if(cont_len>data_info->cont_len)
481     cont_len=data_info->cont_len;
482   data_info->ptr+=cont_len;
483   data_info->cont_len-=cont_len;
484   memcpy(data,ptr,cont_len);
485
486   return cont_len+count;
487 }
488
489
490 ul_cbuff_inline void *
491 ul_cbuff_get_rear_ptr(ul_cbuff_t *buff, ul_cbuff_msg_head_t *msg_head)
492 {
493   ul_cbuff_loc_t loc;
494   unsigned int size;
495   ul_cbuff_state_t *state=buff->state;
496
497   size=ul_cbuff_align(msg_head->length+state->rear_size)+ul_cbuff_msg_head_size;
498   size-=state->rear_size;
499
500   loc=(unsigned char*)msg_head-buff->buff_start;
501   if(state->buff_size-loc > size)
502     loc+=size;
503   else
504     loc=size-(state->buff_size-loc);
505
506   return buff->buff_start+loc;
507 }
508
509 ul_cbuff_inline void *
510 ul_cbuff_prev_rear_ptr(ul_cbuff_t *buff, ul_cbuff_loc_t loc)
511 {
512   ul_cbuff_state_t *state=buff->state;
513
514   if(loc>state->rear_size)
515     return buff->buff_start+loc-state->rear_size;
516   else
517     return buff->buff_start+loc+state->buff_size-state->rear_size;
518 }
519
520 #endif /*UL_CBUFF_INLINE*/
521
522 int ul_cbuff_init(ul_cbuff_t *buff, ul_cbuff_state_t *state,
523                   void *buff_start, ul_cbuff_loc_t size);
524
525
526 #ifdef __cplusplus
527 } /* extern "C"*/
528 #endif
529
530 #endif /* _UL_CBUFF_H */