Blame malloc/dynarray-skeleton.c

Packit Service 82fcde
/* Type-safe arrays which grow dynamically.
Packit Service 82fcde
   Copyright (C) 2017-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
/* Pre-processor macros which act as parameters:
Packit Service 82fcde
Packit Service 82fcde
   DYNARRAY_STRUCT
Packit Service 82fcde
      The struct tag of dynamic array to be defined.
Packit Service 82fcde
   DYNARRAY_ELEMENT
Packit Service 82fcde
      The type name of the element type.  Elements are copied
Packit Service 82fcde
      as if by memcpy, and can change address as the dynamic
Packit Service 82fcde
      array grows.
Packit Service 82fcde
   DYNARRAY_PREFIX
Packit Service 82fcde
      The prefix of the functions which are defined.
Packit Service 82fcde
Packit Service 82fcde
   The following parameters are optional:
Packit Service 82fcde
Packit Service 82fcde
   DYNARRAY_ELEMENT_FREE
Packit Service 82fcde
      DYNARRAY_ELEMENT_FREE (E) is evaluated to deallocate the
Packit Service 82fcde
      contents of elements. E is of type  DYNARRAY_ELEMENT *.
Packit Service 82fcde
   DYNARRAY_ELEMENT_INIT
Packit Service 82fcde
      DYNARRAY_ELEMENT_INIT (E) is evaluated to initialize a new
Packit Service 82fcde
      element.  E is of type  DYNARRAY_ELEMENT *.
Packit Service 82fcde
      If DYNARRAY_ELEMENT_FREE but not DYNARRAY_ELEMENT_INIT is
Packit Service 82fcde
      defined, new elements are automatically zero-initialized.
Packit Service 82fcde
      Otherwise, new elements have undefined contents.
Packit Service 82fcde
   DYNARRAY_INITIAL_SIZE
Packit Service 82fcde
      The size of the statically allocated array (default:
Packit Service 82fcde
      at least 2, more elements if they fit into 128 bytes).
Packit Service 82fcde
      Must be a preprocessor constant.  If DYNARRAY_INITIAL_SIZE is 0,
Packit Service 82fcde
      there is no statically allocated array at, and all non-empty
Packit Service 82fcde
      arrays are heap-allocated.
Packit Service 82fcde
   DYNARRAY_FINAL_TYPE
Packit Service 82fcde
      The name of the type which holds the final array.  If not
Packit Service 82fcde
      defined, is PREFIX##finalize not provided.  DYNARRAY_FINAL_TYPE
Packit Service 82fcde
      must be a struct type, with members of type DYNARRAY_ELEMENT and
Packit Service 82fcde
      size_t at the start (in this order).
Packit Service 82fcde
Packit Service 82fcde
   These macros are undefined after this header file has been
Packit Service 82fcde
   included.
Packit Service 82fcde
Packit Service 82fcde
   The following types are provided (their members are private to the
Packit Service 82fcde
   dynarray implementation):
Packit Service 82fcde
Packit Service 82fcde
     struct DYNARRAY_STRUCT
Packit Service 82fcde
Packit Service 82fcde
   The following functions are provided:
Packit Service 82fcde
Packit Service 82fcde
     void DYNARRAY_PREFIX##init (struct DYNARRAY_STRUCT *);
Packit Service 82fcde
     void DYNARRAY_PREFIX##free (struct DYNARRAY_STRUCT *);
Packit Service 82fcde
     bool DYNARRAY_PREFIX##has_failed (const struct DYNARRAY_STRUCT *);
Packit Service 82fcde
     void DYNARRAY_PREFIX##mark_failed (struct DYNARRAY_STRUCT *);
Packit Service 82fcde
     size_t DYNARRAY_PREFIX##size (const struct DYNARRAY_STRUCT *);
Packit Service 82fcde
     DYNARRAY_ELEMENT *DYNARRAY_PREFIX##begin (const struct DYNARRAY_STRUCT *);
Packit Service 82fcde
     DYNARRAY_ELEMENT *DYNARRAY_PREFIX##end (const struct DYNARRAY_STRUCT *);
Packit Service 82fcde
     DYNARRAY_ELEMENT *DYNARRAY_PREFIX##at (struct DYNARRAY_STRUCT *, size_t);
Packit Service 82fcde
     void DYNARRAY_PREFIX##add (struct DYNARRAY_STRUCT *, DYNARRAY_ELEMENT);
Packit Service 82fcde
     DYNARRAY_ELEMENT *DYNARRAY_PREFIX##emplace (struct DYNARRAY_STRUCT *);
Packit Service 82fcde
     bool DYNARRAY_PREFIX##resize (struct DYNARRAY_STRUCT *, size_t);
Packit Service 82fcde
     void DYNARRAY_PREFIX##remove_last (struct DYNARRAY_STRUCT *);
Packit Service 82fcde
     void DYNARRAY_PREFIX##clear (struct DYNARRAY_STRUCT *);
Packit Service 82fcde
Packit Service 82fcde
   The following functions are provided are provided if the
Packit Service 82fcde
   prerequisites are met:
Packit Service 82fcde
Packit Service 82fcde
     bool DYNARRAY_PREFIX##finalize (struct DYNARRAY_STRUCT *,
Packit Service 82fcde
                                     DYNARRAY_FINAL_TYPE *);
Packit Service 82fcde
       (if DYNARRAY_FINAL_TYPE is defined)
Packit Service 82fcde
     DYNARRAY_ELEMENT *DYNARRAY_PREFIX##finalize (struct DYNARRAY_STRUCT *,
Packit Service 82fcde
                                                  size_t *);
Packit Service 82fcde
       (if DYNARRAY_FINAL_TYPE is not defined)
Packit Service 82fcde
*/
Packit Service 82fcde
Packit Service 82fcde
#include <malloc/dynarray.h>
Packit Service 82fcde
Packit Service 82fcde
#include <errno.h>
Packit Service 82fcde
#include <stdlib.h>
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
Packit Service 82fcde
#ifndef DYNARRAY_STRUCT
Packit Service 82fcde
# error "DYNARRAY_STRUCT must be defined"
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#ifndef DYNARRAY_ELEMENT
Packit Service 82fcde
# error "DYNARRAY_ELEMENT must be defined"
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#ifndef DYNARRAY_PREFIX
Packit Service 82fcde
# error "DYNARRAY_PREFIX must be defined"
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#ifdef DYNARRAY_INITIAL_SIZE
Packit Service 82fcde
# if DYNARRAY_INITIAL_SIZE < 0
Packit Service 82fcde
#  error "DYNARRAY_INITIAL_SIZE must be non-negative"
Packit Service 82fcde
# endif
Packit Service 82fcde
# if DYNARRAY_INITIAL_SIZE > 0
Packit Service 82fcde
#  define DYNARRAY_HAVE_SCRATCH 1
Packit Service 82fcde
# else
Packit Service 82fcde
#  define DYNARRAY_HAVE_SCRATCH 0
Packit Service 82fcde
# endif
Packit Service 82fcde
#else
Packit Service 82fcde
/* Provide a reasonable default which limits the size of
Packit Service 82fcde
   DYNARRAY_STRUCT.  */
Packit Service 82fcde
# define DYNARRAY_INITIAL_SIZE \
Packit Service 82fcde
  (sizeof (DYNARRAY_ELEMENT) > 64 ? 2 : 128 / sizeof (DYNARRAY_ELEMENT))
Packit Service 82fcde
# define DYNARRAY_HAVE_SCRATCH 1
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* Public type definitions.  */
Packit Service 82fcde
Packit Service 82fcde
/* All fields of this struct are private to the implementation.  */
Packit Service 82fcde
struct DYNARRAY_STRUCT
Packit Service 82fcde
{
Packit Service 82fcde
  union
Packit Service 82fcde
  {
Packit Service 82fcde
    struct dynarray_header dynarray_abstract;
Packit Service 82fcde
    struct
Packit Service 82fcde
    {
Packit Service 82fcde
      /* These fields must match struct dynarray_header.  */
Packit Service 82fcde
      size_t used;
Packit Service 82fcde
      size_t allocated;
Packit Service 82fcde
      DYNARRAY_ELEMENT *array;
Packit Service 82fcde
    } dynarray_header;
Packit Service 82fcde
  };
Packit Service 82fcde
Packit Service 82fcde
#if DYNARRAY_HAVE_SCRATCH
Packit Service 82fcde
  /* Initial inline allocation.  */
Packit Service 82fcde
  DYNARRAY_ELEMENT scratch[DYNARRAY_INITIAL_SIZE];
Packit Service 82fcde
#endif
Packit Service 82fcde
};
Packit Service 82fcde
Packit Service 82fcde
/* Internal use only: Helper macros.  */
Packit Service 82fcde
Packit Service 82fcde
/* Ensure macro-expansion of DYNARRAY_PREFIX.  */
Packit Service 82fcde
#define DYNARRAY_CONCAT0(prefix, name) prefix##name
Packit Service 82fcde
#define DYNARRAY_CONCAT1(prefix, name) DYNARRAY_CONCAT0(prefix, name)
Packit Service 82fcde
#define DYNARRAY_NAME(name) DYNARRAY_CONCAT1(DYNARRAY_PREFIX, name)
Packit Service 82fcde
Packit Service 82fcde
/* Address of the scratch buffer if any.  */
Packit Service 82fcde
#if DYNARRAY_HAVE_SCRATCH
Packit Service 82fcde
# define DYNARRAY_SCRATCH(list) (list)->scratch
Packit Service 82fcde
#else
Packit Service 82fcde
# define DYNARRAY_SCRATCH(list) NULL
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* Internal use only: Helper functions.  */
Packit Service 82fcde
Packit Service 82fcde
/* Internal function.  Call DYNARRAY_ELEMENT_FREE with the array
Packit Service 82fcde
   elements.  Name mangling needed due to the DYNARRAY_ELEMENT_FREE
Packit Service 82fcde
   macro expansion.  */
Packit Service 82fcde
static inline void
Packit Service 82fcde
DYNARRAY_NAME (free__elements__) (DYNARRAY_ELEMENT *__dynarray_array,
Packit Service 82fcde
                                  size_t __dynarray_used)
Packit Service 82fcde
{
Packit Service 82fcde
#ifdef DYNARRAY_ELEMENT_FREE
Packit Service 82fcde
  for (size_t __dynarray_i = 0; __dynarray_i < __dynarray_used; ++__dynarray_i)
Packit Service 82fcde
    DYNARRAY_ELEMENT_FREE (&__dynarray_array[__dynarray_i]);
Packit Service 82fcde
#endif /* DYNARRAY_ELEMENT_FREE */
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Internal function.  Free the non-scratch array allocation.  */
Packit Service 82fcde
static inline void
Packit Service 82fcde
DYNARRAY_NAME (free__array__) (struct DYNARRAY_STRUCT *list)
Packit Service 82fcde
{
Packit Service 82fcde
#if DYNARRAY_HAVE_SCRATCH
Packit Service 82fcde
  if (list->dynarray_header.array != list->scratch)
Packit Service 82fcde
    free (list->dynarray_header.array);
Packit Service 82fcde
#else
Packit Service 82fcde
  free (list->dynarray_header.array);
Packit Service 82fcde
#endif
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Public functions.  */
Packit Service 82fcde
Packit Service 82fcde
/* Initialize a dynamic array object.  This must be called before any
Packit Service 82fcde
   use of the object.  */
Packit Service 82fcde
__attribute__ ((nonnull (1)))
Packit Service 82fcde
static void
Packit Service 82fcde
DYNARRAY_NAME (init) (struct DYNARRAY_STRUCT *list)
Packit Service 82fcde
{
Packit Service 82fcde
  list->dynarray_header.used = 0;
Packit Service 82fcde
  list->dynarray_header.allocated = DYNARRAY_INITIAL_SIZE;
Packit Service 82fcde
  list->dynarray_header.array = DYNARRAY_SCRATCH (list);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Deallocate the dynamic array and its elements.  */
Packit Service 82fcde
__attribute__ ((unused, nonnull (1)))
Packit Service 82fcde
static void
Packit Service 82fcde
DYNARRAY_NAME (free) (struct DYNARRAY_STRUCT *list)
Packit Service 82fcde
{
Packit Service 82fcde
  DYNARRAY_NAME (free__elements__)
Packit Service 82fcde
    (list->dynarray_header.array, list->dynarray_header.used);
Packit Service 82fcde
  DYNARRAY_NAME (free__array__) (list);
Packit Service 82fcde
  DYNARRAY_NAME (init) (list);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Return true if the dynamic array is in an error state.  */
Packit Service 82fcde
__attribute__ ((nonnull (1)))
Packit Service 82fcde
static inline bool
Packit Service 82fcde
DYNARRAY_NAME (has_failed) (const struct DYNARRAY_STRUCT *list)
Packit Service 82fcde
{
Packit Service 82fcde
  return list->dynarray_header.allocated == __dynarray_error_marker ();
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Mark the dynamic array as failed.  All elements are deallocated as
Packit Service 82fcde
   a side effect.  */
Packit Service 82fcde
__attribute__ ((nonnull (1)))
Packit Service 82fcde
static void
Packit Service 82fcde
DYNARRAY_NAME (mark_failed) (struct DYNARRAY_STRUCT *list)
Packit Service 82fcde
{
Packit Service 82fcde
  DYNARRAY_NAME (free__elements__)
Packit Service 82fcde
    (list->dynarray_header.array, list->dynarray_header.used);
Packit Service 82fcde
  DYNARRAY_NAME (free__array__) (list);
Packit Service 82fcde
  list->dynarray_header.array = DYNARRAY_SCRATCH (list);
Packit Service 82fcde
  list->dynarray_header.used = 0;
Packit Service 82fcde
  list->dynarray_header.allocated = __dynarray_error_marker ();
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Return the number of elements which have been added to the dynamic
Packit Service 82fcde
   array.  */
Packit Service 82fcde
__attribute__ ((nonnull (1)))
Packit Service 82fcde
static inline size_t
Packit Service 82fcde
DYNARRAY_NAME (size) (const struct DYNARRAY_STRUCT *list)
Packit Service 82fcde
{
Packit Service 82fcde
  return list->dynarray_header.used;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Return a pointer to the array element at INDEX.  Terminate the
Packit Service 82fcde
   process if INDEX is out of bounds.  */
Packit Service 82fcde
__attribute__ ((nonnull (1)))
Packit Service 82fcde
static inline DYNARRAY_ELEMENT *
Packit Service 82fcde
DYNARRAY_NAME (at) (struct DYNARRAY_STRUCT *list, size_t index)
Packit Service 82fcde
{
Packit Service 82fcde
  if (__glibc_unlikely (index >= DYNARRAY_NAME (size) (list)))
Packit Service 82fcde
    __libc_dynarray_at_failure (DYNARRAY_NAME (size) (list), index);
Packit Service 82fcde
  return list->dynarray_header.array + index;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Return a pointer to the first array element, if any.  For a
Packit Service 82fcde
   zero-length array, the pointer can be NULL even though the dynamic
Packit Service 82fcde
   array has not entered the failure state.  */
Packit Service 82fcde
__attribute__ ((nonnull (1)))
Packit Service 82fcde
static inline DYNARRAY_ELEMENT *
Packit Service 82fcde
DYNARRAY_NAME (begin) (struct DYNARRAY_STRUCT *list)
Packit Service 82fcde
{
Packit Service 82fcde
  return list->dynarray_header.array;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Return a pointer one element past the last array element.  For a
Packit Service 82fcde
   zero-length array, the pointer can be NULL even though the dynamic
Packit Service 82fcde
   array has not entered the failure state.  */
Packit Service 82fcde
__attribute__ ((nonnull (1)))
Packit Service 82fcde
static inline DYNARRAY_ELEMENT *
Packit Service 82fcde
DYNARRAY_NAME (end) (struct DYNARRAY_STRUCT *list)
Packit Service 82fcde
{
Packit Service 82fcde
  return list->dynarray_header.array + list->dynarray_header.used;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Internal function.  Slow path for the add function below.  */
Packit Service 82fcde
static void
Packit Service 82fcde
DYNARRAY_NAME (add__) (struct DYNARRAY_STRUCT *list, DYNARRAY_ELEMENT item)
Packit Service 82fcde
{
Packit Service 82fcde
  if (__glibc_unlikely
Packit Service 82fcde
      (!__libc_dynarray_emplace_enlarge (&list->dynarray_abstract,
Packit Service 82fcde
                                         DYNARRAY_SCRATCH (list),
Packit Service 82fcde
                                         sizeof (DYNARRAY_ELEMENT))))
Packit Service 82fcde
    {
Packit Service 82fcde
      DYNARRAY_NAME (mark_failed) (list);
Packit Service 82fcde
      return;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Copy the new element and increase the array length.  */
Packit Service 82fcde
  list->dynarray_header.array[list->dynarray_header.used++] = item;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Add ITEM at the end of the array, enlarging it by one element.
Packit Service 82fcde
   Mark *LIST as failed if the dynamic array allocation size cannot be
Packit Service 82fcde
   increased.  */
Packit Service 82fcde
__attribute__ ((unused, nonnull (1)))
Packit Service 82fcde
static inline void
Packit Service 82fcde
DYNARRAY_NAME (add) (struct DYNARRAY_STRUCT *list, DYNARRAY_ELEMENT item)
Packit Service 82fcde
{
Packit Service 82fcde
  /* Do nothing in case of previous error.  */
Packit Service 82fcde
  if (DYNARRAY_NAME (has_failed) (list))
Packit Service 82fcde
    return;
Packit Service 82fcde
Packit Service 82fcde
  /* Enlarge the array if necessary.  */
Packit Service 82fcde
  if (__glibc_unlikely (list->dynarray_header.used
Packit Service 82fcde
                        == list->dynarray_header.allocated))
Packit Service 82fcde
    {
Packit Service 82fcde
      DYNARRAY_NAME (add__) (list, item);
Packit Service 82fcde
      return;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Copy the new element and increase the array length.  */
Packit Service 82fcde
  list->dynarray_header.array[list->dynarray_header.used++] = item;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Internal function.  Building block for the emplace functions below.
Packit Service 82fcde
   Assumes space for one more element in *LIST.  */
Packit Service 82fcde
static inline DYNARRAY_ELEMENT *
Packit Service 82fcde
DYNARRAY_NAME (emplace__tail__) (struct DYNARRAY_STRUCT *list)
Packit Service 82fcde
{
Packit Service 82fcde
  DYNARRAY_ELEMENT *result
Packit Service 82fcde
    = &list->dynarray_header.array[list->dynarray_header.used];
Packit Service 82fcde
  ++list->dynarray_header.used;
Packit Service 82fcde
#if defined (DYNARRAY_ELEMENT_INIT)
Packit Service 82fcde
  DYNARRAY_ELEMENT_INIT (result);
Packit Service 82fcde
#elif defined (DYNARRAY_ELEMENT_FREE)
Packit Service 82fcde
  memset (result, 0, sizeof (*result));
Packit Service 82fcde
#endif
Packit Service 82fcde
  return result;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Internal function.  Slow path for the emplace function below.  */
Packit Service 82fcde
static DYNARRAY_ELEMENT *
Packit Service 82fcde
DYNARRAY_NAME (emplace__) (struct DYNARRAY_STRUCT *list)
Packit Service 82fcde
{
Packit Service 82fcde
  if (__glibc_unlikely
Packit Service 82fcde
      (!__libc_dynarray_emplace_enlarge (&list->dynarray_abstract,
Packit Service 82fcde
                                         DYNARRAY_SCRATCH (list),
Packit Service 82fcde
                                         sizeof (DYNARRAY_ELEMENT))))
Packit Service 82fcde
    {
Packit Service 82fcde
      DYNARRAY_NAME (mark_failed) (list);
Packit Service 82fcde
      return NULL;
Packit Service 82fcde
    }
Packit Service 82fcde
  return DYNARRAY_NAME (emplace__tail__) (list);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Allocate a place for a new element in *LIST and return a pointer to
Packit Service 82fcde
   it.  The pointer can be NULL if the dynamic array cannot be
Packit Service 82fcde
   enlarged due to a memory allocation failure.  */
Packit Service 82fcde
__attribute__ ((unused, warn_unused_result, nonnull (1)))
Packit Service 82fcde
static
Packit Service 82fcde
/* Avoid inlining with the larger initialization code.  */
Packit Service 82fcde
#if !(defined (DYNARRAY_ELEMENT_INIT) || defined (DYNARRAY_ELEMENT_FREE))
Packit Service 82fcde
inline
Packit Service 82fcde
#endif
Packit Service 82fcde
DYNARRAY_ELEMENT *
Packit Service 82fcde
DYNARRAY_NAME (emplace) (struct DYNARRAY_STRUCT *list)
Packit Service 82fcde
{
Packit Service 82fcde
  /* Do nothing in case of previous error.  */
Packit Service 82fcde
  if (DYNARRAY_NAME (has_failed) (list))
Packit Service 82fcde
    return NULL;
Packit Service 82fcde
Packit Service 82fcde
  /* Enlarge the array if necessary.  */
Packit Service 82fcde
  if (__glibc_unlikely (list->dynarray_header.used
Packit Service 82fcde
                        == list->dynarray_header.allocated))
Packit Service 82fcde
    return (DYNARRAY_NAME (emplace__) (list));
Packit Service 82fcde
  return DYNARRAY_NAME (emplace__tail__) (list);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Change the size of *LIST to SIZE.  If SIZE is larger than the
Packit Service 82fcde
   existing size, new elements are added (which can be initialized).
Packit Service 82fcde
   Otherwise, the list is truncated, and elements are freed.  Return
Packit Service 82fcde
   false on memory allocation failure (and mark *LIST as failed).  */
Packit Service 82fcde
__attribute__ ((unused, nonnull (1)))
Packit Service 82fcde
static bool
Packit Service 82fcde
DYNARRAY_NAME (resize) (struct DYNARRAY_STRUCT *list, size_t size)
Packit Service 82fcde
{
Packit Service 82fcde
  if (size > list->dynarray_header.used)
Packit Service 82fcde
    {
Packit Service 82fcde
      bool ok;
Packit Service 82fcde
#if defined (DYNARRAY_ELEMENT_INIT)
Packit Service 82fcde
      /* The new elements have to be initialized.  */
Packit Service 82fcde
      size_t old_size = list->dynarray_header.used;
Packit Service 82fcde
      ok = __libc_dynarray_resize (&list->dynarray_abstract,
Packit Service 82fcde
                                   size, DYNARRAY_SCRATCH (list),
Packit Service 82fcde
                                   sizeof (DYNARRAY_ELEMENT));
Packit Service 82fcde
      if (ok)
Packit Service 82fcde
        for (size_t i = old_size; i < size; ++i)
Packit Service 82fcde
          {
Packit Service 82fcde
            DYNARRAY_ELEMENT_INIT (&list->dynarray_header.array[i]);
Packit Service 82fcde
          }
Packit Service 82fcde
#elif defined (DYNARRAY_ELEMENT_FREE)
Packit Service 82fcde
      /* Zero initialization is needed so that the elements can be
Packit Service 82fcde
         safely freed.  */
Packit Service 82fcde
      ok = __libc_dynarray_resize_clear
Packit Service 82fcde
        (&list->dynarray_abstract, size,
Packit Service 82fcde
         DYNARRAY_SCRATCH (list), sizeof (DYNARRAY_ELEMENT));
Packit Service 82fcde
#else
Packit Service 82fcde
      ok =  __libc_dynarray_resize (&list->dynarray_abstract,
Packit Service 82fcde
                                    size, DYNARRAY_SCRATCH (list),
Packit Service 82fcde
                                    sizeof (DYNARRAY_ELEMENT));
Packit Service 82fcde
#endif
Packit Service 82fcde
      if (__glibc_unlikely (!ok))
Packit Service 82fcde
        DYNARRAY_NAME (mark_failed) (list);
Packit Service 82fcde
      return ok;
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      /* The list has shrunk in size.  Free the removed elements.  */
Packit Service 82fcde
      DYNARRAY_NAME (free__elements__)
Packit Service 82fcde
        (list->dynarray_header.array + size,
Packit Service 82fcde
         list->dynarray_header.used - size);
Packit Service 82fcde
      list->dynarray_header.used = size;
Packit Service 82fcde
      return true;
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Remove the last element of LIST if it is present.  */
Packit Service 82fcde
__attribute__ ((unused, nonnull (1)))
Packit Service 82fcde
static void
Packit Service 82fcde
DYNARRAY_NAME (remove_last) (struct DYNARRAY_STRUCT *list)
Packit Service 82fcde
{
Packit Service 82fcde
  /* used > 0 implies that the array is the non-failed state.  */
Packit Service 82fcde
  if (list->dynarray_header.used > 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      size_t new_length = list->dynarray_header.used - 1;
Packit Service 82fcde
#ifdef DYNARRAY_ELEMENT_FREE
Packit Service 82fcde
      DYNARRAY_ELEMENT_FREE (&list->dynarray_header.array[new_length]);
Packit Service 82fcde
#endif
Packit Service 82fcde
      list->dynarray_header.used = new_length;
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Remove all elements from the list.  The elements are freed, but the
Packit Service 82fcde
   list itself is not.  */
Packit Service 82fcde
__attribute__ ((unused, nonnull (1)))
Packit Service 82fcde
static void
Packit Service 82fcde
DYNARRAY_NAME (clear) (struct DYNARRAY_STRUCT *list)
Packit Service 82fcde
{
Packit Service 82fcde
  /* free__elements__ does nothing if the list is in the failed
Packit Service 82fcde
     state.  */
Packit Service 82fcde
  DYNARRAY_NAME (free__elements__)
Packit Service 82fcde
    (list->dynarray_header.array, list->dynarray_header.used);
Packit Service 82fcde
  list->dynarray_header.used = 0;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
#ifdef DYNARRAY_FINAL_TYPE
Packit Service 82fcde
/* Transfer the dynamic array to a permanent location at *RESULT.
Packit Service 82fcde
   Returns true on success on false on allocation failure.  In either
Packit Service 82fcde
   case, *LIST is re-initialized and can be reused.  A NULL pointer is
Packit Service 82fcde
   stored in *RESULT if LIST refers to an empty list.  On success, the
Packit Service 82fcde
   pointer in *RESULT is heap-allocated and must be deallocated using
Packit Service 82fcde
   free.  */
Packit Service 82fcde
__attribute__ ((unused, warn_unused_result, nonnull (1, 2)))
Packit Service 82fcde
static bool
Packit Service 82fcde
DYNARRAY_NAME (finalize) (struct DYNARRAY_STRUCT *list,
Packit Service 82fcde
                          DYNARRAY_FINAL_TYPE *result)
Packit Service 82fcde
{
Packit Service 82fcde
  struct dynarray_finalize_result res;
Packit Service 82fcde
  if (__libc_dynarray_finalize (&list->dynarray_abstract,
Packit Service 82fcde
                                DYNARRAY_SCRATCH (list),
Packit Service 82fcde
                                sizeof (DYNARRAY_ELEMENT), &res))
Packit Service 82fcde
    {
Packit Service 82fcde
      /* On success, the result owns all the data.  */
Packit Service 82fcde
      DYNARRAY_NAME (init) (list);
Packit Service 82fcde
      *result = (DYNARRAY_FINAL_TYPE) { res.array, res.length };
Packit Service 82fcde
      return true;
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      /* On error, we need to free all data.  */
Packit Service 82fcde
      DYNARRAY_NAME (free) (list);
Packit Service 82fcde
      errno = ENOMEM;
Packit Service 82fcde
      return false;
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
#else /* !DYNARRAY_FINAL_TYPE */
Packit Service 82fcde
/* Transfer the dynamic array to a heap-allocated array and return a
Packit Service 82fcde
   pointer to it.  The pointer is NULL if memory allocation fails, or
Packit Service 82fcde
   if the array is empty, so this function should be used only for
Packit Service 82fcde
   arrays which are known not be empty (usually because they always
Packit Service 82fcde
   have a sentinel at the end).  If LENGTHP is not NULL, the array
Packit Service 82fcde
   length is written to *LENGTHP.  *LIST is re-initialized and can be
Packit Service 82fcde
   reused.  */
Packit Service 82fcde
__attribute__ ((unused, warn_unused_result, nonnull (1)))
Packit Service 82fcde
static DYNARRAY_ELEMENT *
Packit Service 82fcde
DYNARRAY_NAME (finalize) (struct DYNARRAY_STRUCT *list, size_t *lengthp)
Packit Service 82fcde
{
Packit Service 82fcde
  struct dynarray_finalize_result res;
Packit Service 82fcde
  if (__libc_dynarray_finalize (&list->dynarray_abstract,
Packit Service 82fcde
                                DYNARRAY_SCRATCH (list),
Packit Service 82fcde
                                sizeof (DYNARRAY_ELEMENT), &res))
Packit Service 82fcde
    {
Packit Service 82fcde
      /* On success, the result owns all the data.  */
Packit Service 82fcde
      DYNARRAY_NAME (init) (list);
Packit Service 82fcde
      if (lengthp != NULL)
Packit Service 82fcde
        *lengthp = res.length;
Packit Service 82fcde
      return res.array;
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      /* On error, we need to free all data.  */
Packit Service 82fcde
      DYNARRAY_NAME (free) (list);
Packit Service 82fcde
      errno = ENOMEM;
Packit Service 82fcde
      return NULL;
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
#endif /* !DYNARRAY_FINAL_TYPE */
Packit Service 82fcde
Packit Service 82fcde
/* Undo macro definitions.  */
Packit Service 82fcde
Packit Service 82fcde
#undef DYNARRAY_CONCAT0
Packit Service 82fcde
#undef DYNARRAY_CONCAT1
Packit Service 82fcde
#undef DYNARRAY_NAME
Packit Service 82fcde
#undef DYNARRAY_SCRATCH
Packit Service 82fcde
#undef DYNARRAY_HAVE_SCRATCH
Packit Service 82fcde
Packit Service 82fcde
#undef DYNARRAY_STRUCT
Packit Service 82fcde
#undef DYNARRAY_ELEMENT
Packit Service 82fcde
#undef DYNARRAY_PREFIX
Packit Service 82fcde
#undef DYNARRAY_ELEMENT_FREE
Packit Service 82fcde
#undef DYNARRAY_ELEMENT_INIT
Packit Service 82fcde
#undef DYNARRAY_INITIAL_SIZE
Packit Service 82fcde
#undef DYNARRAY_FINAL_TYPE