/* ** Act - Abstract Container Type Library ** Copyright (c) 1999-2001 Ralf S. Engelschall ** ** This file is part of Act, a library for dealing with Abstract ** Container Types which can be found at http://www.ossp.org/pkg/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 #include #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; }