updates.
[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 {
115   uint32 truelen;
116   uint32 len;
117   unsigned char *head;
118   unsigned char *data;
119   unsigned char *tail;
120   unsigned char *end;
121 } *SilcBuffer, SilcBufferStruct;
122
123 /* Macros */
124
125 /* Returns the true length of the buffer. This is used to pull
126    the buffer area to the end of the buffer. */
127 #define SILC_BUFFER_END(x) ((x)->end - (x)->head)
128
129 /* Inline functions */
130
131 extern inline
132 SilcBuffer silc_buffer_alloc(uint32 len)
133 {
134   SilcBuffer sb;
135
136   /* Allocate new SilcBuffer */
137   sb = (SilcBuffer)silc_calloc(1, sizeof(*sb));
138
139   /* Allocate the actual data area */
140   sb->head = (unsigned char *)silc_calloc(len, sizeof(*sb->head));
141
142   /* Set pointers to the new buffer */
143   sb->truelen = len;
144   sb->data = sb->head;
145   sb->tail = sb->head;
146   sb->end = sb->head + sb->truelen;
147
148   return sb;
149 }
150
151 /* Free's a SilcBuffer */
152
153 extern inline
154 void silc_buffer_free(SilcBuffer sb)
155 {
156   if (sb) {
157     memset(sb->head, 'F', sb->truelen);
158     silc_free(sb->head);
159     silc_free(sb);
160   }
161 }
162
163 /* Sets the `data' and `data_len' to the buffer pointer sent as argument.
164    The data area is automatically set to the `data_len'. This function
165    can be used to set the data to static buffer without needing any
166    memory allocations. The `data' will not be copied to the buffer. */
167
168 extern inline
169 void silc_buffer_set(SilcBuffer sb, unsigned char *data, uint32 data_len)
170 {
171   sb->data = sb->head = data;
172   sb->tail = sb->end = data + data_len;
173   sb->len = sb->truelen = data_len;
174 }
175
176 /* Pulls current data area towards end. The length of the currently
177    valid data area is also decremented. Returns pointer to the data
178    area before pulling. 
179
180    Example:
181    ---------------------------------
182    | head  | data       | tail     |
183    ---------------------------------
184            ^
185            Pulls the start of the data area.
186
187    ---------------------------------
188    | head     | data    | tail     |
189    ---------------------------------
190            ^
191 */
192
193 extern inline 
194 unsigned char *silc_buffer_pull(SilcBuffer sb, uint32 len)
195 {
196   unsigned char *old_data = sb->data;
197
198 #ifdef SILC_DEBUG
199   assert(len <= (sb->tail - sb->data));
200 #endif
201
202   sb->data += len;
203   sb->len -= len;
204
205   return old_data;
206 }
207
208 /* Pushes current data area towards beginning. Length of the currently
209    valid data area is also incremented. Returns a pointer to the 
210    data area before pushing. 
211
212    Example:
213    ---------------------------------
214    | head     | data    | tail     |
215    ---------------------------------
216               ^
217               Pushes the start of the data area.
218
219    ---------------------------------
220    | head  | data       | tail     |
221    ---------------------------------
222               ^
223 */
224
225 extern inline 
226 unsigned char *silc_buffer_push(SilcBuffer sb, uint32 len)
227 {
228   unsigned char *old_data = sb->data;
229
230 #ifdef SILC_DEBUG
231   assert((sb->data - len) >= sb->head);
232 #endif
233
234   sb->data -= len;
235   sb->len += len;
236
237   return old_data;
238 }
239
240 /* Pulls current tail section towards end. Length of the current valid
241    data area is also incremented. Returns a pointer to the data area 
242    before pulling.
243
244    Example:
245    ---------------------------------
246    | head  | data       | tail     |
247    ---------------------------------
248                         ^
249                         Pulls the start of the tail section.
250
251    ---------------------------------
252    | head  | data           | tail |
253    ---------------------------------
254                         ^
255 */
256
257 extern inline 
258 unsigned char *silc_buffer_pull_tail(SilcBuffer sb, uint32 len)
259 {
260   unsigned char *old_tail = sb->tail;
261
262 #ifdef SILC_DEBUG
263   assert((sb->end - sb->tail) >= len);
264 #endif
265
266   sb->tail += len;
267   sb->len += len;
268
269   return old_tail;
270 }
271
272 /* Pushes current tail section towards beginning. Length of the current
273    valid data area is also decremented. Returns a pointer to the 
274    tail section before pushing. 
275
276    Example:
277    ---------------------------------
278    | head  | data           | tail |
279    ---------------------------------
280                             ^
281                             Pushes the start of the tail section.
282
283    ---------------------------------
284    | head  | data       | tail     |
285    ---------------------------------
286                             ^
287 */
288
289 extern inline
290 unsigned char *silc_buffer_push_tail(SilcBuffer sb, uint32 len)
291 {
292   unsigned char *old_tail = sb->tail;
293
294 #ifdef SILC_DEBUG
295   assert((sb->tail - len) >= sb->data);
296 #endif
297
298   sb->tail -= len;
299   sb->len -= len;
300
301   return old_tail;
302 }
303
304 /* Puts data at the head of the buffer. Returns pointer to the copied
305    data area. 
306    
307    Example:
308    ---------------------------------
309    | head  | data       | tail     |
310    ---------------------------------
311    ^
312    Puts data to the head section. 
313 */
314
315 extern inline
316 unsigned char *silc_buffer_put_head(SilcBuffer sb, 
317                                     unsigned char *data,
318                                     uint32 len)
319 {
320 #ifdef SILC_DEBUG
321   assert((sb->data - sb->head) >= len);
322 #endif
323   return (unsigned char *)memcpy(sb->head, data, len);
324 }
325
326 /* Puts data at the start of the valid data area. Returns a pointer 
327    to the copied data area. 
328
329    Example:
330    ---------------------------------
331    | head  | data       | tail     |
332    ---------------------------------
333            ^
334            Puts data to the data section.
335 */
336
337 extern inline
338 unsigned char *silc_buffer_put(SilcBuffer sb, 
339                                unsigned char *data,
340                                uint32 len)
341 {
342 #ifdef SILC_DEBUG
343   assert((sb->tail - sb->data) >= len);
344 #endif
345   return (unsigned char *)memcpy(sb->data, data, len);
346 }
347
348 /* Puts data at the tail of the buffer. Returns pointer to the copied
349    data area. 
350
351    Example:
352    ---------------------------------
353    | head  | data           | tail |
354    ---------------------------------
355                             ^
356                             Puts data to the tail section.
357 */
358
359 extern inline
360 unsigned char *silc_buffer_put_tail(SilcBuffer sb, 
361                                     unsigned char *data,
362                                     uint32 len)
363 {
364 #ifdef SILC_DEBUG
365   assert((sb->end - sb->tail) >= len);
366 #endif
367   return (unsigned char *)memcpy(sb->tail, data, len);
368 }
369
370 #endif