Covert a complex C header to D

Nicholas Wilson via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sun Apr 2 16:49:38 PDT 2017


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


More information about the Digitalmars-d-learn mailing list