Blame lib/malloc/scratch_buffer.h

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