1/* Variable-sized buffer with on-stack default allocation.
2 Copyright (C) 2015-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19#ifndef _SCRATCH_BUFFER_H
20#define _SCRATCH_BUFFER_H
21
22/* Scratch buffers with a default stack allocation and fallback to
23 heap allocation. It is expected that this function is used in this
24 way:
25
26 struct scratch_buffer tmpbuf;
27 scratch_buffer_init (&tmpbuf);
28
29 while (!function_that_uses_buffer (tmpbuf.data, tmpbuf.length))
30 if (!scratch_buffer_grow (&tmpbuf))
31 return -1;
32
33 scratch_buffer_free (&tmpbuf);
34 return 0;
35
36 The allocation functions (scratch_buffer_grow,
37 scratch_buffer_grow_preserve, scratch_buffer_set_array_size) make
38 sure that the heap allocation, if any, is freed, so that the code
39 above does not have a memory leak. The buffer still remains in a
40 state that can be deallocated using scratch_buffer_free, so a loop
41 like this is valid as well:
42
43 struct scratch_buffer tmpbuf;
44 scratch_buffer_init (&tmpbuf);
45
46 while (!function_that_uses_buffer (tmpbuf.data, tmpbuf.length))
47 if (!scratch_buffer_grow (&tmpbuf))
48 break;
49
50 scratch_buffer_free (&tmpbuf);
51
52 scratch_buffer_grow and scratch_buffer_grow_preserve are guaranteed
53 to grow the buffer by at least 512 bytes. This means that when
54 using the scratch buffer as a backing store for a non-character
55 array whose element size, in bytes, is 512 or smaller, the scratch
56 buffer only has to grow once to make room for at least one more
57 element.
58*/
59
60#include <stdbool.h>
61#include <stddef.h>
62#include <stdlib.h>
63
64/* Scratch buffer. Must be initialized with scratch_buffer_init
65 before its use. */
66struct scratch_buffer {
67 void *data; /* Pointer to the beginning of the scratch area. */
68 size_t length; /* Allocated space at the data pointer, in bytes. */
69 union { max_align_t __align; char __c[1024]; } __space;
70};
71
72/* Initializes *BUFFER so that BUFFER->data points to BUFFER->__space
73 and BUFFER->length reflects the available space. */
74static inline void
75scratch_buffer_init (struct scratch_buffer *buffer)
76{
77 buffer->data = buffer->__space.__c;
78 buffer->length = sizeof (buffer->__space);
79}
80
81/* Deallocates *BUFFER (if it was heap-allocated). */
82static inline void
83scratch_buffer_free (struct scratch_buffer *buffer)
84{
85 if (buffer->data != buffer->__space.__c)
86 free (ptr: buffer->data);
87}
88
89/* Grow *BUFFER by some arbitrary amount. The buffer contents is NOT
90 preserved. Return true on success, false on allocation failure (in
91 which case the old buffer is freed). On success, the new buffer is
92 larger than the previous size. On failure, *BUFFER is deallocated,
93 but remains in a free-able state, and errno is set. */
94bool __libc_scratch_buffer_grow (struct scratch_buffer *buffer);
95libc_hidden_proto (__libc_scratch_buffer_grow)
96
97/* Alias for __libc_scratch_buffer_grow. */
98static __always_inline bool
99scratch_buffer_grow (struct scratch_buffer *buffer)
100{
101 return __glibc_likely (__libc_scratch_buffer_grow (buffer));
102}
103
104/* Like __libc_scratch_buffer_grow, but preserve the old buffer
105 contents on success, as a prefix of the new buffer. */
106bool __libc_scratch_buffer_grow_preserve (struct scratch_buffer *buffer);
107libc_hidden_proto (__libc_scratch_buffer_grow_preserve)
108
109/* Alias for __libc_scratch_buffer_grow_preserve. */
110static __always_inline bool
111scratch_buffer_grow_preserve (struct scratch_buffer *buffer)
112{
113 return __glibc_likely (__libc_scratch_buffer_grow_preserve (buffer));
114}
115
116/* Grow *BUFFER so that it can store at least NELEM elements of SIZE
117 bytes. The buffer contents are NOT preserved. Both NELEM and SIZE
118 can be zero. Return true on success, false on allocation failure
119 (in which case the old buffer is freed, but *BUFFER remains in a
120 free-able state, and errno is set). It is unspecified whether this
121 function can reduce the array size. */
122bool __libc_scratch_buffer_set_array_size (struct scratch_buffer *buffer,
123 size_t nelem, size_t size);
124libc_hidden_proto (__libc_scratch_buffer_set_array_size)
125
126/* Alias for __libc_scratch_set_array_size. */
127static __always_inline bool
128scratch_buffer_set_array_size (struct scratch_buffer *buffer,
129 size_t nelem, size_t size)
130{
131 return __glibc_likely (__libc_scratch_buffer_set_array_size
132 (buffer, nelem, size));
133}
134
135/* Return a copy of *BUFFER's first SIZE bytes as a heap-allocated block,
136 deallocating *BUFFER if it was heap-allocated. SIZE must be at
137 most *BUFFER's size. Return NULL (setting errno) on memory
138 exhaustion. */
139void *__libc_scratch_buffer_dupfree (struct scratch_buffer *buffer,
140 size_t size);
141libc_hidden_proto (__libc_scratch_buffer_dupfree)
142
143/* Alias for __libc_scratch_dupfree. */
144static __always_inline void *
145scratch_buffer_dupfree (struct scratch_buffer *buffer, size_t size)
146{
147 void *r = __libc_scratch_buffer_dupfree (buffer, size);
148 return __glibc_likely (r != NULL) ? r : NULL;
149}
150
151#endif /* _SCRATCH_BUFFER_H */
152

source code of glibc/include/scratch_buffer.h