1a988d4c0e5b410858a20a92977539f920800639
[openvswitch] / lib / buffer.c
1 /* Copyright (C) 2007 Board of Trustees, Leland Stanford Jr. University.
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy
4  * of this software and associated documentation files (the "Software"), to
5  * deal in the Software without restriction, including without limitation the
6  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7  * sell copies of the Software, and to permit persons to whom the Software is
8  * furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19  * IN THE SOFTWARE.
20  */
21
22 #include "buffer.h"
23 #include <assert.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include "util.h"
27
28 /* Initializes 'b' as an empty buffer that contains the 'allocated' bytes of
29  * memory starting at 'base'.
30  *
31  * 'base' should ordinarily be the first byte of a region obtained from
32  * malloc(), but in circumstances where it can be guaranteed that 'b' will
33  * never need to be expanded or freed, it can be a pointer into arbitrary
34  * memory. */
35 void
36 buffer_use(struct buffer *b, void *base, size_t allocated)
37 {
38     b->base = b->data = base;
39     b->allocated = allocated;
40     b->size = 0;
41     b->l2 = b->l3 = b->l4 = NULL;
42     b->next = NULL;
43 }
44
45 /* Initializes 'b' as a buffer with an initial capacity of 'size' bytes. */
46 void
47 buffer_init(struct buffer *b, size_t size)
48 {
49     buffer_use(b, size ? xmalloc(size) : NULL, size);
50 }
51
52 /* Frees memory that 'b' points to. */
53 void
54 buffer_uninit(struct buffer *b) 
55 {
56     if (b) {
57         free(b->base);
58     }
59 }
60
61 /* Frees memory that 'b' points to and allocates a new buffer */
62 void
63 buffer_reinit(struct buffer *b, size_t size)
64 {
65     buffer_uninit(b);
66     buffer_init(b, size);
67 }
68
69 /* Creates and returns a new buffer with an initial capacity of 'size'
70  * bytes. */
71 struct buffer *
72 buffer_new(size_t size)
73 {
74     struct buffer *b = xmalloc(sizeof *b);
75     buffer_init(b, size);
76     return b;
77 }
78
79 struct buffer *
80 buffer_clone(const struct buffer *buffer) 
81 {
82     /* FIXME: reference counting. */
83     struct buffer *b = buffer_new(buffer->size);
84     buffer_put(b, buffer->data, buffer->size);
85     return b;
86 }
87
88 /* Frees memory that 'b' points to, as well as 'b' itself. */
89 void
90 buffer_delete(struct buffer *b) 
91 {
92     if (b) {
93         buffer_uninit(b);
94         free(b);
95     }
96 }
97
98 /* Returns the number of bytes of headroom in 'b', that is, the number of bytes
99  * of unused space in buffer 'b' before the data that is in use.  (Most
100  * commonly, the data in a buffer is at its beginning, and thus the buffer's
101  * headroom is 0.) */
102 size_t
103 buffer_headroom(struct buffer *b) 
104 {
105     return b->data - b->base;
106 }
107
108 /* Returns the number of bytes that may be appended to the tail end of buffer
109  * 'b' before the buffer must be reallocated. */
110 size_t
111 buffer_tailroom(struct buffer *b) 
112 {
113     return buffer_end(b) - buffer_tail(b);
114 }
115
116 /* Ensures that 'b' has room for at least 'size' bytes at its tail end,
117  * reallocating and copying its data if necessary. */
118 void
119 buffer_reserve_tailroom(struct buffer *b, size_t size) 
120 {
121     if (size > buffer_tailroom(b)) {
122         size_t new_allocated = b->allocated + MAX(size, 64);
123         void *new_base = xmalloc(new_allocated);
124         uintptr_t base_delta = new_base - b->base;
125         memcpy(new_base, b->base, b->allocated);
126         free(b->base);
127         b->base = new_base;
128         b->allocated = new_allocated;
129         b->data += base_delta;
130         if (b->l2) {
131             b->l2 += base_delta;
132         }
133         if (b->l3) {
134             b->l3 += base_delta;
135         }
136         if (b->l4) {
137             b->l4 += base_delta;
138         }
139     }
140 }
141
142 void
143 buffer_reserve_headroom(struct buffer *b, size_t size) 
144 {
145     assert(size <= buffer_headroom(b));
146 }
147
148 /* Appends 'size' bytes of data to the tail end of 'b', reallocating and
149  * copying its data if necessary.  Returns a pointer to the first byte of the
150  * new data, which is left uninitialized. */
151 void *
152 buffer_put_uninit(struct buffer *b, size_t size) 
153 {
154     void *p;
155     buffer_reserve_tailroom(b, size);
156     p = buffer_tail(b);
157     b->size += size;
158     return p;
159 }
160
161 /* Appends the 'size' bytes of data in 'p' to the tail end of 'b'.  Data in 'b'
162  * is reallocated and copied if necessary. */
163 void
164 buffer_put(struct buffer *b, const void *p, size_t size) 
165 {
166     memcpy(buffer_put_uninit(b, size), p, size);
167 }
168
169 void *
170 buffer_push_uninit(struct buffer *b, size_t size) 
171 {
172     buffer_reserve_headroom(b, size);
173     b->data -= size;
174     b->size += size;
175     return b->data;
176 }
177
178 /* If 'b' contains at least 'offset + size' bytes of data, returns a pointer to
179  * byte 'offset'.  Otherwise, returns a null pointers. */
180 void *
181 buffer_at(const struct buffer *b, size_t offset, size_t size) 
182 {
183     return offset + size <= b->size ? (char *) b->data + offset : NULL;
184 }
185
186 /* Returns a pointer to byte 'offset' in 'b', which must contain at least
187  * 'offset + size' bytes of data. */
188 void *
189 buffer_at_assert(const struct buffer *b, size_t offset, size_t size) 
190 {
191     assert(offset + size <= b->size);
192     return ((char *) b->data) + offset;
193 }
194
195 /* Returns the byte following the last byte of data in use in 'b'. */
196 void *
197 buffer_tail(const struct buffer *b) 
198 {
199     return (char *) b->data + b->size;
200 }
201
202 /* Returns the byte following the last byte allocated for use (but not
203  * necessarily in use) by 'b'. */
204 void *
205 buffer_end(const struct buffer *b) 
206 {
207     return (char *) b->base + b->allocated;
208 }
209
210 /* Clears any data from 'b'. */
211 void
212 buffer_clear(struct buffer *b) 
213 {
214     b->data = b->base;
215     b->size = 0;
216 }
217
218 /* Removes 'size' bytes from the head end of 'b', which must contain at least
219  * 'size' bytes of data. */
220 void
221 buffer_pull(struct buffer *b, size_t size) 
222 {
223     assert(b->size >= size);
224     b->data += size;
225     b->size -= size;
226 }
227