ossp-pkg/act/act_mem.c
/*
** OSSP act - Abstract Container Types
** Copyright (c) 1999-2003 Ralf S. Engelschall <rse@engelschall.com>
** Copyright (c) 1999-2003 The OSSP Project <http://www.ossp.org/>
**
** This file is part of OSSP act, an abstract container type library
** which can be found at http://www.ossp.org/pkg/lib/act/.
**
** Permission to use, copy, modify, and distribute this software for
** any purpose with or without fee is hereby granted, provided that
** the above copyright notice and this permission notice appear in all
** copies.
**
** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
** SUCH DAMAGE.
**
** act_mem.c: memory handling (implementation)
*/
#include <stdlib.h>
#include <string.h>
#include "act_p.h"
/* the API consists only of indirection pointers */
void *(*act_mem_alloc)(size_t) = malloc;
void *(*act_mem_realloc)(void *, size_t) = realloc;
void (*act_mem_free)(void *) = free;
void *(*act_mem_dup)(void *, size_t) = _act_mem_dup;
void *(*act_mem_set)(void *, int, size_t) = _act_mem_set;
void *(*act_mem_move)(void *, const void *, size_t) = _act_mem_move;
void *(*act_mem_mem)(const void *, size_t, const void *, size_t) = _act_mem_mem;
void *(*act_mem_char)(const void *, unsigned char, size_t) = _act_mem_char;
int (*act_mem_cmp)(const void *, const void *, size_t) = _act_mem_cmp;
/*
* Align a size to the next larger or equal size which is likely to have the
* longest *relevant* CPU-specific memory word alignment restrictions.
*/
size_t act_mem_align(size_t size)
{
union mem_word {
void *mw_vp;
void (*mw_fp)(void);
char *mw_cp;
long mw_l;
double mw_d;
};
return ((1+((size-1) / sizeof(union mem_word))) * sizeof(union mem_word));
}
/* the initialization function for the memory part */
intern int act_mem_init(void)
{
#ifdef HAVE_MEMSET
act_mem_set = memset;
#endif
#ifdef HAVE_MEMMOVE
act_mem_move = memmove;
#endif
#ifdef HAVE_MEMCMP
act_mem_cmp = memcmp;
#endif
return TRUE;
}
/* the destruction function for the memory part */
intern int act_mem_kill(void)
{
act_mem_set = _act_mem_set;
act_mem_move = _act_mem_move;
act_mem_cmp = _act_mem_cmp;
return TRUE;
}
/* local version of a memdup function */
intern void *_act_mem_dup(void *mem, size_t bytes)
{
void *dmem;
if (mem == NULL)
return NULL;
if ((dmem = act_mem_alloc(bytes)) == NULL)
return NULL;
act_mem_move(dmem, mem, bytes);
return dmem;
}
/* local fallback version of POSIX memset(3) */
intern void *_act_mem_set(void *dst0, int c0, size_t bytes)
{
register size_t t;
register unsigned int c;
register unsigned char *dst;
const int word_size = sizeof(unsigned int);
const int word_mask = (sizeof(unsigned int) - 1);
dst = dst0;
/* if not enough words for a reasonable speedup, just fill bytes */
if (bytes < 3 * word_size) {
while (bytes != 0) {
*dst++ = c0;
--bytes;
}
return dst0;
}
/* fill the whole stamping word */
if ((c = (unsigned char)c0) != 0) {
c = c | (c << 8);
#if (SIZEOF_INT > 2)
c = c | (c << 16);
#endif
#if (SIZEOF_INT > 4)
c = c | (c << 32);
#endif
}
/* align destination by filling in bytes */
if ((t = (long)dst & word_mask) != 0) {
t = word_size - t;
bytes -= t;
do {
*dst++ = c0;
} while (--t != 0);
}
/* now fill with words. length was >= 2*words so we know t >= 1 here */
t = bytes / word_size;
do {
*(unsigned int *)dst = c;
dst += word_size;
} while (--t != 0);
/* finish with trailing bytes, if there are bytes left */
t = bytes & word_mask;
if (t != 0) {
do {
*dst++ = c0;
} while (--t != 0);
}
return dst0;
}
/* local fallback version of POSIX memmove(3) */
intern void *_act_mem_move(void *dst, const void *src, size_t bytes)
{
register unsigned char *dst_p;
register const unsigned char *src_p;
if (src == NULL || dst == NULL)
return NULL;
src_p = src;
dst_p = dst;
if (dst > src) {
/* must go high to low */
src_p += bytes;
dst_p += bytes;
while (bytes-- > 0)
*--dst_p = *--src_p;
}
else if (dst < src) {
/* must go low to high */
while (bytes-- > 0)
*dst_p++ = *src_p++;
}
return dst;
}
/* local fallback version of POSIX memchr(3) */
intern void *_act_mem_char(const void *src, unsigned char c, size_t bytes)
{
register const unsigned char *cp;
if (bytes != 0) {
cp = src;
do {
if (*cp++ == c)
return ((void *)(cp - 1));
} while (--bytes != 0);
}
return NULL;
}
/* additional function: memmem(3) like */
intern void *
_act_mem_mem(
const void *haystack, size_t haystack_len,
const void *needle, size_t needle_len)
{
register const char *begin;
register const char *last_possible;
if (needle_len == 0)
/* The first occurrence of the empty string is deemed to occur at
the end of the string. */
return (void *)&((const char *)haystack)[haystack_len - 1];
last_possible = (const char *)haystack + haystack_len - needle_len;
for (begin = (const char *)haystack; begin <= last_possible; begin++)
if ( *begin == *((const char *)needle)
&& act_mem_cmp(&begin[1], (const char *)needle + 1, needle_len - 1) == 0)
return (void *)begin;
return NULL;
}
/* local fallback version of POSIX memcmp(3) */
intern int _act_mem_cmp(const void *src1, const void *src2, size_t bytes)
{
register const unsigned char *cp1;
register const unsigned char *cp2;
if (bytes != 0) {
cp1 = src1;
cp2 = src2;
do {
if (*cp1++ != *cp2++)
return (*--cp1 - *--cp2);
} while (--bytes != 0);
}
return 0;
}
/* special utility function: a variant of act_mem_alloc() via a context */
void *act_mem_alloc_ctx(act_ctx_t *ctx, size_t size)
{
void *fct = NULL;
void *ctxarg = NULL;
int ctxuse = FALSE;
void *rv = NULL;
if (ctx == NULL)
return NULL;
act_ctx_get(ctx, ACT_CTX_MEM_ALLOC, &fct);
if (fct == NULL)
fct = (void *)act_mem_alloc;
else {
act_ctx_get(ctx, ACT_CTX_MEM_CTXUSE, &ctxuse);
if (ctxuse)
act_ctx_get(ctx, ACT_CTX_MEM_CTXARG, &ctxarg);
}
if (ctxuse)
rv = ((act_mem_alloc_ctx_t)fct)(ctxarg, size);
else
rv = ((act_mem_alloc_t)fct)(size);
return rv;
}
/* special utility function: a variant of act_mem_realloc() via a context */
void *act_mem_realloc_ctx(act_ctx_t *ctx, void *ptr, size_t size)
{
void *fct = NULL;
void *ctxarg = NULL;
int ctxuse = FALSE;
void *rv = NULL;
if (ctx == NULL)
return NULL;
act_ctx_get(ctx, ACT_CTX_MEM_REALLOC, &fct);
if (fct == NULL)
fct = (void *)act_mem_realloc;
else {
act_ctx_get(ctx, ACT_CTX_MEM_CTXUSE, &ctxuse);
if (ctxuse)
act_ctx_get(ctx, ACT_CTX_MEM_CTXARG, &ctxarg);
}
if (ctxuse)
rv = ((act_mem_realloc_ctx_t)fct)(ctxarg, ptr, size);
else
rv = ((act_mem_realloc_t)fct)(ptr, size);
return rv;
}
/* special utility function: a variant of act_mem_free() via a context */
void act_mem_free_ctx(act_ctx_t *ctx, void *ptr)
{
void *fct = NULL;
void *ctxarg = NULL;
int ctxuse = FALSE;
if (ctx == NULL)
return;
act_ctx_get(ctx, ACT_CTX_MEM_FREE, &fct);
if (fct == NULL)
fct = (void *)act_mem_free;
else {
act_ctx_get(ctx, ACT_CTX_MEM_CTXUSE, &ctxuse);
if (ctxuse)
act_ctx_get(ctx, ACT_CTX_MEM_CTXARG, &ctxarg);
}
if (ctxuse)
((act_mem_free_ctx_t)fct)(ctxarg, ptr);
else
((act_mem_free_t)fct)(ptr);
return;
}