/* Copyright 2022 Jeffrey Kegler */ /* This file is a modification of one of the versions of the GNU obstack.h * which was LGPL 2.1. Here is the copyright notice from that file: * * obstack.c - subroutines used implicitly by object stack macros * Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, * 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. * 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, write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef _MARPA_OBS_H__ #define _MARPA_OBS_H__ 1 /* Suppress 'unnamed type definition in parentheses' warning in #define ALIGNOF(type) below under MS C compiler older than .NET 2003 */ #if defined(_MSC_VER) && _MSC_VER >= 1310 && !defined(__cplusplus) #pragma warning(disable:4116) #endif #define ALIGNOF(type) offsetof (struct { char c; type element; }, element) /* If B is the base of an object addressed by P, return the result of aligning P to the next multiple of A + 1. B and P must be of type char *. A + 1 must be a power of 2. */ #define ALIGN_UP(x, align) (((x) + (align) - 1) & ~((align) - 1)) #define ALIGN_DOWN(x, align) ((x) & ~((align) - 1)) #define ALIGN_POINTER(base, p, align) \ ((base) + (ptrdiff_t)ALIGN_UP((size_t)((p)-(base)), (align))) /* The original GNU obstack implementation used __PTR_ALIGN, where pointers were converted to integers, aligned as integers, and converted back again. This is unsafe according to C89 and we are purists, so we don't use it. */ /* |object_base| is the base of the object currently being built. |next_free| is the potential base of the next object, and therefore a limit (we hope!) on the size of the one currently being built. |object_base| == |next_free| if we are "idle" -- not currently building an object. An obstack is "idle" when it is initialized. Objects are "started" by moving |next_free| forward so that |next_free| > |object_base|. Objects are finished by setting |next_free| == |object_base|, so the obstack is again "idle". */ struct marpa_obstack /* control current object in current chunk */ { struct marpa_obstack_chunk *chunk; /* address of current struct obstack_chunk */ char *object_base; char *next_free; size_t minimum_chunk_size; /* preferred size to allocate chunks in */ }; struct marpa_obstack_chunk_header /* Lives at front of each chunk. */ { struct marpa_obstack_chunk* prev; /* address of prior chunk or NULL */ size_t size; }; struct marpa_obstack_chunk { struct marpa_obstack_chunk_header header; /* objects begin here in the second and subsequent chunks */ char contents[4]; }; extern void* marpa__obs_newchunk (struct marpa_obstack *, size_t, size_t); extern struct marpa_obstack* marpa__obs_begin (size_t); void marpa__obs_free (struct marpa_obstack *__obstack); /* Pointer to beginning of object being allocated or to be allocated next. Note that this might not be the final address of the object because a new chunk might be needed to hold the final size. */ #define marpa_obs_base(h) ((void *) (h)->object_base) #define marpa_obs_init marpa__obs_begin (0) # define marpa_obstack_object_size(h) \ (unsigned) ((h)->next_free - (h)->object_base) # define marpa_obs_free(h) (marpa__obs_free((h))) /* Reject any object being built, as if it never existed */ # define marpa_obs_reject(h) \ ((h)->next_free = (h)->object_base) # define marpa_obstack_room(h) \ ((h)->chunk->header.size - ((h)->next_free - (char*)((h)->chunk))) #define marpa_obs_new(h, type, count) \ ((type *)marpa__obs_alloc((h), (sizeof(type)*((size_t)(count))), ALIGNOF(type))) /* Start an object */ static inline void* marpa_obs_start (struct marpa_obstack *h, size_t length, size_t alignment) { const size_t current_offset = (size_t)(h->next_free - (char *) (h->chunk)); const size_t aligned_offset = ALIGN_UP (current_offset, alignment); if (aligned_offset + length > h->chunk->header.size) { return marpa__obs_newchunk (h, length, alignment); } h->object_base = (char *) (h->chunk) + aligned_offset; h->next_free = h->object_base + length; return h->object_base; } static inline void *marpa_obs_finish (struct marpa_obstack *h) { void * const finished_object = h->object_base; h->object_base = h->next_free; return finished_object; } static inline void * marpa__obs_alloc (struct marpa_obstack *h, size_t length, size_t alignment) { marpa_obs_start (h, length, alignment); return marpa_obs_finish (h); } /* "Confirm", which is to set at its final value, * the size of a reserved object, currently being built. * The caller needs to ensure that the * confirmed size is less than or equal to the reserved size. * "Fast" here means there is no check -- it is up to the caller * to ensure that the confirmed size is not too big */ static inline void marpa_obs_confirm_fast (struct marpa_obstack* h, int length) { h->next_free = h->object_base + length; } #endif /* marpa_obs.h */ /* vim: set expandtab shiftwidth=4: */