Thread overview
recursive template (first attempt)
Apr 20, 2006
akcom
Apr 20, 2006
Ryan Steen
Apr 20, 2006
akcom
Apr 20, 2006
Don Clugston
Apr 21, 2006
akcom
April 20, 2006
I apologize if this is an easily resolved problem, this is my first attempt at writing a template function.  the objective of this function is to mimic the behavior of the AP hash function, but as a template function obviously.  Here is what I have so far:

uint aphash( ubyte []buf )
{
	uint hash;

	for ( uint i = 0; i < buf.length; i++ )
	{
		hash ^= ((i & 1) == 0) ?	(  (hash <<  7) ^ (buf[i]) ^ (hash >> 3)) :
									(~((hash << 11) ^ (buf[i]) ^ (hash >> 5)));
	}
	return hash;
}

template aphasht( T : ubyte [] )
{
	uint aphasht( T t )
	{
		uint result;
		static if ( t.length == 0 )
		{
			return 0;
		}
		static if ( t.length & 1 )
		{
			result = aphasht( t[1..$] );
			return (result << 7) ^ t[0] ^ (result >> 3);
		}
		else
		{
			result = aphasht( t[1..$] );
			return (result << 11) ^ t[0] ^ (result >> 5);
		}
	}
}

void test()
{
	static ubyte []str = [ 0x01, 0x02, 0x03, 0x03 ];
	writefln( "aphash(str) = %X", aphash( str ) );
	writefln( "aphasht(str) = %X", aphasht!(ubyte [])( str ) );
}


When I attempt to compile it, I get the following errors:

dmd -w -c main.d
main.d(49): expression ((t).length) == 0u does not evaluate to a boolean
main.d(53): expression ((t).length) & 1u does not evaluate to a boolean
main.d(70): template instance main.aphasht!(ubyte[]) error instantiating

Could someone please point out my mistake, and if there is a more elegant way of completing this task, I'd appreciate some input on that as well.

Regards,
Alex
April 20, 2006
In article <e26v01$2m8$1@digitaldaemon.com>, akcom says...

>		static if ( t.length == 0 )
>		static if ( t.length & 1 )
>main.d(49): expression ((t).length) == 0u does not evaluate to a boolean
>main.d(53): expression ((t).length) & 1u does not evaluate to a boolean

"It is an error if AssignExpression ... cannot be evaluated at compile time."


April 20, 2006
Ryan Steen wrote:
> In article <e26v01$2m8$1@digitaldaemon.com>, akcom says...
> 
> 
>>		static if ( t.length == 0 )
>>		static if ( t.length & 1 )
>>main.d(49): expression ((t).length) == 0u does not evaluate to a boolean
>>main.d(53): expression ((t).length) & 1u does not evaluate to a boolean
> 
> 
> "It is an error if AssignExpression ... cannot be evaluated at compile time."
> 
> 
why can't it be computed at compile time if I make "str" static/const?
April 20, 2006
akcom wrote:
> Ryan Steen wrote:
>> In article <e26v01$2m8$1@digitaldaemon.com>, akcom says...
>>
>>
>>> 		static if ( t.length == 0 )
>>> 		static if ( t.length & 1 )
>>> main.d(49): expression ((t).length) == 0u does not evaluate to a boolean
>>> main.d(53): expression ((t).length) & 1u does not evaluate to a boolean
>>
>> "It is an error if AssignExpression ... cannot be evaluated at compile time."
>>
>>
> why can't it be computed at compile time if I make "str" static/const?

It's just because array literals are only supported at this time for strings. (Your code might work in DMD 2.0).

If you change the definitions to
const char [] str = x"01 02 03";

template aphasht( char [] T)
{
	const uint aphasht = ...
}
(changing returns to const aphasht).

it would work with

writefln( "aphasht(str) = %X", aphasht!(str ) );
April 21, 2006
Don Clugston wrote:
> akcom wrote:
> 
>> Ryan Steen wrote:
>>
>>> In article <e26v01$2m8$1@digitaldaemon.com>, akcom says...
>>>
>>>
>>>>         static if ( t.length == 0 )
>>>>         static if ( t.length & 1 )
>>>> main.d(49): expression ((t).length) == 0u does not evaluate to a
>>>> boolean
>>>> main.d(53): expression ((t).length) & 1u does not evaluate to a boolean
>>>
>>>
>>> "It is an error if AssignExpression ... cannot be evaluated at compile time."
>>>
>>>
>> why can't it be computed at compile time if I make "str" static/const?
> 
> 
> It's just because array literals are only supported at this time for strings. (Your code might work in DMD 2.0).
> 
> If you change the definitions to
> const char [] str = x"01 02 03";
> 
> template aphasht( char [] T)
> {
>     const uint aphasht = ...
> }
> (changing returns to const aphasht).
> 
> it would work with
> 
> writefln( "aphasht(str) = %X", aphasht!(str ) );

I finally got it working, but for some odd reason the templates gives different results than the original function when the string being processed has a length that is odd, any ideas?

uint aphash( char []buf )
{
	uint hash;

	hash = 0;
	for ( uint i = 0; i < buf.length; i++ )
	{
		hash ^= ((i & 1) == 0) ?	(  (hash <<  7) ^ (cast(ubyte)buf[i]) ^ (hash
>> 3)) :
									(~((hash << 11) ^ (cast(ubyte)buf[i]) ^ (hash >> 5)));
	}
	return hash;
}

template aphashT( char []s, uint lastHash = 0 )
{
	static if ( s.length == 0 )
	{
		const aphashT = lastHash;
	}
	else static if ( s.length & 1 )
	{
		const aphashT = aphashT!( s[1..$], lastHash ^ ~( (lastHash << 11) ^
cast(ubyte)(s[0]) ^ (lastHash >> 5) ) );
	}
	else
	{
		const aphashT = aphashT!( s[1..$], lastHash ^ ( (lastHash << 7) ^
cast(ubyte)(s[0]) ^ (lastHash >>3) ) );
	}
}

unittest
{
	assert( aphashT!( "aaa" ) == aphash( "aaa" ) ); //fails
	assert( aphashT!( "abcdefg12345" ) == aphash( "abcdefg12345" ) );
	assert( aphashT!( "rofl haxor" ) == aphash( "rofl haxor" ) );
	assert( aphashT!( "abc" ) == aphash( "abc" ) );
	assert( aphashT!( "hello world" ) == aphash( "hello world" ) ); //fails
}