On Monday, 9 May 2016 at 06:35:36 UTC, rikki cattermole wrote:
On 09/05/2016 6:22 PM, Hildigard Sandyman wrote:
It's true but... why do you bother with IAllocator ? Everything can be set a compile time with a template parameter. As long as the param is a struct with allocate/deallocate/reallocate it's OK. you can use already
a good part of the package content in a @nogc fashion.

Do you have an example where IAllocator must be used and where, for
example, Mallocator can't be passed ?!

The moment where you need to use OOP, you most definitely need IAllocator.
I cannot make a windowing library without the use of IAllocator.

You can't always template functions with the type that is the allocator.
Its just not possible or reasonable.

You don't need OOP for neither windowing, nor image abstraction. None of the OS APIs require it. I haven't considered using classes for my projects for more than a year, because D offers much better ways to solve most problems and cuz programming in a Java-like way just sucks. Functions that require memory allocation should take alias allocator template parameters. And everything should be templated for maximum flexibility!

For example, instead writing Image interfaces/classes or even structs, just offer a couple of free functions that convert from .bmp/.png/.jpg/ etc. to ndslice and back.

For example:

/**
 * Automatically determines the image format and reads the
 * image in memory by converting each pixel to `ColorType`.
 * Internally calls readImage!(ImageFormat.png) /
 * readImage!(ImageFormat.bmp / etc. depending on
 * the deduced image format.
 *
 * If the underlying `allocator` is `MmapAllocator`, it maps
 * the file into memory, instead of copying it.
 *
 * Parameters:
 *     file_path = string input range specifying location
 *                 of the image to be read
 *
 * Returns:
 *    `Slice!(N, RandAccessR!ColorType)` where `N` is >= 2.
 *    (All images are conceptually two dimensional, but may
 *    be internally divided into blocks).
 */
auto readImage(ColorType, alias allocator = GCAllocator.instance, R)(R file_path)
    if (isStringRange!R && isColor!ColorType &&
        is(typeof(allocatorInstance!allocator)));

// example 1 - image manipulation
unittest
{
    auto tinyAlloc = StackAllocator!256();
    auto imgAlloc = ScopedAllocator!MmapAllocator;
    alias C = Color!(ColorFormat.RGBA8);

    auto images =
        ["./img1.jpg", "../images/img2.png", "./mask.bmp"]
        .map!(path => path.readImage!(C, imgAlloc))
        .array!tinyAlloc; // force eager evaluation

    auto result = makeSlice!C(imgAlloc, image[0].shape);

    auto xyzo_slice = lockstep(aliasSeqOf!images, result);

    xyzo_slice.each!((in ref x, in ref y, in ref y, ref o) =>
               o = (x + y) * z)();

    result.writeImage!(ImageFormat.png)("./output.png");

    // All allocated memory is freed at the end of the scope.
}

// example 2 - image viewer
void main(string[] args)
{
    enforce(args.length == 2, "Usage: imgshow <image-path>");
    enforce(exists(args[1], "%s doesn't exist".format(args[1]));

    auto imgAllocator = ScopedAllocator!MmapAllocator;
    auto uiAllocator = ScopedAllocator!Mallocator;
    alias C = Color!(ColorFormat.RGBA8);
    auto img = readImage!(C, imgAllocator)(args[1]);

    // I don't think you need heap allocations for basic stuff
// with Win32 but still I'm not familiar with every API out there.
    // `window` is RAII struct that should manage GUI resources
    // as needed.
    auto window = createWindowWithImage!uiAllocator(img);
    bool running = true;

    window.show.enterEventLoop!(
        (QuitEvent q) { running = false; },
        (ResizeEvent r) => false /* do not allow resizing */
        (MouseClick m) /* color picker */
            { writefln("pixel at [%s, %s] is %s",
                  m.coords.expand, img[m.coords]); }
        /* ignore other events */
    )(&running);
}

See, no classes or interfaces were harmed during the making of those examples :D




Reply via email to