root/maint/gnulib/lib/malloc/scratch_buffer.h

/* [previous][next][first][last][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. scratch_buffer_init
  2. scratch_buffer_free
  3. libc_hidden_proto
  4. libc_hidden_proto
  5. libc_hidden_proto
  6. libc_hidden_proto

   1 /* Variable-sized buffer with on-stack default allocation.
   2    Copyright (C) 2015-2021 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.  */
  66 struct 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.  */
  74 static inline void
  75 scratch_buffer_init (struct scratch_buffer *buffer)
     /* [previous][next][first][last][top][bottom][index][help] */
  76 {
  77   buffer->data = buffer->__space.__c;
  78   buffer->length = sizeof (buffer->__space);
  79 }
  80 
  81 /* Deallocates *BUFFER (if it was heap-allocated).  */
  82 static inline void
  83 scratch_buffer_free (struct scratch_buffer *buffer)
     /* [previous][next][first][last][top][bottom][index][help] */
  84 {
  85   if (buffer->data != buffer->__space.__c)
  86     free (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.  */
  94 bool __libc_scratch_buffer_grow (struct scratch_buffer *buffer);
  95 libc_hidden_proto (__libc_scratch_buffer_grow)
     /* [previous][next][first][last][top][bottom][index][help] */
  96 
  97 /* Alias for __libc_scratch_buffer_grow.  */
  98 static __always_inline bool
  99 scratch_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.  */
 106 bool __libc_scratch_buffer_grow_preserve (struct scratch_buffer *buffer);
 107 libc_hidden_proto (__libc_scratch_buffer_grow_preserve)
     /* [previous][next][first][last][top][bottom][index][help] */
 108 
 109 /* Alias for __libc_scratch_buffer_grow_preserve.  */
 110 static __always_inline bool
 111 scratch_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.  */
 122 bool __libc_scratch_buffer_set_array_size (struct scratch_buffer *buffer,
 123                                            size_t nelem, size_t size);
 124 libc_hidden_proto (__libc_scratch_buffer_set_array_size)
     /* [previous][next][first][last][top][bottom][index][help] */
 125 
 126 /* Alias for __libc_scratch_set_array_size.  */
 127 static __always_inline bool
 128 scratch_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.  */
 139 void *__libc_scratch_buffer_dupfree (struct scratch_buffer *buffer,
 140                                      size_t size);
 141 libc_hidden_proto (__libc_scratch_buffer_dupfree)
     /* [previous][next][first][last][top][bottom][index][help] */
 142 
 143 /* Alias for __libc_scratch_dupfree.  */
 144 static __always_inline void *
 145 scratch_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 */

/* [previous][next][first][last][top][bottom][index][help] */