-/* PSPP - computes sample statistics.
+/* PSPP - a program for statistical analysis.
Copyright (C) 2000 Free Software Foundation, Inc.
- Written by Ben Pfaff <blp@gnu.org>.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
- This program 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
- General Public License for more details.
+ This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <config.h>
#include "pool.h"
+#include <stdint.h>
#include <stdlib.h>
-#include "alloc.h"
#include <libpspp/assertion.h>
#include "message.h"
-#include "size_max.h"
#include "str.h"
+#include "xalloc.h"
+
/* Fast, low-overhead memory block suballocator. */
struct pool
{
};
/* Pool block. */
-struct pool_block
+struct pool_block
{
struct pool_block *prev;
struct pool_block *next;
};
/* Pool routines can maintain objects (`gizmos') as well as doing
- suballocation.
+ suballocation.
This structure is used to keep track of them. */
struct pool_gizmo
{
/* DISCRETE_BLOCKS may be declared as nonzero to prevent
suballocation of blocks. This is useful under memory
- debuggers like Checker or valgrind because it allows the
- source location of bugs to be more accurately pinpointed.
+ debuggers like valgrind because it allows the source location
+ of bugs to be more accurately pinpointed.
On the other hand, if we're testing the library, then we want to
test the library's real functionality, not its crippled, slow,
block = xmalloc (BLOCK_SIZE);
block->prev = block->next = block;
block->ofs = POOL_BLOCK_SIZE + POOL_SIZE;
-
+
pool = (struct pool *) (((char *) block) + POOL_BLOCK_SIZE);
pool->parent = NULL;
pool->blocks = block;
Meant for use indirectly via pool_create_container(). */
void *
-pool_create_at_offset (size_t struct_size, size_t pool_member_offset)
+pool_create_at_offset (size_t struct_size, size_t pool_member_offset)
{
struct pool *pool;
char *struct_;
return;
/* Remove this pool from its parent's list of gizmos. */
- if (pool->parent)
+ if (pool->parent)
delete_gizmo (pool->parent, (void *) (((char *) pool) + POOL_SIZE));
-
+
free_all_gizmos (pool);
/* Free all the memory. */
/* Release all the memory and gizmos in POOL.
Blocks are not given back with free() but kept for later
- allocations. To give back memory, use a subpool instead. */
+ allocations. To give back memory, use a subpool instead. */
void
-pool_clear (struct pool *pool)
+pool_clear (struct pool *pool)
{
free_all_gizmos (pool);
/* Zero out block sizes. */
{
struct pool_block *cur;
-
+
cur = pool->blocks;
do
{
cur->ofs = POOL_BLOCK_SIZE;
- if ((char *) cur + POOL_BLOCK_SIZE == (char *) pool)
+ if ((char *) cur + POOL_BLOCK_SIZE == (char *) pool)
{
cur->ofs += POOL_SIZE;
if (pool->parent != NULL)
- cur->ofs += POOL_GIZMO_SIZE;
+ cur->ofs += POOL_GIZMO_SIZE;
}
cur = cur->next;
}
if (amt == 0)
return NULL;
-
+
#ifndef DISCRETE_BLOCKS
if (amt <= MAX_SUBALLOC)
{
/* No space in this block, so we must make other
arrangements. */
- if (b->next->ofs == 0)
+ if (b->next->ofs == 0)
{
/* The next block is empty. Use it. */
b = b->next;
if ((char *) b + POOL_BLOCK_SIZE == (char *) pool)
b->ofs += POOL_SIZE;
}
- else
+ else
{
/* Create a new block at the start of the list. */
b = xmalloc (BLOCK_SIZE);
/* Strings need not be aligned on any boundary, but some
operations may be more efficient when they are. However,
that's only going to help with reasonably long strings. */
- if (amt < ALIGN_SIZE)
+ if (amt < ALIGN_SIZE)
{
if (amt == 0)
return NULL;
Terminates the program if the memory cannot be obtained,
including the case where N * S overflows the range of size_t. */
void *
-pool_nalloc (struct pool *pool, size_t n, size_t s)
+pool_nalloc (struct pool *pool, size_t n, size_t s)
{
if (xalloc_oversized (n, s))
xalloc_die ();
the returned pointere may not be aligned properly for other
types. */
char *
-pool_strdup (struct pool *pool, const char *string)
+pool_strdup (struct pool *pool, const char *string)
{
return pool_clone_unaligned (pool, string, strlen (string) + 1);
}
+/* Duplicates the SIZE bytes of STRING, plus a trailing 0 byte,
+ and returns a pointer to the duplicate. For use only with
+ strings, because the returned pointere may not be aligned
+ properly for other types. */
+char *
+pool_strdup0 (struct pool *pool, const char *string, size_t size)
+{
+ char *new_string = pool_alloc_unaligned (pool, size + 1);
+ memcpy (new_string, string, size);
+ new_string[size] = '\0';
+ return new_string;
+}
+
/* Formats FORMAT with the given ARGS in memory allocated from
POOL and returns the formatted string. */
char *
needed = vsnprintf (s, avail, format, args);
va_end (args);
- if (needed >= 0)
+ if (needed >= 0)
{
- if (needed < avail)
+ if (needed < avail)
{
/* Success. Reserve the space that was actually used. */
b->ofs += needed + 1;
va_end (args);
}
}
- else
+ else
{
/* Some old libc's returned -1 when the destination string
was too short. This should be uncommon these days and
{
va_list args;
char *string;
-
+
va_start (args, format);
string = pool_vasprintf (pool, format, args);
va_end (args);
Terminates the program if the memory cannot be obtained,
including the case where N * S overflows the range of size_t. */
void *
-pool_nmalloc (struct pool *pool, size_t n, size_t s)
+pool_nmalloc (struct pool *pool, size_t n, size_t s)
{
if (xalloc_oversized (n, s))
xalloc_die ();
return pool_malloc (pool, n * s);
}
+/* Allocates AMT bytes using malloc(), to be managed by POOL,
+ zeros the block, and returns a pointer to the beginning of the
+ block.
+ If POOL is a null pointer, then allocates a normal memory block
+ with xmalloc(). */
+void *
+pool_zalloc (struct pool *pool, size_t amt)
+{
+ void *p = pool_malloc (pool, amt);
+ memset (p, 0, amt);
+ return p;
+}
+
+/* Allocates and returns N elements of S bytes each, to be
+ managed by POOL, and zeros the block.
+ If POOL is a null pointer, then allocates a normal memory block
+ with malloc().
+ N must be nonnegative, S must be positive.
+ Terminates the program if the memory cannot be obtained,
+ including the case where N * S overflows the range of size_t. */
+void *
+pool_calloc (struct pool *pool, size_t n, size_t s)
+{
+ void *p = pool_nmalloc (pool, n, s);
+ memset (p, 0, n * s);
+ return p;
+}
+
/* Changes the allocation size of the specified memory block P managed
by POOL to AMT bytes and returns a pointer to the beginning of the
block.
g = (void *) (((char *) subpool->blocks) + subpool->blocks->ofs);
subpool->blocks->ofs += POOL_GIZMO_SIZE;
-
+
g->type = POOL_GIZMO_SUBPOOL;
g->p.subpool = subpool;
The subpool will be destroyed automatically when POOL is destroyed.
It may also be destroyed explicitly in advance. */
void
-pool_add_subpool (struct pool *pool, struct pool *subpool)
+pool_add_subpool (struct pool *pool, struct pool *subpool)
{
struct pool_gizmo *g;
assert (pool != NULL);
assert (subpool != NULL);
assert (subpool->parent == NULL);
-
+
g = pool_alloc (subpool, sizeof *g);
g->type = POOL_GIZMO_SUBPOOL;
g->p.subpool = subpool;
assert (pool && file_name && mode);
f = fopen (file_name, mode);
- if (f == NULL)
- return NULL;
+ if (f != NULL)
+ pool_attach_file (pool, f);
return f;
}
may be closed explicitly in advance using pool_fclose(), or
detached from the pool with pool_detach_file(). */
FILE *
-pool_tmpfile (struct pool *pool)
+pool_tmpfile (struct pool *pool)
{
FILE *file = tmpfile ();
if (file != NULL)
pool_unregister (struct pool *pool, void *p)
{
assert (pool && p);
-
+
{
struct pool_gizmo *g;
return true;
}
}
-
+
return false;
}
\f
/* Restores to POOL the state recorded in MARK.
Emptied blocks are not given back with free() but kept for
later allocations. To get that behavior, use a subpool
- instead. */
+ instead. */
void
pool_release (struct pool *pool, const struct pool_mark *mark)
{
assert (pool && mark);
-
+
{
struct pool_gizmo *cur, *next;
else
pool->gizmos = NULL;
}
-
+
{
struct pool_block *cur;
- for (cur = pool->blocks; cur != mark->block; cur = cur->next)
+ for (cur = pool->blocks; cur != mark->block; cur = cur->next)
{
cur->ofs = POOL_BLOCK_SIZE;
- if ((char *) cur + POOL_BLOCK_SIZE == (char *) pool)
+ if ((char *) cur + POOL_BLOCK_SIZE == (char *) pool)
{
cur->ofs += POOL_SIZE;
if (pool->parent != NULL)
- cur->ofs += POOL_GIZMO_SIZE;
+ cur->ofs += POOL_GIZMO_SIZE;
}
}
pool->blocks = mark->block;
check_gizmo (pool, gizmo);
}
-
+
/* Removes GIZMO from POOL's gizmo list. */
static void
delete_gizmo (struct pool *pool, struct pool_gizmo *gizmo)
/* Free all the gizmos in POOL. */
static void
-free_all_gizmos (struct pool *pool)
+free_all_gizmos (struct pool *pool)
{
struct pool_gizmo *cur, *next;
}
static void
-check_gizmo (struct pool *p, struct pool_gizmo *g)
+check_gizmo (struct pool *p, struct pool_gizmo *g)
{
assert (g->pool == p);
assert (g->next == NULL || g->next->prev == g);