On Monday, 16 June 2014 at 19:42:14 UTC, Mike wrote:
I have refactored the code as recommended.

I have also modified the not-yet-reviewed writers part to take advantage of the same approach (preallocated static-sized buffer) rather than allocate slices in loops.

Hoping to hear something from you guys!

Best,
Mike

https://github.com/emesx/TGA/blob/develop/source/tga/model/utils.d#L80

Fully qualified names are only necessary when there's a name conflict. The std.algorithm can be removed.


https://github.com/emesx/TGA/blob/develop/source/tga/model/utils.d#L8

It's a shame the result of among can't be returned directly but casts are terribly heavy handed. They're best reserved for when you're poking holes in the type system ;)

For safe conversions use to!something:

return to!bool(isColorMapped(header)
                        ? header.colorMapDepth.among(16, 32)
                        : header.pixelDepth.among(16, 32));


https://github.com/emesx/TGA/blob/develop/source/tga/model/utils.d#L29

This one depends on taste, but these helpers can be eliminated by changing the Header definition a little. It's the same union / anonymous struct trick from the previous post, only this time with bitfields:

http://dpaste.dzfl.pl/13258b0ce0c4


https://github.com/emesx/TGA/blob/develop/source/tga/model/utils.d#L92

Hashtable lookup would indeed be nice here, but if you ever need a linear lookup it's included in std.algorithm:

http://dlang.org/library/std/algorithm/countUntil.html

const index = colorMap.countUntil(pixel);
enforce(index >= 0, "Pixel color not found in color map: " ~ pixel.text);
return index.to!ushort;

Note the use of to!ushort to avoid the cast. to!ushort also performs overflow checking.


https://github.com/emesx/TGA/blob/develop/source/tga/model/validation.d#L52

This is one of the many places where the allowed bitdepths are enumerated in an array / among(). Putting the allowed bitdepths in an enum has some advantages: use of '.max' for buffer sizes, EnumMembers in conjunction with among and only, to! checking for correctness... Some examples here:

http://dpaste.dzfl.pl/30d2a593468f

But it depends on your taste. Personally I prefer to use strong typing like this whenever possible. Helps to find bugs earlier, and makes maintenance easier when your software and data format are still in flux.


https://github.com/emesx/TGA/blob/develop/source/tga/model/validation.d#L39

This should be checked both ways. The current method will not detect an error when the image type is not mapped but a color map is present. At least I assume that is not a valid TGA file?

enforce(header.colorMapDepth.among(EnumMembers!ColorMapDepth));
enforce(header.isColorMapped == (header.colorMapType == ColorMapType.PRESENT)); enforce(header.isColorMapped == (header.colorMapDepth != ColorMapDepth.BPP0));


https://github.com/emesx/TGA/blob/develop/source/tga/io/readers.d#L95

You could change this to

foreach(ref pixel; pixels)
{
  pixel = ...
}


https://github.com/emesx/TGA/blob/develop/source/tga/io/readers.d#L165

Readability can be improved using the union + bitfields thingy. It's a bit longer but much easier on the eyes IMO:

http://dpaste.dzfl.pl/77ecbafa1e0e


https://github.com/emesx/TGA/blob/develop/source/tga/io/writers.d#L23

The with statement can be used here:

with(image.header)
{
  write(file, idLength);
  ...
}


I think this is everything I can come up with. The writeCompressed function can probably be simplified using std.algorithm but it's not straightforward. I'll need to ponder it for a while.

Reply via email to