www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Please take a look

reply bearophile <bearophileHUGS lycos.com> writes:
Content-Type: text/plain

I have implemented a struct, with methods, able to manage 24-bit unsigned
integers. They are slower than an uint, so they may be useful only in quite
uncommon situations when you must save RAM.
In the attach you can find a stripped down version where I have removed
unittests, speed tests, most Ddoc comments, etc. Now I know some D, but surely
there are *lot* of things I know little about still (about memory management,
operator overloading, casting, the best way to use the CPU, etc). If you have a
bit of free time can you please take a look at that code in attach and tell me
if you like it, if you can see some things that can be done in a better way in
D, in a faster way, more D-onic, if you can solve some of the little problems
you can find in the comments, etc.

Bye and thank you,
bearophile
Dec 20 2007
parent reply Lukas Pinkowski <Lukas.Pinkowski web.de> writes:
bearophile wrote:

 I have implemented a struct, with methods, able to manage 24-bit unsigned
 integers. They are slower than an uint, so they may be useful only in
 quite uncommon situations when you must save RAM. In the attach you can
 find a stripped down version where I have removed unittests, speed tests,
 most Ddoc comments, etc. Now I know some D, but surely there are *lot* of
 things I know little about still (about memory management, operator
 overloading, casting, the best way to use the CPU, etc). If you have a bit
 of free time can you please take a look at that code in attach and tell me
 if you like it, if you can see some things that can be done in a better
 way in D, in a faster way, more D-onic, if you can solve some of the
 little problems you can find in the comments, etc.
 
 Bye and thank you,
 bearophile

Taking a look at it, I see, you've done the following: uint opCast() { //return (up << 16) | low; // worse? return *(cast(uint*)(cast(void*)this)); } You really should uncomment the first line and remove the second, since uint* is a pointer to a 4-byte type, while your struct holds 3 bytes. Thus dereferencing the uint* will lead to a 4th byte with an arbitrary value and finally to errors.
Dec 21 2007
parent reply bearophile <bearophileHUGS lycos.com> writes:
Lukas Pinkowski:
Taking a look at it, I see, you've done the following:
 
 uint opCast() {
     //return (up << 16) | low; // worse?
     return *(cast(uint*)(cast(void*)this));
 }

 You really should uncomment the first line and remove the second, since
 uint* is a pointer to a 4-byte type, while your struct holds 3 bytes.
 Thus dereferencing the uint* will lead to a 4th byte with an arbitrary
 value and finally to errors.

I belive you; code similar to that ( (up << 16) | low ) was the first thing I have written. The funny thing is that (before posting the code on this newsgroup) I have written almost 200 lines of testing code along the code for those 24 bit unsigned integers, and they have failed catching the bug you talk about :-] This other piece of testing code too fails spotting the problem: import std.random, u24; int randInt(int max) { int k, n; n = max + 1; k = cast(int)(n * (rand / (uint.max + 1.0))); return (k == n) ? k - 1 : k; } void main() { Uint24[200_000] arr; assert(arr.sizeof == 200_000*3); rand_seed(10, 0); foreach(ref u; arr) u = randInt(Uint24.max); rand_seed(10, 0); foreach(i, u; arr) assert(u == randInt(Uint24.max)); } Eventually I'll probably put back code like that ( (up << 16) | low ) because I must write safe code (despite being slower) but so far I have failed finding testcases that make that double casting fail :-) Can you show me an example where if shows the bug? Bye and thank you, bearophile
Dec 22 2007
parent Lukas Pinkowski <Lukas.Pinkowski web.de> writes:
bearophile wrote:
 Can you 
 show me an example where if shows the bug?

int main(char[][] args) { Uint24[4] array; array[0] = 0xffffff; array[1] = 0x000000; array[2] = 0xeeeeee; array[3] = 0xffffff; uint a = array[0].val; uint b = array[1].val; uint c = array[2].val; Stdout.formatln( "{:x}", a ); Stdout.formatln( "{:x}", b ); Stdout.formatln( "{:x}", c ); assert( a == 0x00ffffff ); assert( b == 0x00000000 ); assert( c == 0x00ffffff ); return 0; } Executing gives: ffffff ee000000 ffeeeeee tango.core.Exception.AssertException bug24(62): Assertion failure As you see, taking the value of one array element will return the Uint24 value + the first byte of the next array element (shifted 24bits to the left). (the first is correct because 0xffffff + (0x000000 << 24) is 0x00ffffff)
Dec 22 2007