R
Richard Harter
Apologies for the length - this post is best viewed with fixed font
and a line width >= 72.
Below is the source code for a C header file that provides a suite
of storage management macros. I am asking for comments on it. In
particular: Are there any gotchas that I have overlooked? Are
there any suggestions for improvements? Is there a generally
available superior packages to do the same thing with the same
general licensing? Comments on the documentation and suggestions
for improving it are welcome.
And, of course, anyone is welcome to use this little package as
they see fit.
/* ----------------------------------------------------------------- */
/* Copyright (c) 2006 by Richard Harter */
/* */
/* Permission is hereby granted, free of charge, to any person */
/* obtaining a copy of this software and associated documentation */
/* files (the "Software"), to deal in the Software without */
/* restriction, including without limitation the rights to use, */
/* copy, modify, merge, publish, distribute, sublicense, and/or */
/* sell copies of the Software, and to permit persons to whom the */
/* Software is furnished to do so, subject to the following */
/* conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the */
/* Software. */
/* */
/* Derived works shall include a notice that the software is a */
/* modified version of the copyrighted software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY */
/* KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE */
/* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */
/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR */
/* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR */
/* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/* */
/* ----------------------------------------------------------------- */
/* */
/* This include file provides a suite of macros that simplify the */
/* management of allocatable storage. There are two groups of */
/* macros, the segmented space macros, and dynamic array macros. */
/* The segmented space macros create a sequence of segments, where */
/* the segments are all of the same type but are variable in size. */
/* The dynamic array macros create an extensible array of elements */
/* all the same size. Typically the segspace macros are used for */
/* creating blocks of storage of primitive types, e.g., ints or */
/* chars; there is no provision for indexing through the blocks. */
/* Dynamic arrays, on the other hand, are typically used for tables. */
/* */
/* All of the storage is allocated off the heap. Control data is */
/* global to the file containing the include file. All references */
/* to storage should be of the form of base+offset (e.g. array */
/* indexing) rather than pointers because the base address can */
/* can as the base is resized. Resizing is always upwards, i.e. the */
/* storage elements never decrease in size. Each separate storage */
/* unit can be invidually freed. */
/* */
/* Usage: */
/* */
/* Storage units (segmented spaces or dynamic arrays) should be */
/* declared at the file level using the STF_DCL_SEGSPACE and */
/* STG_DCL_DYNARRAY macros. Both macros take a type and a base */
/* name as arguments; in addition the STG_DCL_DYNARRAY macro has the */
/* the address of a variable that will contain the array length. */
/* The "name" argument is the address of the variable that contains */
/* the pointer to base of the storage space. */
/* */
/* There are two macros for increasing segspace storage, one to add */
/* a segment and one to trim the length of the last segment. The */
/* STG_ADD_SEGSPACE macro takes three arguments, the base name, the */
/* segment length (tentative), and the address of the offset. The */
/* trim macro reduces the length of the last segment. */
/* */
/* There are also two macros for increasing the size of dynamic */
/* arrays, one to increment the array size, and one to increase its */
/* size by an arbitrary amount. The STG_INCR_DYNARRAY macro has a */
/* single argument, the base pointer. The STG_REQSZ_DYNARRAY macro */
/* two arguments, the base pointer, and the new size. */
/* */
/* Caveats: */
/* */
/* There is no error checking. Users are expected to use the macros */
/* intelligently. The calls are not followed by error checks on the */
/* returned value. All macro calls must be followed by a semicolon. */
/* */
/* ----------------------------------------------------------------- */
#ifndef utl_stgmacros_include
#define utl_stgmacros_include
#define STG_DCL_SEGSPACE(name,type) \
static type * name = 0; \
static size_t name##_size = sizeof(type); \
static size_t name##_alloc = 0; \
static size_t name##_used = 0
#define STG_ADD_SEGSPACE(name,offset,length) \
do { \
offset = name##_used; \
name##_used += length; \
if (name##_used > name##_alloc) { \
name##_alloc = 2*name##_alloc + length; \
name = realloc(name, name##_alloc*name##_size); \
} \
} while (0)
#define STG_TRIM_SEGSPACE(name,length) \
name##_used -= length
#define STG_FREE_SEGSPACE(name); \
do { \
free(name); \
name = 0; \
name##_alloc = 0; \
name##_used = 0; \
} while (0)
#define STG_DCL_DYNARRAY(name, type, length) \
static type * name = 0; \
static int length = 0; \
static size_t name##_size = sizeof(type); \
static size_t name##_alloc = 0; \
static int * name##_lenptr = &length
#define STG_INCR_DYNARRAY(name) \
do { \
(*name##_lenptr)++; \
if (*name##_lenptr > name##_alloc ) { \
if (name##_alloc < 8) name##_alloc = 8; \
else name##_alloc *= 2; \
name = realloc(name,name##_alloc * name##_size); \
} \
} while (0)
#define STG_REQSZ_DYNARRAY(name,length) \
do { \
if (length > name##_alloc) { \
name = realloc(name,length * name##_size); \
name##_alloc = length; \
} \
} while (0)
#define STG_FREE_DYNARRAY(name) \
do { \
free(name); \
name = 0; \
*name##_lenptr = 0; \
name##_alloc = 0; \
} while (0)
#endif
and a line width >= 72.
Below is the source code for a C header file that provides a suite
of storage management macros. I am asking for comments on it. In
particular: Are there any gotchas that I have overlooked? Are
there any suggestions for improvements? Is there a generally
available superior packages to do the same thing with the same
general licensing? Comments on the documentation and suggestions
for improving it are welcome.
And, of course, anyone is welcome to use this little package as
they see fit.
/* ----------------------------------------------------------------- */
/* Copyright (c) 2006 by Richard Harter */
/* */
/* Permission is hereby granted, free of charge, to any person */
/* obtaining a copy of this software and associated documentation */
/* files (the "Software"), to deal in the Software without */
/* restriction, including without limitation the rights to use, */
/* copy, modify, merge, publish, distribute, sublicense, and/or */
/* sell copies of the Software, and to permit persons to whom the */
/* Software is furnished to do so, subject to the following */
/* conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the */
/* Software. */
/* */
/* Derived works shall include a notice that the software is a */
/* modified version of the copyrighted software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY */
/* KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE */
/* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */
/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR */
/* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR */
/* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/* */
/* ----------------------------------------------------------------- */
/* */
/* This include file provides a suite of macros that simplify the */
/* management of allocatable storage. There are two groups of */
/* macros, the segmented space macros, and dynamic array macros. */
/* The segmented space macros create a sequence of segments, where */
/* the segments are all of the same type but are variable in size. */
/* The dynamic array macros create an extensible array of elements */
/* all the same size. Typically the segspace macros are used for */
/* creating blocks of storage of primitive types, e.g., ints or */
/* chars; there is no provision for indexing through the blocks. */
/* Dynamic arrays, on the other hand, are typically used for tables. */
/* */
/* All of the storage is allocated off the heap. Control data is */
/* global to the file containing the include file. All references */
/* to storage should be of the form of base+offset (e.g. array */
/* indexing) rather than pointers because the base address can */
/* can as the base is resized. Resizing is always upwards, i.e. the */
/* storage elements never decrease in size. Each separate storage */
/* unit can be invidually freed. */
/* */
/* Usage: */
/* */
/* Storage units (segmented spaces or dynamic arrays) should be */
/* declared at the file level using the STF_DCL_SEGSPACE and */
/* STG_DCL_DYNARRAY macros. Both macros take a type and a base */
/* name as arguments; in addition the STG_DCL_DYNARRAY macro has the */
/* the address of a variable that will contain the array length. */
/* The "name" argument is the address of the variable that contains */
/* the pointer to base of the storage space. */
/* */
/* There are two macros for increasing segspace storage, one to add */
/* a segment and one to trim the length of the last segment. The */
/* STG_ADD_SEGSPACE macro takes three arguments, the base name, the */
/* segment length (tentative), and the address of the offset. The */
/* trim macro reduces the length of the last segment. */
/* */
/* There are also two macros for increasing the size of dynamic */
/* arrays, one to increment the array size, and one to increase its */
/* size by an arbitrary amount. The STG_INCR_DYNARRAY macro has a */
/* single argument, the base pointer. The STG_REQSZ_DYNARRAY macro */
/* two arguments, the base pointer, and the new size. */
/* */
/* Caveats: */
/* */
/* There is no error checking. Users are expected to use the macros */
/* intelligently. The calls are not followed by error checks on the */
/* returned value. All macro calls must be followed by a semicolon. */
/* */
/* ----------------------------------------------------------------- */
#ifndef utl_stgmacros_include
#define utl_stgmacros_include
#define STG_DCL_SEGSPACE(name,type) \
static type * name = 0; \
static size_t name##_size = sizeof(type); \
static size_t name##_alloc = 0; \
static size_t name##_used = 0
#define STG_ADD_SEGSPACE(name,offset,length) \
do { \
offset = name##_used; \
name##_used += length; \
if (name##_used > name##_alloc) { \
name##_alloc = 2*name##_alloc + length; \
name = realloc(name, name##_alloc*name##_size); \
} \
} while (0)
#define STG_TRIM_SEGSPACE(name,length) \
name##_used -= length
#define STG_FREE_SEGSPACE(name); \
do { \
free(name); \
name = 0; \
name##_alloc = 0; \
name##_used = 0; \
} while (0)
#define STG_DCL_DYNARRAY(name, type, length) \
static type * name = 0; \
static int length = 0; \
static size_t name##_size = sizeof(type); \
static size_t name##_alloc = 0; \
static int * name##_lenptr = &length
#define STG_INCR_DYNARRAY(name) \
do { \
(*name##_lenptr)++; \
if (*name##_lenptr > name##_alloc ) { \
if (name##_alloc < 8) name##_alloc = 8; \
else name##_alloc *= 2; \
name = realloc(name,name##_alloc * name##_size); \
} \
} while (0)
#define STG_REQSZ_DYNARRAY(name,length) \
do { \
if (length > name##_alloc) { \
name = realloc(name,length * name##_size); \
name##_alloc = length; \
} \
} while (0)
#define STG_FREE_DYNARRAY(name) \
do { \
free(name); \
name = 0; \
*name##_lenptr = 0; \
name##_alloc = 0; \
} while (0)
#endif