1 /* Variable-sized buffer with on-stack default allocation. 2 Copyright (C) 2017-2021 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 /* Return a copy of *BUFFER's first SIZE bytes as a heap-allocated block, 102 deallocating *BUFFER if it was heap-allocated. SIZE must be at 103 most *BUFFER's size. Return NULL (setting errno) on memory 104 exhaustion. */ 105 #if 0 106 extern void *scratch_buffer_dupfree (struct scratch_buffer *buffer, 107 size_t size); 108 #endif 109 110 111 /* The implementation is imported from glibc. */ 112 113 /* Avoid possible conflicts with symbols exported by the GNU libc. */ 114 #define __libc_scratch_buffer_dupfree gl_scratch_buffer_dupfree 115 #define __libc_scratch_buffer_grow gl_scratch_buffer_grow 116 #define __libc_scratch_buffer_grow_preserve gl_scratch_buffer_grow_preserve 117 #define __libc_scratch_buffer_set_array_size gl_scratch_buffer_set_array_size 118 119 #ifndef _GL_LIKELY 120 /* Rely on __builtin_expect, as provided by the module 'builtin-expect'. */ 121 # define _GL_LIKELY(cond) __builtin_expect ((cond), 1) 122 # define _GL_UNLIKELY(cond) __builtin_expect ((cond), 0) 123 #endif 124 125 #include <malloc/scratch_buffer.gl.h> 126 127 #endif /* _GL_SCRATCH_BUFFER_H */