Search code examples
d

custom alignment options for an efficient quad edge implementation


I'm fairly new to the D2 programming language. I need to implement a quad edge data structure. This is an adjacency data structure for effective graph embeddings and their duals. From previous experience with C, I started with the following implementation:

struct edge(T) {
    edge* next;
    T* data;
    uint position;
}
alias edge[4] qedge;
edge* new_edge() {
    qedge* q = new qedge; // does not compile, just analogous
    // initialize the four edges (q[i].position = i)
    return cast (edge*) q;
}

That works fine, but this position field is bugging me - it is just wasting space there. Is there a way to align to a (8 * ${machine word size}) boundary when allocating the memory for the qedge array (then I will not need the additional position field, because the information at which position an edge is in the qedge array will be encoded into the edge address)?

I'm aiming at an efficient and cute implementation (that's why I've chosen D), so any other suggestions are welcome.

EDIT: Here is a piece of code to make the thing more clear http://dpaste.dzfl.pl/e26baaad:

module qedge;

class edge(T) {
    edge next;
    T* data;
}

alias edge!int iedge;
alias iedge[4] qedge;

import std.stdio;
import std.c.stdlib;

void main() {
    writeln(iedge.sizeof); // 8
    writeln(qedge.sizeof); // 32
    // need something for the next line, 
    // which always returns an address, divisible by 32
    qedge* q = cast (qedge*) malloc(qedge.sizeof);
    writeln(q); // ex. 0x10429A0 = 17050016, which is, does not start at 32-byte boundary
}

Solution

  • To directly answer the question - use the align(N) to specify the alignment you want. However, keep this in mind (quote from dlang.org): Do not align references or pointers that were allocated using NewExpression on boundaries that are not a multiple of size_t

    Reference manual at http://dlang.org has a section about alignment - http://dlang.org/attribute.html#align .

    Say, the T is int - the edge!int is already 24 bytes big on 64-bit architecture. D is not so different from C in alignment. Check the following (runnable/editable code at: http://dpaste.dzfl.pl/de0121e1):

    module so_0001;
    // http://stackoverflow.com/questions/11383240/custom-alignment-options-for-an-efficient-quad-edge-implementation
    
    struct edge(T) {
        edge* next;
        T* data;
        uint position;
    }
    alias edge!int iedge;
    alias edge!int[4] qedge;
    
    /* not a good idea for struct... it is a value type...
    edge!int new_edge() {
        // in the original example it used new... D is not C++ to mix value and reference types! :)
    }
    */
    
    import std.stdio;
    
    int main() {
        writeln(iedge.sizeof);
    
        //                                   64bit
        //                                ----------
        writeln(iedge.next.offsetof);     // 0
        writeln(iedge.data.offsetof);     // 8
        writeln(iedge.position.offsetof); // 16
        writeln(qedge.sizeof);
        return 0;
    }