Re: [Libclc-developers] CLC_FAST & clc_ultostr (Was: new function: clc_strrev)
Status: Planning
Brought to you by:
augestad
|
From: Hallvard B F. <h.b...@us...> - 2003-03-27 23:17:30
|
Bj=F8rn Augestad writes:
>Hallvard B Furuseth wrote:
>> Bj=F8rn Augestad writes:
>=20
>>>Speaking of optimizations, any opinions on code like this?
>>>
>>>int clc_ultostr(char *ptr, size_t size, unsigned long num, int base)
>>>{
>>> const char *sym =3D "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
>>> char* sp;
>>>
>>>#ifdef CLC_FAST
>>> if(base =3D=3D 2) { (...) return num =3D=3D 0; }
>>>#endif
>>> .... /* regular version goes here */
>>>}
>>=20
>>=20
>> Since the _whole_ base2 function is special-cased, I think it's better
>> to provide a separate base2 function. Then the library still gets
>> bigger like you say, but not the application using it.
>=20
> Hmm. A separate base2 function means that the user must call different
> functions depending on the speed/size tradeoff he's willing to make. We
> discussed the concept of CLC_FAST early in the project, where the
> intention of CLC_FAST was to allow for speedier implementations if the
> user/builder of libclc wanted that.
Sorry, I forgot about that. Yes, I think that may be a good idea if we
implement CLC_FAST. I'm not sure if CLC_FAST is a good idea though...
> I used base2 as an easy-to-implement example, pretty sure that if the
> idea catches on, others can provide optimizations for e.g. base 16.
Here is one which covers all power-of-2 bases.
In the case of base 2, it's 10-20% slower than hardcoded base 2 on
Solaris, I think that's acceptable.
BTW, your claim that CLC_FAST is 4 times as fast as without CLC_FAST
depends on how large NUM is. With NUM=3D0, this function is 15% faster,
with random NUM, 50% faster on Solaris.
Anyway, shall I check it in? We can always take CLC_FAST out later
if c.l.c doesn't like it.
int clc_ultostr(char *ptr, size_t size, unsigned long num, int base)
{
const char *sym =3D "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char *sp;
clc_assert_not_null(clc_ultostr, ptr);
clc_assert_arg(clc_ultostr, size > 1);
clc_assert_arg(clc_ultostr, base >=3D 2 && base <=3D 36);
--size;
sp =3D ptr;
#ifdef CLC_FAST
if((base & (base-1)) =3D=3D 0) {
static const unsigned int log[] =3D { 1,2,3,0, 4,0,0,0, 5 };
unsigned int shift =3D log[base / 4];
unsigned int mask =3D base - 1U;
do {
*sp++ =3D sym[num & mask];
num >>=3D shift;
} while(num && --size);
}
else
#endif /* CLC_FAST */
{
do {
*sp++ =3D sym[num % base];
num /=3D base;
} while (num && --size);
}
*sp =3D '\0';
clc_memrev(ptr, sp-ptr);
return !num;
}
> What if we add clc_ltostr(), clc_lltostr(), clc_itostr() and
> clc_ulltostr() for other integer types?
Not clc_itostr() I hope. clc_ltostr() can handle that. As for
clc_{u}lltostr(), I guess that depends on whether or not we want to add
a bunch of long long functions when compiled with C99 compilers.
--=20
Hallvard
|