(root)/
tar-1.35/
gnu/
malloc/
scratch_buffer.h
       1  /* Variable-sized buffer with on-stack default allocation.
       2     Copyright (C) 2015-2023 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)
      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)
      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)
      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)
     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)
     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  #endif /* _SCRATCH_BUFFER_H */