Blame malloc/dynarray.h

Packit 6c4009
/* Type-safe arrays which grow dynamically.  Shared definitions.
Packit 6c4009
   Copyright (C) 2017-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
/* To use the dynarray facility, you need to include
Packit 6c4009
   <malloc/dynarray-skeleton.c> and define the parameter macros
Packit 6c4009
   documented in that file.
Packit 6c4009
Packit 6c4009
   A minimal example which provides a growing list of integers can be
Packit 6c4009
   defined like this:
Packit 6c4009
Packit 6c4009
     struct int_array
Packit 6c4009
     {
Packit 6c4009
       // Pointer to result array followed by its length,
Packit 6c4009
       // as required by DYNARRAY_FINAL_TYPE.
Packit 6c4009
       int *array;
Packit 6c4009
       size_t length;
Packit 6c4009
     };
Packit 6c4009
Packit 6c4009
     #define DYNARRAY_STRUCT dynarray_int
Packit 6c4009
     #define DYNARRAY_ELEMENT int
Packit 6c4009
     #define DYNARRAY_PREFIX dynarray_int_
Packit 6c4009
     #define DYNARRAY_FINAL_TYPE struct int_array
Packit 6c4009
     #include <malloc/dynarray-skeleton.c>
Packit 6c4009
Packit 6c4009
   To create a three-element array with elements 1, 2, 3, use this
Packit 6c4009
   code:
Packit 6c4009
Packit 6c4009
     struct dynarray_int dyn;
Packit 6c4009
     dynarray_int_init (&dyn);
Packit 6c4009
     for (int i = 1; i <= 3; ++i)
Packit 6c4009
       {
Packit 6c4009
         int *place = dynarray_int_emplace (&dyn);
Packit 6c4009
         assert (place != NULL);
Packit 6c4009
         *place = i;
Packit 6c4009
       }
Packit 6c4009
     struct int_array result;
Packit 6c4009
     bool ok = dynarray_int_finalize (&dyn, &result);
Packit 6c4009
     assert (ok);
Packit 6c4009
     assert (result.length == 3);
Packit 6c4009
     assert (result.array[0] == 1);
Packit 6c4009
     assert (result.array[1] == 2);
Packit 6c4009
     assert (result.array[2] == 3);
Packit 6c4009
     free (result.array);
Packit 6c4009
Packit 6c4009
   If the elements contain resources which must be freed, define
Packit 6c4009
   DYNARRAY_ELEMENT_FREE appropriately, like this:
Packit 6c4009
Packit 6c4009
     struct str_array
Packit 6c4009
     {
Packit 6c4009
       char **array;
Packit 6c4009
       size_t length;
Packit 6c4009
     };
Packit 6c4009
Packit 6c4009
     #define DYNARRAY_STRUCT dynarray_str
Packit 6c4009
     #define DYNARRAY_ELEMENT char *
Packit 6c4009
     #define DYNARRAY_ELEMENT_FREE(ptr) free (*ptr)
Packit 6c4009
     #define DYNARRAY_PREFIX dynarray_str_
Packit 6c4009
     #define DYNARRAY_FINAL_TYPE struct str_array
Packit 6c4009
     #include <malloc/dynarray-skeleton.c>
Packit 6c4009
Packit 6c4009
   Compared to scratch buffers, dynamic arrays have the following
Packit 6c4009
   features:
Packit 6c4009
Packit 6c4009
   - They have an element type, and are not just an untyped buffer of
Packit 6c4009
     bytes.
Packit 6c4009
Packit 6c4009
   - When growing, previously stored elements are preserved.  (It is
Packit 6c4009
     expected that scratch_buffer_grow_preserve and
Packit 6c4009
     scratch_buffer_set_array_size eventually go away because all
Packit 6c4009
     current users are moved to dynamic arrays.)
Packit 6c4009
Packit 6c4009
   - Scratch buffers have a more aggressive growth policy because
Packit 6c4009
     growing them typically means a retry of an operation (across an
Packit 6c4009
     NSS service module boundary), which is expensive.
Packit 6c4009
Packit 6c4009
   - For the same reason, scratch buffers have a much larger initial
Packit 6c4009
     stack allocation.  */
Packit 6c4009
Packit 6c4009
#ifndef _DYNARRAY_H
Packit 6c4009
#define _DYNARRAY_H
Packit 6c4009
Packit 6c4009
#include <stdbool.h>
Packit 6c4009
#include <stddef.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
Packit 6c4009
struct dynarray_header
Packit 6c4009
{
Packit 6c4009
  size_t used;
Packit 6c4009
  size_t allocated;
Packit 6c4009
  void *array;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
/* Marker used in the allocated member to indicate that an error was
Packit 6c4009
   encountered.  */
Packit 6c4009
static inline size_t
Packit 6c4009
__dynarray_error_marker (void)
Packit 6c4009
{
Packit 6c4009
  return -1;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Internal function.  See the has_failed function in
Packit 6c4009
   dynarray-skeleton.c.  */
Packit 6c4009
static inline bool
Packit 6c4009
__dynarray_error (struct dynarray_header *list)
Packit 6c4009
{
Packit 6c4009
  return list->allocated == __dynarray_error_marker ();
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Internal function.  Enlarge the dynamically allocated area of the
Packit 6c4009
   array to make room for one more element.  SCRATCH is a pointer to
Packit 6c4009
   the scratch area (which is not heap-allocated and must not be
Packit 6c4009
   freed).  ELEMENT_SIZE is the size, in bytes, of one element.
Packit 6c4009
   Return false on failure, true on success.  */
Packit 6c4009
bool __libc_dynarray_emplace_enlarge (struct dynarray_header *,
Packit 6c4009
                                      void *scratch, size_t element_size);
Packit 6c4009
Packit 6c4009
/* Internal function.  Enlarge the dynamically allocated area of the
Packit 6c4009
   array to make room for at least SIZE elements (which must be larger
Packit 6c4009
   than the existing used part of the dynamic array).  SCRATCH is a
Packit 6c4009
   pointer to the scratch area (which is not heap-allocated and must
Packit 6c4009
   not be freed).  ELEMENT_SIZE is the size, in bytes, of one element.
Packit 6c4009
   Return false on failure, true on success.  */
Packit 6c4009
bool __libc_dynarray_resize (struct dynarray_header *, size_t size,
Packit 6c4009
                             void *scratch, size_t element_size);
Packit 6c4009
Packit 6c4009
/* Internal function.  Like __libc_dynarray_resize, but clear the new
Packit 6c4009
   part of the dynamic array.  */
Packit 6c4009
bool __libc_dynarray_resize_clear (struct dynarray_header *, size_t size,
Packit 6c4009
                                   void *scratch, size_t element_size);
Packit 6c4009
Packit 6c4009
/* Internal type.  */
Packit 6c4009
struct dynarray_finalize_result
Packit 6c4009
{
Packit 6c4009
  void *array;
Packit 6c4009
  size_t length;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
/* Internal function.  Copy the dynamically-allocated area to an
Packit 6c4009
   explicitly-sized heap allocation.  SCRATCH is a pointer to the
Packit 6c4009
   embedded scratch space.  ELEMENT_SIZE is the size, in bytes, of the
Packit 6c4009
   element type.  On success, true is returned, and pointer and length
Packit 6c4009
   are written to *RESULT.  On failure, false is returned.  The caller
Packit 6c4009
   has to take care of some of the memory management; this function is
Packit 6c4009
   expected to be called from dynarray-skeleton.c.  */
Packit 6c4009
bool __libc_dynarray_finalize (struct dynarray_header *list, void *scratch,
Packit 6c4009
                               size_t element_size,
Packit 6c4009
                               struct dynarray_finalize_result *result);
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Internal function.  Terminate the process after an index error.
Packit 6c4009
   SIZE is the number of elements of the dynamic array.  INDEX is the
Packit 6c4009
   lookup index which triggered the failure.  */
Packit 6c4009
void __libc_dynarray_at_failure (size_t size, size_t index)
Packit 6c4009
  __attribute__ ((noreturn));
Packit 6c4009
Packit 6c4009
#ifndef _ISOMAC
Packit 6c4009
libc_hidden_proto (__libc_dynarray_emplace_enlarge)
Packit 6c4009
libc_hidden_proto (__libc_dynarray_resize)
Packit 6c4009
libc_hidden_proto (__libc_dynarray_resize_clear)
Packit 6c4009
libc_hidden_proto (__libc_dynarray_finalize)
Packit 6c4009
libc_hidden_proto (__libc_dynarray_at_failure)
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#endif /* _DYNARRAY_H */