1 | /* Variable-sized buffer with on-stack default allocation.
|
---|
2 | Copyright (C) 2017-2022 Free Software Foundation, Inc.
|
---|
3 |
|
---|
4 | This file is free software: you can redistribute it and/or modify
|
---|
5 | it under the terms of the GNU Lesser General Public License as
|
---|
6 | published by the Free Software Foundation; either version 2.1 of the
|
---|
7 | License, or (at your option) any later version.
|
---|
8 |
|
---|
9 | This file is distributed in the hope that it will be useful,
|
---|
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
12 | GNU Lesser General Public License for more details.
|
---|
13 |
|
---|
14 | You should have received a copy of the GNU Lesser General Public License
|
---|
15 | along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
---|
16 |
|
---|
17 | /* Written by Paul Eggert, 2017. */
|
---|
18 |
|
---|
19 | #ifndef _GL_SCRATCH_BUFFER_H
|
---|
20 | #define _GL_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 | /* Scratch buffer. Must be initialized with scratch_buffer_init
|
---|
61 | before its use. */
|
---|
62 | struct scratch_buffer;
|
---|
63 |
|
---|
64 | /* Initializes *BUFFER so that BUFFER->data points to BUFFER->__space
|
---|
65 | and BUFFER->length reflects the available space. */
|
---|
66 | #if 0
|
---|
67 | extern void scratch_buffer_init (struct scratch_buffer *buffer);
|
---|
68 | #endif
|
---|
69 |
|
---|
70 | /* Deallocates *BUFFER (if it was heap-allocated). */
|
---|
71 | #if 0
|
---|
72 | extern void scratch_buffer_free (struct scratch_buffer *buffer);
|
---|
73 | #endif
|
---|
74 |
|
---|
75 | /* Grow *BUFFER by some arbitrary amount. The buffer contents is NOT
|
---|
76 | preserved. Return true on success, false on allocation failure (in
|
---|
77 | which case the old buffer is freed). On success, the new buffer is
|
---|
78 | larger than the previous size. On failure, *BUFFER is deallocated,
|
---|
79 | but remains in a free-able state, and errno is set. */
|
---|
80 | #if 0
|
---|
81 | extern bool scratch_buffer_grow (struct scratch_buffer *buffer);
|
---|
82 | #endif
|
---|
83 |
|
---|
84 | /* Like scratch_buffer_grow, but preserve the old buffer
|
---|
85 | contents on success, as a prefix of the new buffer. */
|
---|
86 | #if 0
|
---|
87 | extern bool scratch_buffer_grow_preserve (struct scratch_buffer *buffer);
|
---|
88 | #endif
|
---|
89 |
|
---|
90 | /* Grow *BUFFER so that it can store at least NELEM elements of SIZE
|
---|
91 | bytes. The buffer contents are NOT preserved. Both NELEM and SIZE
|
---|
92 | can be zero. Return true on success, false on allocation failure
|
---|
93 | (in which case the old buffer is freed, but *BUFFER remains in a
|
---|
94 | free-able state, and errno is set). It is unspecified whether this
|
---|
95 | function can reduce the array size. */
|
---|
96 | #if 0
|
---|
97 | extern bool scratch_buffer_set_array_size (struct scratch_buffer *buffer,
|
---|
98 | size_t nelem, size_t size);
|
---|
99 | #endif
|
---|
100 |
|
---|
101 |
|
---|
102 | /* The implementation is imported from glibc. */
|
---|
103 |
|
---|
104 | /* Avoid possible conflicts with symbols exported by the GNU libc. */
|
---|
105 | #define __libc_scratch_buffer_grow gl_scratch_buffer_grow
|
---|
106 | #define __libc_scratch_buffer_grow_preserve gl_scratch_buffer_grow_preserve
|
---|
107 | #define __libc_scratch_buffer_set_array_size gl_scratch_buffer_set_array_size
|
---|
108 |
|
---|
109 | #ifndef _GL_LIKELY
|
---|
110 | /* Rely on __builtin_expect, as provided by the module 'builtin-expect'. */
|
---|
111 | # define _GL_LIKELY(cond) __builtin_expect ((cond), 1)
|
---|
112 | # define _GL_UNLIKELY(cond) __builtin_expect ((cond), 0)
|
---|
113 | #endif
|
---|
114 |
|
---|
115 | #include <malloc/scratch_buffer.gl.h>
|
---|
116 |
|
---|
117 | #endif /* _GL_SCRATCH_BUFFER_H */
|
---|