qse/qse/lib/cmn/mem.c

442 lines
8.5 KiB
C
Raw Normal View History

/*
2009-09-16 04:01:02 +00:00
* $Id: mem.c 287 2009-09-15 10:01:02Z hyunghwan.chung $
*
2009-09-16 04:01:02 +00:00
Copyright 2006-2009 Chung, Hyung-Hwan.
This file is part of QSE.
2009-09-16 04:01:02 +00:00
QSE 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 3 of
the License, or (at your option) any later version.
2009-09-16 04:01:02 +00:00
QSE 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.
2009-09-16 04:01:02 +00:00
You should have received a copy of the GNU Lesser General Public
License along with QSE. If not, see <http://www.gnu.org/licenses/>.
*/
2008-12-21 21:35:07 +00:00
#include <qse/cmn/mem.h>
#include <stdlib.h>
2008-04-25 07:08:14 +00:00
#if defined(__SPU__)
#include <spu_intrinsics.h>
2008-12-21 21:35:07 +00:00
#define SPU_VUC_SIZE QSE_SIZEOF(vector unsigned char)
2008-04-25 07:08:14 +00:00
#endif
2008-12-21 21:35:07 +00:00
/*#define IS_UNALIGNED(ptr) (((qse_size_t)ptr)%QSE_SIZEOF(qse_size_t))*/
#define IS_UNALIGNED(ptr) (((qse_size_t)ptr)&(QSE_SIZEOF(qse_size_t)-1))
2007-12-25 21:25:45 +00:00
#define IS_ALIGNED(ptr) (!IS_UNALIGNED(ptr))
2007-12-25 21:37:48 +00:00
#define IS_EITHER_UNALIGNED(ptr1,ptr2) \
2008-12-21 21:35:07 +00:00
(((qse_size_t)ptr1|(qse_size_t)ptr2)&(QSE_SIZEOF(qse_size_t)-1))
2007-12-25 21:37:48 +00:00
#define IS_BOTH_ALIGNED(ptr1,ptr2) (!IS_EITHER_UNALIGNED(ptr1,ptr2))
2008-12-21 21:35:07 +00:00
void* qse_memcpy (void* dst, const void* src, qse_size_t n)
{
2008-12-21 21:35:07 +00:00
#if defined(QSE_BUILD_FOR_SIZE)
2008-04-25 22:50:34 +00:00
2008-12-21 21:35:07 +00:00
qse_byte_t* d = (qse_byte_t*)dst;
qse_byte_t* s = (qse_byte_t*)src;
2008-04-25 06:19:44 +00:00
while (n-- > 0) *d++ = *s++;
return dst;
2008-04-25 22:50:34 +00:00
#elif defined(__SPU__)
2008-12-21 21:35:07 +00:00
qse_byte_t* d;
qse_byte_t* s;
2008-04-25 22:50:34 +00:00
2008-04-25 22:59:00 +00:00
if (n >= SPU_VUC_SIZE &&
2008-12-21 21:35:07 +00:00
(((qse_size_t)dst) & (SPU_VUC_SIZE-1)) == 0 &&
(((qse_size_t)src) & (SPU_VUC_SIZE-1)) == 0)
2008-04-25 22:50:34 +00:00
{
vector unsigned char* du = (vector unsigned char*)dst;
vector unsigned char* su = (vector unsigned char*)src;
do
{
*du++ = *su++;
n -= SPU_VUC_SIZE;
}
while (n >= SPU_VUC_SIZE);
2008-12-21 21:35:07 +00:00
d = (qse_byte_t*)du;
s = (qse_byte_t*)su;
2008-04-25 22:50:34 +00:00
}
else
{
2008-12-21 21:35:07 +00:00
d = (qse_byte_t*)dst;
s = (qse_byte_t*)src;
2008-04-25 22:50:34 +00:00
}
while (n-- > 0) *d++ = *s++;
return dst;
2008-04-25 06:19:44 +00:00
#else
2008-04-25 22:50:34 +00:00
2008-12-21 21:35:07 +00:00
qse_byte_t* d;
qse_byte_t* s;
2007-12-25 21:25:45 +00:00
2008-12-21 21:35:07 +00:00
if (n >= QSE_SIZEOF(qse_size_t) && IS_BOTH_ALIGNED(dst,src))
2007-12-25 21:25:45 +00:00
{
2008-12-21 21:35:07 +00:00
qse_size_t* du = (qse_size_t*)dst;
qse_size_t* su = (qse_size_t*)src;
2008-04-25 07:34:17 +00:00
do
2007-12-25 21:25:45 +00:00
{
2008-04-25 06:19:44 +00:00
*du++ = *su++;
2008-12-21 21:35:07 +00:00
n -= QSE_SIZEOF(qse_size_t);
2007-12-25 21:25:45 +00:00
}
2008-12-21 21:35:07 +00:00
while (n >= QSE_SIZEOF(qse_size_t));
2007-12-25 21:25:45 +00:00
2008-12-21 21:35:07 +00:00
d = (qse_byte_t*)du;
s = (qse_byte_t*)su;
2007-12-25 21:25:45 +00:00
}
2008-04-25 06:19:44 +00:00
else
{
2008-12-21 21:35:07 +00:00
d = (qse_byte_t*)dst;
s = (qse_byte_t*)src;
}
2008-04-25 06:19:44 +00:00
while (n-- > 0) *d++ = *s++;
return dst;
2008-04-25 22:50:34 +00:00
2008-04-25 06:19:44 +00:00
#endif
}
2008-12-21 21:35:07 +00:00
void* qse_memmove (void* dst, const void* src, qse_size_t n)
2008-04-26 22:58:10 +00:00
{
2008-12-21 21:35:07 +00:00
const qse_byte_t* sre = (const qse_byte_t*)src + n;
2008-04-26 22:58:10 +00:00
if (dst <= src || dst >= (const void*)sre)
{
2008-12-21 21:35:07 +00:00
qse_byte_t* d = (qse_byte_t*)dst;
const qse_byte_t* s = (const qse_byte_t*)src;
2008-04-26 22:58:10 +00:00
while (n-- > 0) *d++ = *s++;
}
else
{
2008-12-21 21:35:07 +00:00
qse_byte_t* dse = (qse_byte_t*)dst + n;
2008-04-26 22:58:10 +00:00
while (n-- > 0) *--dse = *--sre;
}
return dst;
}
2008-12-21 21:35:07 +00:00
void* qse_memset (void* dst, int val, qse_size_t n)
{
2008-12-21 21:35:07 +00:00
#if defined(QSE_BUILD_FOR_SIZE)
2008-04-25 07:08:14 +00:00
2008-12-21 21:35:07 +00:00
qse_byte_t* d = (qse_byte_t*)dst;
while (n-- > 0) *d++ = (qse_byte_t)val;
2008-04-25 06:19:44 +00:00
return dst;
2008-04-25 07:08:14 +00:00
2008-04-25 06:19:44 +00:00
#elif defined(__SPU__)
2008-04-25 07:08:14 +00:00
2008-12-21 21:35:07 +00:00
qse_byte_t* d;
qse_size_t rem;
2008-04-25 07:08:14 +00:00
2008-04-25 08:25:47 +00:00
if (n <= 0) return dst;
2008-12-21 21:35:07 +00:00
d = (qse_byte_t*)dst;
2008-04-25 08:25:47 +00:00
2008-04-25 07:08:14 +00:00
/* spu SIMD instructions require 16-byte alignment */
2008-12-21 21:35:07 +00:00
rem = ((qse_size_t)dst) & (SPU_VUC_SIZE-1);
2008-04-25 07:08:14 +00:00
if (rem > 0)
{
2008-04-25 22:27:37 +00:00
/* handle leading unaligned part */
2008-12-21 21:35:07 +00:00
do { *d++ = (qse_byte_t)val; }
2008-04-25 22:50:34 +00:00
while (n-- > 0 && ++rem < SPU_VUC_SIZE);
2008-04-25 07:08:14 +00:00
}
/* do the vector copy */
2008-04-25 22:50:34 +00:00
if (n >= SPU_VUC_SIZE)
2008-04-25 07:08:14 +00:00
{
2008-04-25 07:40:41 +00:00
/* a vector of 16 unsigned char cells */
vector unsigned char v16;
/* a pointer to such a vector */
vector unsigned char* vd = (vector unsigned char*)d;
2008-04-25 07:08:14 +00:00
2008-04-25 07:40:41 +00:00
/* fills all 16 unsigned char cells with the same value
* no need to use shift and bitwise-or owing to splats */
2008-12-21 21:35:07 +00:00
v16 = spu_splats((qse_byte_t)val);
2008-04-25 07:40:41 +00:00
do
{
*vd++ = v16;
2008-04-25 22:50:34 +00:00
n -= SPU_VUC_SIZE;
2008-04-25 07:40:41 +00:00
}
2008-04-25 22:50:34 +00:00
while (n >= SPU_VUC_SIZE);
2008-04-25 07:40:41 +00:00
2008-12-21 21:35:07 +00:00
d = (qse_byte_t*)vd;
2008-04-25 06:19:44 +00:00
}
2008-04-25 22:27:37 +00:00
/* handle the trailing part */
2008-12-21 21:35:07 +00:00
while (n-- > 0) *d++ = (qse_byte_t)val;
2008-04-25 07:08:14 +00:00
return dst;
2008-04-25 06:19:44 +00:00
#else
2008-04-25 07:08:14 +00:00
2008-12-21 21:35:07 +00:00
qse_byte_t* d;
qse_size_t rem;
2008-04-25 08:25:47 +00:00
if (n <= 0) return dst;
2008-12-21 21:35:07 +00:00
d = (qse_byte_t*)dst;
2008-04-25 08:25:47 +00:00
2008-04-25 07:21:17 +00:00
rem = IS_UNALIGNED(dst);
if (rem > 0)
{
2008-12-21 21:35:07 +00:00
do { *d++ = (qse_byte_t)val; }
while (n-- > 0 && ++rem < QSE_SIZEOF(qse_size_t));
2008-04-25 07:21:17 +00:00
}
2008-12-21 21:35:07 +00:00
if (n >= QSE_SIZEOF(qse_size_t))
2008-04-25 07:21:17 +00:00
{
2008-12-21 21:35:07 +00:00
qse_size_t* u = (qse_size_t*)d;
qse_size_t uv = 0;
2008-04-25 06:19:44 +00:00
int i;
if (val != 0)
{
2008-12-21 21:35:07 +00:00
for (i = 0; i < QSE_SIZEOF(qse_size_t); i++)
uv = (uv << 8) | (qse_byte_t)val;
2008-04-25 06:19:44 +00:00
}
2008-12-21 21:35:07 +00:00
QSE_ASSERT (IS_ALIGNED(u));
2008-04-25 07:34:17 +00:00
do
2008-04-25 06:19:44 +00:00
{
*u++ = uv;
2008-12-21 21:35:07 +00:00
n -= QSE_SIZEOF(qse_size_t);
2008-04-25 06:19:44 +00:00
}
2008-12-21 21:35:07 +00:00
while (n >= QSE_SIZEOF(qse_size_t));
2008-04-25 06:19:44 +00:00
2008-12-21 21:35:07 +00:00
d = (qse_byte_t*)u;
}
2008-12-21 21:35:07 +00:00
while (n-- > 0) *d++ = (qse_byte_t)val;
return dst;
2008-04-25 07:08:14 +00:00
2008-04-25 06:19:44 +00:00
#endif
}
2008-12-21 21:35:07 +00:00
int qse_memcmp (const void* s1, const void* s2, qse_size_t n)
{
2008-12-21 21:35:07 +00:00
#if defined(QSE_BUILD_FOR_SIZE)
2007-12-29 06:39:01 +00:00
2008-12-21 21:35:07 +00:00
const qse_byte_t* b1 = (const qse_byte_t*)s1;
const qse_byte_t* b2 = (const qse_byte_t*)s2;
2008-04-25 06:19:44 +00:00
while (n-- > 0)
{
if (*b1 != *b2) return *b1 - *b2;
b1++; b2++;
}
return 0;
2008-04-26 01:01:05 +00:00
#elif defined(__SPU__)
2008-12-21 21:35:07 +00:00
const qse_byte_t* b1;
const qse_byte_t* b2;
2008-04-26 01:01:05 +00:00
if (n >= SPU_VUC_SIZE &&
2008-12-21 21:35:07 +00:00
(((qse_size_t)s1) & (SPU_VUC_SIZE-1)) == 0 &&
(((qse_size_t)s2) & (SPU_VUC_SIZE-1)) == 0)
2008-04-26 01:01:05 +00:00
{
2008-04-26 02:57:55 +00:00
vector unsigned char* v1 = (vector unsigned char*)s1;
vector unsigned char* v2 = (vector unsigned char*)s2;
vector unsigned int tmp;
2008-04-26 01:01:05 +00:00
do
{
2008-04-26 02:57:55 +00:00
unsigned int cnt;
unsigned int pat;
2008-04-26 03:18:57 +00:00
/* compare 16 chars at one time */
2008-04-26 02:57:55 +00:00
tmp = spu_gather(spu_cmpeq(*v1,*v2));
2008-04-26 03:18:57 +00:00
/* extract the bit pattern */
pat = spu_extract(tmp, 0);
/* invert the bit patterns */
2008-04-26 02:57:55 +00:00
pat = 0xFFFF & ~pat;
2008-04-26 03:18:57 +00:00
/* put it back to the vector */
2008-04-26 02:57:55 +00:00
tmp = spu_insert (pat, tmp, 0);
2008-04-26 03:18:57 +00:00
/* count the leading zeros */
2008-04-26 02:57:55 +00:00
cnt = spu_extract(spu_cntlz(tmp),0);
2008-04-26 03:18:57 +00:00
/* 32 leading zeros mean that
* all characters are the same */
2008-04-26 02:57:55 +00:00
if (cnt != 32)
2008-04-26 02:06:58 +00:00
{
2008-04-26 03:18:57 +00:00
/* otherwise, calculate the
* unmatching pointer address */
2008-12-21 21:35:07 +00:00
b1 = (const qse_byte_t*)v1 + (cnt - 16);
b2 = (const qse_byte_t*)v2 + (cnt - 16);
2008-04-26 02:06:58 +00:00
break;
}
2008-04-26 01:01:05 +00:00
v1++; v2++;
n -= SPU_VUC_SIZE;
2008-04-26 02:06:58 +00:00
if (n < SPU_VUC_SIZE)
{
2008-12-21 21:35:07 +00:00
b1 = (const qse_byte_t*)v1;
b2 = (const qse_byte_t*)v2;
2008-04-26 02:06:58 +00:00
break;
}
2008-04-26 01:01:05 +00:00
}
2008-04-26 02:06:58 +00:00
while (1);
2008-04-26 01:01:05 +00:00
}
else
{
2008-12-21 21:35:07 +00:00
b1 = (const qse_byte_t*)s1;
b2 = (const qse_byte_t*)s2;
2008-04-26 01:01:05 +00:00
}
while (n-- > 0)
{
if (*b1 != *b2) return *b1 - *b2;
b1++; b2++;
}
return 0;
2008-04-25 06:19:44 +00:00
#else
2008-12-21 21:35:07 +00:00
const qse_byte_t* b1;
const qse_byte_t* b2;
2008-04-25 06:19:44 +00:00
2008-12-21 21:35:07 +00:00
if (n >= QSE_SIZEOF(qse_size_t) && IS_BOTH_ALIGNED(s1,s2))
2008-04-25 06:19:44 +00:00
{
2008-12-21 21:35:07 +00:00
const qse_size_t* u1 = (const qse_size_t*)s1;
const qse_size_t* u2 = (const qse_size_t*)s2;
2008-04-25 06:19:44 +00:00
2008-04-25 07:34:17 +00:00
do
2008-04-25 06:19:44 +00:00
{
2008-04-25 06:33:26 +00:00
if (*u1 != *u2) break;
2008-04-25 06:19:44 +00:00
u1++; u2++;
2008-12-21 21:35:07 +00:00
n -= QSE_SIZEOF(qse_size_t);
2008-04-25 06:19:44 +00:00
}
2008-12-21 21:35:07 +00:00
while (n >= QSE_SIZEOF(qse_size_t));
2008-04-25 06:33:26 +00:00
2008-12-21 21:35:07 +00:00
b1 = (const qse_byte_t*)u1;
b2 = (const qse_byte_t*)u2;
2008-04-25 06:19:44 +00:00
}
else
{
2008-12-21 21:35:07 +00:00
b1 = (const qse_byte_t*)s1;
b2 = (const qse_byte_t*)s2;
2008-04-25 06:19:44 +00:00
}
2007-12-29 06:39:01 +00:00
2008-04-25 06:19:44 +00:00
while (n-- > 0)
2007-12-29 06:39:01 +00:00
{
2008-04-25 06:19:44 +00:00
if (*b1 != *b2) return *b1 - *b2;
b1++; b2++;
2007-12-29 06:39:01 +00:00
}
return 0;
2008-04-25 06:19:44 +00:00
#endif
}
2008-04-26 22:58:10 +00:00
2008-12-21 21:35:07 +00:00
void* qse_memchr (const void* s, int val, qse_size_t n)
2008-04-26 22:58:10 +00:00
{
2008-12-21 21:35:07 +00:00
const qse_byte_t* x = (const qse_byte_t*)s;
2008-04-26 22:58:10 +00:00
while (n-- > 0)
{
2008-12-21 21:35:07 +00:00
if (*x == (qse_byte_t)val) return (void*)x;
2008-04-26 22:58:10 +00:00
x++;
}
2008-12-21 21:35:07 +00:00
return QSE_NULL;
2008-04-26 22:58:10 +00:00
}
2008-12-21 21:35:07 +00:00
void* qse_memrchr (const void* s, int val, qse_size_t n)
2008-04-26 22:58:10 +00:00
{
2008-12-21 21:35:07 +00:00
const qse_byte_t* x = (qse_byte_t*)s + n - 1;
2008-04-26 22:58:10 +00:00
while (n-- > 0)
{
2008-12-21 21:35:07 +00:00
if (*x == (qse_byte_t)val) return (void*)x;
2008-04-26 22:58:10 +00:00
x--;
}
2008-12-21 21:35:07 +00:00
return QSE_NULL;
2008-04-26 22:58:10 +00:00
}
2008-12-21 21:35:07 +00:00
void* qse_memmem (const void* hs, qse_size_t hl, const void* nd, qse_size_t nl)
2008-04-26 22:58:10 +00:00
{
if (nl <= hl)
{
2008-12-21 21:35:07 +00:00
qse_size_t i;
const qse_byte_t* h = (const qse_byte_t*)hs;
2008-04-26 22:58:10 +00:00
for (i = hl - nl + 1; i > 0; i--)
{
2008-12-21 21:35:07 +00:00
if (qse_memcmp(h, nd, nl) == 0) return (void*)h;
2008-04-26 22:58:10 +00:00
h++;
}
}
2008-12-21 21:35:07 +00:00
return QSE_NULL;
2008-04-26 22:58:10 +00:00
}
2008-12-21 21:35:07 +00:00
void* qse_memrmem (const void* hs, qse_size_t hl, const void* nd, qse_size_t nl)
2008-04-26 22:58:10 +00:00
{
if (nl <= hl)
{
2008-12-21 21:35:07 +00:00
qse_size_t i;
const qse_byte_t* h;
2008-04-26 22:58:10 +00:00
/* things are slightly more complacated
* when searching backward */
if (nl == 0)
{
/* when the needle is empty, it returns
* the pointer to the last byte of the haystack.
2008-12-21 21:35:07 +00:00
* this is because qse_memmem returns the pointer
2008-04-26 22:58:10 +00:00
* to the first byte of the haystack when the
* needle is empty. but I'm not so sure if this
* is really desirable behavior */
2008-12-21 21:35:07 +00:00
h = (const qse_byte_t*)hs + hl - 1;
2008-04-26 22:58:10 +00:00
return (void*)h;
}
2008-12-21 21:35:07 +00:00
h = (const qse_byte_t*)hs + hl - nl;
2008-04-26 22:58:10 +00:00
for (i = hl - nl + 1; i > 0; i--)
{
2008-12-21 21:35:07 +00:00
if (qse_memcmp(h, nd, nl) == 0) return (void*)h;
2008-04-26 22:58:10 +00:00
h--;
}
}
2008-12-21 21:35:07 +00:00
return QSE_NULL;
2008-04-26 22:58:10 +00:00
}
2008-12-21 21:35:07 +00:00
static void* mmgr_alloc (void* data, qse_size_t n)
{
return malloc (n);
}
2008-12-21 21:35:07 +00:00
static void* mmgr_realloc (void* data, void* ptr, qse_size_t n)
{
return realloc (ptr, n);
}
2008-08-21 02:22:07 +00:00
static void mmgr_free (void* data, void* ptr)
{
free (ptr);
}
2008-12-21 21:35:07 +00:00
static qse_mmgr_t mmgr =
{
2008-08-21 02:22:07 +00:00
mmgr_alloc,
mmgr_realloc,
mmgr_free,
2008-12-21 21:35:07 +00:00
QSE_NULL
};
2008-12-21 21:35:07 +00:00
qse_mmgr_t* qse_mmgr = &mmgr;