On Sunday, 2 April 2017 at 21:43:52 UTC, biocyberman wrote:
khash.h (http://attractivechaos.github.io/klib/#Khash%3A%20generic%20hash%20table) is a part of klib library in C. I want to covert it to D in the process of learning deeper about D.

First I tried with Dstep (https://github.com/jacob-carlborg/dstep) and read the C to D article (https://dlang.org/ctod.html). I managed to covert the basic statements to D, but all multiline 'define' macros are stripped off. So I am trying to recreate them with D way. For example:


#define __KHASH_TYPE(name, khkey_t, khval_t) \
        typedef struct kh_##name##_s { \
                khint_t n_buckets, size, n_occupied, upper_bound; \
                khint32_t *flags; \
                khkey_t *keys; \
                khval_t *vals; \
        } kh_##name##_t;


I changed to:

template __KHASH_TYPE(string name){
  "struct  kh_" ~ name ~"_t { " ~
"khint_t n_buckets, size, n_occupied, upper_bound; " ~
                "khint32_t *flags; " ~
                "khkey_t *keys; " ~
                "khval_t *vals; " ~
        "}"

}

// NEXT: use mixin with this template.

I am currently get a bit intimidated looking at KHASH_INIT2 macro in khash.c. How do I convert this to the equivalent and idiomatic D?

You are on the right track, converting #define's that declare symbols to template strings to be mixed in. But you also need to parameterise the key type and the value type as they are also arguments to the macro.

so you'd go

mixin( __KHASH_TYPE("mytype",string, int));

However it is generally considered better to use templates where possible as they are generally astir to reason about (and look nicer). Since this is a relatively simple case we could just go:

struct kh_hashtable_t(string name,K,V) {
//kh_hashtable_t is a struct parameterised on the types K and V
    khint_t n_buckets, size, n_occupied, upper_bound;
    khint32_t *flags;
     K *keys;
     V *vals;
}
and not worry about "name", the compiler will generate an internal name for us. Doesn't matter what it is, but it is guaranteed to be unique which is the main property we want. We probably don't even need the nam parameter at all.

(there is also the builtin hash table declared V[K] e.g. int[string] i.e. a hash table of ints indexed by strings.).

So for KHASH_INIT2:

the argument to the macro are
    name: a string
scope: a protection modifier (in C they use static inline, in D this would be pragma(inline, true) private. But I would ignore this parameter.
    khkey_t: the key type
    khval_t: the value type
    kh_is_map: a bool (not sure of its purpose).
    __hash_func: the function used to generate a hash from the key
   __hash_equal:

so you'd want something like

template KHASH_INIT(string name,K,V,bool kh_is_map, alias keyhash, alias equal = (V a , V b) => a==b)
{
    //...
}

where K and V are types, "alias keyhash" is a function that transforms a key into a hash and alias equal is a function that deternimes if two values(keys?) are equal.

you'd call it like
KHASH_INIT!("some_name",string,int,true, (string a) => myFancyHash(a) /* leave equal as a default*/);

Let me know if you get stuck.
Nic

Reply via email to