Blame include/scratch_buffer.h

Packit Service 82fcde
/* Variable-sized buffer with on-stack default allocation.
Packit Service 82fcde
   Copyright (C) 2015-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#ifndef _SCRATCH_BUFFER_H
Packit Service 82fcde
#define _SCRATCH_BUFFER_H
Packit Service 82fcde
Packit Service 82fcde
/* Scratch buffers with a default stack allocation and fallback to
Packit Service 82fcde
   heap allocation.  It is expected that this function is used in this
Packit Service 82fcde
   way:
Packit Service 82fcde
Packit Service 82fcde
     struct scratch_buffer tmpbuf;
Packit Service 82fcde
     scratch_buffer_init (&tmpbuf);
Packit Service 82fcde
Packit Service 82fcde
     while (!function_that_uses_buffer (tmpbuf.data, tmpbuf.length))
Packit Service 82fcde
       if (!scratch_buffer_grow (&tmpbuf))
Packit Service 82fcde
	 return -1;
Packit Service 82fcde
Packit Service 82fcde
     scratch_buffer_free (&tmpbuf);
Packit Service 82fcde
     return 0;
Packit Service 82fcde
Packit Service 82fcde
   The allocation functions (scratch_buffer_grow,
Packit Service 82fcde
   scratch_buffer_grow_preserve, scratch_buffer_set_array_size) make
Packit Service 82fcde
   sure that the heap allocation, if any, is freed, so that the code
Packit Service 82fcde
   above does not have a memory leak.  The buffer still remains in a
Packit Service 82fcde
   state that can be deallocated using scratch_buffer_free, so a loop
Packit Service 82fcde
   like this is valid as well:
Packit Service 82fcde
Packit Service 82fcde
     struct scratch_buffer tmpbuf;
Packit Service 82fcde
     scratch_buffer_init (&tmpbuf);
Packit Service 82fcde
Packit Service 82fcde
     while (!function_that_uses_buffer (tmpbuf.data, tmpbuf.length))
Packit Service 82fcde
       if (!scratch_buffer_grow (&tmpbuf))
Packit Service 82fcde
	 break;
Packit Service 82fcde
Packit Service 82fcde
     scratch_buffer_free (&tmpbuf);
Packit Service 82fcde
Packit Service 82fcde
   scratch_buffer_grow and scratch_buffer_grow_preserve are guaranteed
Packit Service 82fcde
   to grow the buffer by at least 512 bytes.  This means that when
Packit Service 82fcde
   using the scratch buffer as a backing store for a non-character
Packit Service 82fcde
   array whose element size, in bytes, is 512 or smaller, the scratch
Packit Service 82fcde
   buffer only has to grow once to make room for at least one more
Packit Service 82fcde
   element.
Packit Service 82fcde
*/
Packit Service 82fcde
Packit Service 82fcde
#include <stdbool.h>
Packit Service 82fcde
#include <stddef.h>
Packit Service 82fcde
#include <stdlib.h>
Packit Service 82fcde
Packit Service 82fcde
/* Scratch buffer.  Must be initialized with scratch_buffer_init
Packit Service 82fcde
   before its use.  */
Packit Service 82fcde
struct scratch_buffer {
Packit Service 82fcde
  void *data;    /* Pointer to the beginning of the scratch area.  */
Packit Service 82fcde
  size_t length; /* Allocated space at the data pointer, in bytes.  */
Packit Service 82fcde
  union { max_align_t __align; char __c[1024]; } __space;
Packit Service 82fcde
};
Packit Service 82fcde
Packit Service 82fcde
/* Initializes *BUFFER so that BUFFER->data points to BUFFER->__space
Packit Service 82fcde
   and BUFFER->length reflects the available space.  */
Packit Service 82fcde
static inline void
Packit Service 82fcde
scratch_buffer_init (struct scratch_buffer *buffer)
Packit Service 82fcde
{
Packit Service 82fcde
  buffer->data = buffer->__space.__c;
Packit Service 82fcde
  buffer->length = sizeof (buffer->__space);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Deallocates *BUFFER (if it was heap-allocated).  */
Packit Service 82fcde
static inline void
Packit Service 82fcde
scratch_buffer_free (struct scratch_buffer *buffer)
Packit Service 82fcde
{
Packit Service 82fcde
  if (buffer->data != buffer->__space.__c)
Packit Service 82fcde
    free (buffer->data);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Grow *BUFFER by some arbitrary amount.  The buffer contents is NOT
Packit Service 82fcde
   preserved.  Return true on success, false on allocation failure (in
Packit Service 82fcde
   which case the old buffer is freed).  On success, the new buffer is
Packit Service 82fcde
   larger than the previous size.  On failure, *BUFFER is deallocated,
Packit Service 82fcde
   but remains in a free-able state, and errno is set.  */
Packit Service 82fcde
bool __libc_scratch_buffer_grow (struct scratch_buffer *buffer);
Packit Service 82fcde
libc_hidden_proto (__libc_scratch_buffer_grow)
Packit Service 82fcde
Packit Service 82fcde
/* Alias for __libc_scratch_buffer_grow.  */
Packit Service 82fcde
static __always_inline bool
Packit Service 82fcde
scratch_buffer_grow (struct scratch_buffer *buffer)
Packit Service 82fcde
{
Packit Service 82fcde
  return __glibc_likely (__libc_scratch_buffer_grow (buffer));
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Like __libc_scratch_buffer_grow, but preserve the old buffer
Packit Service 82fcde
   contents on success, as a prefix of the new buffer.  */
Packit Service 82fcde
bool __libc_scratch_buffer_grow_preserve (struct scratch_buffer *buffer);
Packit Service 82fcde
libc_hidden_proto (__libc_scratch_buffer_grow_preserve)
Packit Service 82fcde
Packit Service 82fcde
/* Alias for __libc_scratch_buffer_grow_preserve.  */
Packit Service 82fcde
static __always_inline bool
Packit Service 82fcde
scratch_buffer_grow_preserve (struct scratch_buffer *buffer)
Packit Service 82fcde
{
Packit Service 82fcde
  return __glibc_likely (__libc_scratch_buffer_grow_preserve (buffer));
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Grow *BUFFER so that it can store at least NELEM elements of SIZE
Packit Service 82fcde
   bytes.  The buffer contents are NOT preserved.  Both NELEM and SIZE
Packit Service 82fcde
   can be zero.  Return true on success, false on allocation failure
Packit Service 82fcde
   (in which case the old buffer is freed, but *BUFFER remains in a
Packit Service 82fcde
   free-able state, and errno is set).  It is unspecified whether this
Packit Service 82fcde
   function can reduce the array size.  */
Packit Service 82fcde
bool __libc_scratch_buffer_set_array_size (struct scratch_buffer *buffer,
Packit Service 82fcde
					   size_t nelem, size_t size);
Packit Service 82fcde
libc_hidden_proto (__libc_scratch_buffer_set_array_size)
Packit Service 82fcde
Packit Service 82fcde
/* Alias for __libc_scratch_set_array_size.  */
Packit Service 82fcde
static __always_inline bool
Packit Service 82fcde
scratch_buffer_set_array_size (struct scratch_buffer *buffer,
Packit Service 82fcde
			       size_t nelem, size_t size)
Packit Service 82fcde
{
Packit Service 82fcde
  return __glibc_likely (__libc_scratch_buffer_set_array_size
Packit Service 82fcde
			 (buffer, nelem, size));
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
#endif /* _SCRATCH_BUFFER_H */