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