2015-04-07 17:03:43 +08:00
|
|
|
/* Variable-sized buffer with on-stack default allocation.
|
2020-01-01 08:14:33 +08:00
|
|
|
Copyright (C) 2015-2020 Free Software Foundation, Inc.
|
2015-04-07 17:03:43 +08:00
|
|
|
This file is part of the GNU C Library.
|
|
|
|
|
|
|
|
The GNU C Library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
The GNU C Library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
|
|
License along with the GNU C Library; if not, see
|
Prefer https to http for gnu.org and fsf.org URLs
Also, change sources.redhat.com to sourceware.org.
This patch was automatically generated by running the following shell
script, which uses GNU sed, and which avoids modifying files imported
from upstream:
sed -ri '
s,(http|ftp)(://(.*\.)?(gnu|fsf|sourceware)\.org($|[^.]|\.[^a-z])),https\2,g
s,(http|ftp)(://(.*\.)?)sources\.redhat\.com($|[^.]|\.[^a-z]),https\2sourceware.org\4,g
' \
$(find $(git ls-files) -prune -type f \
! -name '*.po' \
! -name 'ChangeLog*' \
! -path COPYING ! -path COPYING.LIB \
! -path manual/fdl-1.3.texi ! -path manual/lgpl-2.1.texi \
! -path manual/texinfo.tex ! -path scripts/config.guess \
! -path scripts/config.sub ! -path scripts/install-sh \
! -path scripts/mkinstalldirs ! -path scripts/move-if-change \
! -path INSTALL ! -path locale/programs/charmap-kw.h \
! -path po/libc.pot ! -path sysdeps/gnu/errlist.c \
! '(' -name configure \
-execdir test -f configure.ac -o -f configure.in ';' ')' \
! '(' -name preconfigure \
-execdir test -f preconfigure.ac ';' ')' \
-print)
and then by running 'make dist-prepare' to regenerate files built
from the altered files, and then executing the following to cleanup:
chmod a+x sysdeps/unix/sysv/linux/riscv/configure
# Omit irrelevant whitespace and comment-only changes,
# perhaps from a slightly-different Autoconf version.
git checkout -f \
sysdeps/csky/configure \
sysdeps/hppa/configure \
sysdeps/riscv/configure \
sysdeps/unix/sysv/linux/csky/configure
# Omit changes that caused a pre-commit check to fail like this:
# remote: *** error: sysdeps/powerpc/powerpc64/ppc-mcount.S: trailing lines
git checkout -f \
sysdeps/powerpc/powerpc64/ppc-mcount.S \
sysdeps/unix/sysv/linux/s390/s390-64/syscall.S
# Omit change that caused a pre-commit check to fail like this:
# remote: *** error: sysdeps/sparc/sparc64/multiarch/memcpy-ultra3.S: last line does not end in newline
git checkout -f sysdeps/sparc/sparc64/multiarch/memcpy-ultra3.S
2019-09-07 13:40:42 +08:00
|
|
|
<https://www.gnu.org/licenses/>. */
|
2015-04-07 17:03:43 +08:00
|
|
|
|
|
|
|
#ifndef _SCRATCH_BUFFER_H
|
|
|
|
#define _SCRATCH_BUFFER_H
|
|
|
|
|
|
|
|
/* Scratch buffers with a default stack allocation and fallback to
|
|
|
|
heap allocation. It is expected that this function is used in this
|
|
|
|
way:
|
|
|
|
|
|
|
|
struct scratch_buffer tmpbuf;
|
|
|
|
scratch_buffer_init (&tmpbuf);
|
|
|
|
|
|
|
|
while (!function_that_uses_buffer (tmpbuf.data, tmpbuf.length))
|
|
|
|
if (!scratch_buffer_grow (&tmpbuf))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
scratch_buffer_free (&tmpbuf);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
The allocation functions (scratch_buffer_grow,
|
|
|
|
scratch_buffer_grow_preserve, scratch_buffer_set_array_size) make
|
|
|
|
sure that the heap allocation, if any, is freed, so that the code
|
|
|
|
above does not have a memory leak. The buffer still remains in a
|
|
|
|
state that can be deallocated using scratch_buffer_free, so a loop
|
|
|
|
like this is valid as well:
|
|
|
|
|
|
|
|
struct scratch_buffer tmpbuf;
|
|
|
|
scratch_buffer_init (&tmpbuf);
|
|
|
|
|
|
|
|
while (!function_that_uses_buffer (tmpbuf.data, tmpbuf.length))
|
|
|
|
if (!scratch_buffer_grow (&tmpbuf))
|
|
|
|
break;
|
|
|
|
|
|
|
|
scratch_buffer_free (&tmpbuf);
|
|
|
|
|
|
|
|
scratch_buffer_grow and scratch_buffer_grow_preserve are guaranteed
|
|
|
|
to grow the buffer by at least 512 bytes. This means that when
|
|
|
|
using the scratch buffer as a backing store for a non-character
|
|
|
|
array whose element size, in bytes, is 512 or smaller, the scratch
|
|
|
|
buffer only has to grow once to make room for at least one more
|
|
|
|
element.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdbool.h>
|
2015-10-29 20:46:22 +08:00
|
|
|
#include <stddef.h>
|
2015-04-07 17:03:43 +08:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
/* Scratch buffer. Must be initialized with scratch_buffer_init
|
|
|
|
before its use. */
|
|
|
|
struct scratch_buffer {
|
|
|
|
void *data; /* Pointer to the beginning of the scratch area. */
|
|
|
|
size_t length; /* Allocated space at the data pointer, in bytes. */
|
2017-09-18 20:26:00 +08:00
|
|
|
union { max_align_t __align; char __c[1024]; } __space;
|
2015-04-07 17:03:43 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Initializes *BUFFER so that BUFFER->data points to BUFFER->__space
|
|
|
|
and BUFFER->length reflects the available space. */
|
|
|
|
static inline void
|
|
|
|
scratch_buffer_init (struct scratch_buffer *buffer)
|
|
|
|
{
|
2017-09-18 20:26:00 +08:00
|
|
|
buffer->data = buffer->__space.__c;
|
2015-04-07 17:03:43 +08:00
|
|
|
buffer->length = sizeof (buffer->__space);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Deallocates *BUFFER (if it was heap-allocated). */
|
|
|
|
static inline void
|
|
|
|
scratch_buffer_free (struct scratch_buffer *buffer)
|
|
|
|
{
|
2017-09-18 20:26:00 +08:00
|
|
|
if (buffer->data != buffer->__space.__c)
|
2015-04-07 17:03:43 +08:00
|
|
|
free (buffer->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Grow *BUFFER by some arbitrary amount. The buffer contents is NOT
|
|
|
|
preserved. Return true on success, false on allocation failure (in
|
|
|
|
which case the old buffer is freed). On success, the new buffer is
|
|
|
|
larger than the previous size. On failure, *BUFFER is deallocated,
|
|
|
|
but remains in a free-able state, and errno is set. */
|
|
|
|
bool __libc_scratch_buffer_grow (struct scratch_buffer *buffer);
|
|
|
|
libc_hidden_proto (__libc_scratch_buffer_grow)
|
|
|
|
|
|
|
|
/* Alias for __libc_scratch_buffer_grow. */
|
|
|
|
static __always_inline bool
|
|
|
|
scratch_buffer_grow (struct scratch_buffer *buffer)
|
|
|
|
{
|
|
|
|
return __glibc_likely (__libc_scratch_buffer_grow (buffer));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Like __libc_scratch_buffer_grow, but preserve the old buffer
|
|
|
|
contents on success, as a prefix of the new buffer. */
|
|
|
|
bool __libc_scratch_buffer_grow_preserve (struct scratch_buffer *buffer);
|
|
|
|
libc_hidden_proto (__libc_scratch_buffer_grow_preserve)
|
|
|
|
|
|
|
|
/* Alias for __libc_scratch_buffer_grow_preserve. */
|
|
|
|
static __always_inline bool
|
|
|
|
scratch_buffer_grow_preserve (struct scratch_buffer *buffer)
|
|
|
|
{
|
|
|
|
return __glibc_likely (__libc_scratch_buffer_grow_preserve (buffer));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Grow *BUFFER so that it can store at least NELEM elements of SIZE
|
|
|
|
bytes. The buffer contents are NOT preserved. Both NELEM and SIZE
|
|
|
|
can be zero. Return true on success, false on allocation failure
|
|
|
|
(in which case the old buffer is freed, but *BUFFER remains in a
|
|
|
|
free-able state, and errno is set). It is unspecified whether this
|
|
|
|
function can reduce the array size. */
|
|
|
|
bool __libc_scratch_buffer_set_array_size (struct scratch_buffer *buffer,
|
|
|
|
size_t nelem, size_t size);
|
|
|
|
libc_hidden_proto (__libc_scratch_buffer_set_array_size)
|
|
|
|
|
|
|
|
/* Alias for __libc_scratch_set_array_size. */
|
|
|
|
static __always_inline bool
|
|
|
|
scratch_buffer_set_array_size (struct scratch_buffer *buffer,
|
|
|
|
size_t nelem, size_t size)
|
|
|
|
{
|
|
|
|
return __glibc_likely (__libc_scratch_buffer_set_array_size
|
|
|
|
(buffer, nelem, size));
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* _SCRATCH_BUFFER_H */
|