Initial import
[sliver-openvswitch.git] / 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->next = NULL;
42 }
43
44 /* Initializes 'b' as a buffer with an initial capacity of 'size' bytes. */
45 void
46 buffer_init(struct buffer *b, size_t size)
47 {
48     buffer_use(b, size ? xmalloc(size) : NULL, size);
49 }
50
51 /* Frees memory that 'b' points to. */
52 void
53 buffer_uninit(struct buffer *b) 
54 {
55     if (b) {
56         free(b->base);
57     }
58 }
59
60 /* Frees memory that 'b' points to and allocates a new buffer */
61 void
62 buffer_reinit(struct buffer *b, size_t size)
63 {
64     buffer_uninit(b);
65     buffer_init(b, size);
66 }
67
68 /* Creates and returns a new buffer with an initial capacity of 'size'
69  * bytes. */
70 struct buffer *
71 buffer_new(size_t size)
72 {
73     struct buffer *b = xmalloc(sizeof *b);
74     buffer_init(b, size);
75     return b;
76 }
77
78 /* Frees memory that 'b' points to, as well as 'b' itself. */
79 void
80 buffer_delete(struct buffer *b) 
81 {
82     if (b) {
83         buffer_uninit(b);
84         free(b);
85     }
86 }
87
88 /* Returns the number of bytes of headroom in 'b', that is, the number of bytes
89  * of unused space in buffer 'b' before the data that is in use.  (Most
90  * commonly, the data in a buffer is at its beginning, and thus the buffer's
91  * headroom is 0.) */
92 size_t
93 buffer_headroom(struct buffer *b) 
94 {
95     return b->data - b->base;
96 }
97
98 /* Returns the number of bytes that may be appended to the tail end of buffer
99  * 'b' before the buffer must be reallocated. */
100 size_t
101 buffer_tailroom(struct buffer *b) 
102 {
103     return buffer_end(b) - buffer_tail(b);
104 }
105
106 /* Ensures that 'b' has room for at least 'size' bytes at its tail end,
107  * reallocating and copying its data if necessary. */
108 void
109 buffer_reserve_tailroom(struct buffer *b, size_t size) 
110 {
111     if (size > buffer_tailroom(b)) {
112         size_t headroom = buffer_headroom(b);
113         size_t new_allocated = b->allocated + MAX(size, 64);
114         void *new_base = xmalloc(new_allocated);
115         memcpy(new_base, b->base, b->allocated);
116         free(b->base);
117         b->base = new_base;
118         b->allocated = new_allocated;
119         b->data = new_base + headroom;
120     }
121 }
122
123 /* Appends 'size' bytes of data to the tail end of 'b', reallocating and
124  * copying its data if necessary.  Returns a pointer to the first byte of the
125  * new data, which is left uninitialized. */
126 void *
127 buffer_put_uninit(struct buffer *b, size_t size) 
128 {
129     void *p;
130     buffer_reserve_tailroom(b, size);
131     p = buffer_tail(b);
132     b->size += size;
133     return p;
134 }
135
136 /* Appends the 'size' bytes of data in 'p' to the tail end of 'b'.  Data in 'b'
137  * is reallocated and copied if necessary. */
138 void
139 buffer_put(struct buffer *b, const void *p, size_t size) 
140 {
141     memcpy(buffer_put_uninit(b, size), p, size);
142 }
143
144 /* If 'b' contains at least 'offset + size' bytes of data, returns a pointer to
145  * byte 'offset'.  Otherwise, returns a null pointers. */
146 void *
147 buffer_at(const struct buffer *b, size_t offset, size_t size) 
148 {
149     return offset + size <= b->size ? (char *) b->data + offset : NULL;
150 }
151
152 /* Returns a pointer to byte 'offset' in 'b', which must contain at least
153  * 'offset + size' bytes of data. */
154 void *
155 buffer_at_assert(const struct buffer *b, size_t offset, size_t size) 
156 {
157     assert(offset + size <= b->size);
158     return ((char *) b->data) + offset;
159 }
160
161 /* Returns the byte following the last byte of data in use in 'b'. */
162 void *
163 buffer_tail(const struct buffer *b) 
164 {
165     return (char *) b->data + b->size;
166 }
167
168 /* Returns the byte following the last byte allocated for use (but not
169  * necessarily in use) by 'b'. */
170 void *
171 buffer_end(const struct buffer *b) 
172 {
173     return (char *) b->base + b->allocated;
174 }
175
176 /* Clears any data from 'b'. */
177 void
178 buffer_clear(struct buffer *b) 
179 {
180     b->data = b->base;
181     b->size = 0;
182 }
183
184 /* Removes 'size' bytes from the head end of 'b', which must contain at least
185  * 'size' bytes of data. */
186 void
187 buffer_pull(struct buffer *b, size_t size) 
188 {
189     assert(b->size >= size);
190     b->data += size;
191     b->size -= size;
192 }