34e30c1c1f863f7fa299f79d34aaa26e3d81f36f
[silc.git] / lib / silcutil / silcbuffer.h
1 /*
2
3   silcbuffer.h
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1998 - 2000 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /* $Id$ */
21 /* Optimized buffer managing routines.  These are short inline functions. */
22
23 #ifndef SILCBUFFER_H
24 #define SILCBUFFER_H
25
26 /* 
27    SILC Buffer object.
28
29    SilcBuffer is very simple and easy to use, yet you can do to the
30    buffer almost anything you want with its method functions. The buffer
31    is constructed of four different data sections that in whole creates
32    the allocated data area. Following short description of the fields
33    of the buffer.
34
35    uint32 truelen;
36
37        True length of the buffer. This is set at the allocation of the
38        buffer and it should not be touched after that. This field should
39        be considered read-only.
40
41    uint32 len;
42
43        Length of the currently valid data area. Tells the length of the 
44        data at the buffer. This is set to zero at the allocation of the
45        buffer and should not be updated by hand. Method functions of the
46        buffer automatically updates this field. However, it is not
47        read-only field and can be updated manually if necessary.
48
49    unsiged char *head;
50
51        Head of the allocated buffer. This is the start of the allocated
52        data area and remains as same throughout the lifetime of the buffer.
53        However, the end of the head area or the start of the currently valid
54        data area is variable.
55
56        --------------------------------
57        | head  | data         | tail  |
58        --------------------------------
59        ^       ^
60
61        Current head section in the buffer is sb->data - sb->head.
62
63    unsigned char *data;
64
65        Currently valid data area. This is the start of the currently valid
66        main data area. The data area is variable in all directions.
67
68        --------------------------------
69        | head  | data         | tail  |
70        --------------------------------
71                ^              ^
72  
73        Current valid data area in the buffer is sb->tail - sb->data.
74
75     unsigned char *tail;
76
77        Tail of the buffer. This is the end of the currently valid data area
78        or start of the tail area. The start of the tail area is variable.
79
80        --------------------------------
81        | head  | data         | tail  |
82        --------------------------------
83                               ^       ^
84
85        Current tail section in the buffer is sb->end - sb->tail.
86
87    unsigned char *end;
88
89        End of the allocated buffer. This is the end of the allocated data
90        area and remains as same throughout the lifetime of the buffer.
91        Usually this field is not needed except when checking the size
92        of the buffer.
93
94        --------------------------------
95        | head  | data         | tail  |
96        --------------------------------
97                                       ^
98
99        Length of the entire buffer is (ie. truelen) sb->end - sb->head.
100
101     Currently valid data area is considered to be the main data area in
102     the buffer. However, the entire buffer is of course valid data and can
103     be used as such. Usually head section of the buffer includes different
104     kind of headers or similiar. Data section includes the main data of
105     the buffer. Tail section can be seen as a reserve space of the data
106     section. Tail section can be pulled towards end thus the data section
107     becomes larger.
108
109     This buffer scheme is based on Linux kernel's Socket Buffer, the 
110     idea were taken directly from there and credits should go there.
111
112 */
113
114 typedef struct SilcBufferStruct {
115   uint32 truelen;
116   uint32 len;
117   unsigned char *head;
118   unsigned char *data;
119   unsigned char *tail;
120   unsigned char *end;
121 } SilcBufferObject;
122
123 typedef SilcBufferObject *SilcBuffer;
124
125 /* Macros */
126
127 /* Returns the true length of the buffer. This is used to pull
128    the buffer area to the end of the buffer. */
129 #define SILC_BUFFER_END(x) ((x)->end - (x)->head)
130
131 /* Inline functions */
132
133 extern inline
134 SilcBuffer silc_buffer_alloc(uint32 len)
135 {
136   SilcBuffer sb;
137
138   /* Allocate new SilcBuffer */
139   sb = (SilcBuffer)silc_calloc(1, sizeof(*sb));
140
141   /* Allocate the actual data area */
142   sb->head = (unsigned char *)silc_calloc(len, sizeof(*sb->head));
143
144   /* Set pointers to the new buffer */
145   sb->truelen = len;
146   sb->data = sb->head;
147   sb->tail = sb->head;
148   sb->end = sb->head + sb->truelen;
149
150   return sb;
151 }
152
153 /* Free's a SilcBuffer */
154
155 extern inline
156 void silc_buffer_free(SilcBuffer sb)
157 {
158   if (sb) {
159     memset(sb->head, 'F', sb->truelen);
160     silc_free(sb->head);
161     silc_free(sb);
162   }
163 }
164
165 /* Pulls current data area towards end. The length of the currently
166    valid data area is also decremented. Returns pointer to the data
167    area before pulling. 
168
169    Example:
170    ---------------------------------
171    | head  | data       | tail     |
172    ---------------------------------
173            ^
174            Pulls the start of the data area.
175
176    ---------------------------------
177    | head     | data    | tail     |
178    ---------------------------------
179            ^
180 */
181
182 extern inline 
183 unsigned char *silc_buffer_pull(SilcBuffer sb, uint32 len)
184 {
185   unsigned char *old_data = sb->data;
186
187 #ifdef SILC_DEBUG
188   assert(len <= (sb->tail - sb->data));
189 #endif
190
191   sb->data += len;
192   sb->len -= len;
193
194   return old_data;
195 }
196
197 /* Pushes current data area towards beginning. Length of the currently
198    valid data area is also incremented. Returns a pointer to the 
199    data area before pushing. 
200
201    Example:
202    ---------------------------------
203    | head     | data    | tail     |
204    ---------------------------------
205               ^
206               Pushes the start of the data area.
207
208    ---------------------------------
209    | head  | data       | tail     |
210    ---------------------------------
211               ^
212 */
213
214 extern inline 
215 unsigned char *silc_buffer_push(SilcBuffer sb, uint32 len)
216 {
217   unsigned char *old_data = sb->data;
218
219 #ifdef SILC_DEBUG
220   assert((sb->data - len) >= sb->head);
221 #endif
222
223   sb->data -= len;
224   sb->len += len;
225
226   return old_data;
227 }
228
229 /* Pulls current tail section towards end. Length of the current valid
230    data area is also incremented. Returns a pointer to the data area 
231    before pulling.
232
233    Example:
234    ---------------------------------
235    | head  | data       | tail     |
236    ---------------------------------
237                         ^
238                         Pulls the start of the tail section.
239
240    ---------------------------------
241    | head  | data           | tail |
242    ---------------------------------
243                         ^
244 */
245
246 extern inline 
247 unsigned char *silc_buffer_pull_tail(SilcBuffer sb, uint32 len)
248 {
249   unsigned char *old_tail = sb->tail;
250
251 #ifdef SILC_DEBUG
252   assert((sb->end - sb->tail) >= len);
253 #endif
254
255   sb->tail += len;
256   sb->len += len;
257
258   return old_tail;
259 }
260
261 /* Pushes current tail section towards beginning. Length of the current
262    valid data area is also decremented. Returns a pointer to the 
263    tail section before pushing. 
264
265    Example:
266    ---------------------------------
267    | head  | data           | tail |
268    ---------------------------------
269                             ^
270                             Pushes the start of the tail section.
271
272    ---------------------------------
273    | head  | data       | tail     |
274    ---------------------------------
275                             ^
276 */
277
278 extern inline
279 unsigned char *silc_buffer_push_tail(SilcBuffer sb, uint32 len)
280 {
281   unsigned char *old_tail = sb->tail;
282
283 #ifdef SILC_DEBUG
284   assert((sb->tail - len) >= sb->data);
285 #endif
286
287   sb->tail -= len;
288   sb->len -= len;
289
290   return old_tail;
291 }
292
293 /* Puts data at the head of the buffer. Returns pointer to the copied
294    data area. 
295    
296    Example:
297    ---------------------------------
298    | head  | data       | tail     |
299    ---------------------------------
300    ^
301    Puts data to the head section. 
302 */
303
304 extern inline
305 unsigned char *silc_buffer_put_head(SilcBuffer sb, 
306                                     unsigned char *data,
307                                     uint32 len)
308 {
309 #ifdef SILC_DEBUG
310   assert((sb->data - sb->head) >= len);
311 #endif
312   return (unsigned char *)memcpy(sb->head, data, len);
313 }
314
315 /* Puts data at the start of the valid data area. Returns a pointer 
316    to the copied data area. 
317
318    Example:
319    ---------------------------------
320    | head  | data       | tail     |
321    ---------------------------------
322            ^
323            Puts data to the data section.
324 */
325
326 extern inline
327 unsigned char *silc_buffer_put(SilcBuffer sb, 
328                                unsigned char *data,
329                                uint32 len)
330 {
331 #ifdef SILC_DEBUG
332   assert((sb->tail - sb->data) >= len);
333 #endif
334   return (unsigned char *)memcpy(sb->data, data, len);
335 }
336
337 /* Puts data at the tail of the buffer. Returns pointer to the copied
338    data area. 
339
340    Example:
341    ---------------------------------
342    | head  | data           | tail |
343    ---------------------------------
344                             ^
345                             Puts data to the tail section.
346 */
347
348 extern inline
349 unsigned char *silc_buffer_put_tail(SilcBuffer sb, 
350                                     unsigned char *data,
351                                     uint32 len)
352 {
353 #ifdef SILC_DEBUG
354   assert((sb->end - sb->tail) >= len);
355 #endif
356   return (unsigned char *)memcpy(sb->tail, data, len);
357 }
358
359 #endif