www.digitalmars.com         C & C++   DMDScript  

D - Re: C(/C++) interoperability

reply "Matthew Wilson" <dmd synesis.com.au> writes:
I'm not sure I'm expressing myself correctly here.

I want to write a set of functions in C++, that are importable as D, and
which create and operate on D types. Specifically, I want to create the
following D functions:

char[] integer_to_string(bit value);
char[] integer_to_string(byte value);
char[] integer_to_string(ubyte value);
char[] integer_to_string(short value);
char[] integer_to_string(ushort value);
char[] integer_to_string(int value);
char[] integer_to_string(uint value);
char[] integer_to_string(long value);
char[] integer_to_string(ulong value);

and I want to implement in C++ such as the following (pseudo-code,
obviously):

D_array_char_t   _cdecl   integer_to_string(uint32_t value)
{
  D_array_char_t   result = create a D char array of 10 elements: enough for
"4294967295"

  do the conversion from value into result

  return result;
}

The issues I need to understand are:

1. what is D_array_char_t?
2. How do I allocate an instance of D_array_char_t?
3. How do I allocate the contents that D_array_char_t holds, the payload in
other words? (This assumes that D_array_char_t is a {length + pointer},
which Walter's earlier post indicates)
4. How to I delete it, or place it back in the GC, in the case where I don't
want it.

If this is not possible, then I'm going to have to either:

1. wrap the C/C++ equivalents of what I propose in D functions, which will
loose efficiency, or
2. have the functions return pointers to character arrays, which means (i)
requiring client D code do deal with C arrays not D ones (which seems more
than a little ugly), as well as (ii) complicating the implementation by
providing non-leaking thread-specific-storage within the functions.

Neither of these are attractive, especially since D has garbage collection
which, if usable, would make it all nice and simple, as well as super quick!

All info gratefully received.

Matthew

P.S. Any of you that are C/C++ User's Journal will no doubt recognise what I
plan to do from my December 2002 article "Efficient Integer To String
Conversions". I expect the performance gains described there to be almost
completely acheivable within what I'm proposing here.
Mar 21 2003
parent reply Ilya Minkov <midiclub 8ung.at> writes:
Array storage is described under "memory model" in documentation.

 P.S. Any of you that are C/C++ User's Journal will no doubt recognise what I
 plan to do from my December 2002 article "Efficient Integer To String
 Conversions". I expect the performance gains described there to be almost
 completely acheivable within what I'm proposing here.

I haven't read it, but ... isn't it also doable in D? If not, then why? So if the functions are not exactly huge, consider writing them directly in D. I have tried converting code from C: it doesn't take much time. As to allocating memory using garbage collector, i have looked at the library source. The garbage collector instance _gc is being initialised by gc_init() in gc2\gc.d, and you can call its allocator like "ptr = _gc.malloc(amount);" - from the D code. This is not gonna work from C. Generally, calling it doesn't make sense since you should use new operator in D code, and not rely onto obscure implementation details. It seems to me, that you should wrap the new operator into a extern(C) D function, and compile it with optimisations - hoping it gets everything inlined. -i.
Mar 22 2003
parent reply "Matthew Wilson" <dmd synesis.com.au> writes:
"Ilya Minkov" <midiclub 8ung.at> wrote in message
news:b5i75a$2pim$1 digitaldaemon.com...
 Array storage is described under "memory model" in documentation.

Thanks. Will check it out there. :)
 P.S. Any of you that are C/C++ User's Journal will no doubt recognise


 plan to do from my December 2002 article "Efficient Integer To String
 Conversions". I expect the performance gains described there to be


 completely acheivable within what I'm proposing here.

I haven't read it, but ... isn't it also doable in D? If not, then why? So if the functions are not exactly huge, consider writing them directly in D. I have tried converting code from C: it doesn't take much time.

I'm not sure whether D's template model will lend itself as readily. (I'm not saying it won't, I simply don't know.) Also, I don't what to have to do that. Simply, I don't want to repeat the considerable effort, when I could implement as I've described. More broadly, surely no-one doubts that this kind of requirement will become more and more prevalent? Even the execrably pointer-phobic Java provides the JNI for this interfacing when necessary. I guess my question can be simply boiled down to: Is the a D Native Interface? If not, can we have one? If not, how does D expect people to integrate very significant peices of C/C++/whatever code into D. There are tasks large enough that they would likely be dissuaded from using D if told they must port. And porting is not straightforward, and is *not* an error-proof exercise.
 As to allocating memory using garbage collector, i have looked at the
 library source. The garbage collector instance _gc is being initialised
 by gc_init() in gc2\gc.d, and you can call its allocator like "ptr =
 _gc.malloc(amount);" - from the D code. This is not gonna work from C.
 Generally, calling it doesn't make sense since you should use new
 operator in D code, and not rely onto obscure implementation details. It
 seems to me, that you should wrap the new operator into a extern(C) D
 function, and compile it with optimisations - hoping it gets everything
 inlined.

 -i.

Mar 22 2003
parent reply "Walter" <walter digitalmars.com> writes:
"Matthew Wilson" <dmd synesis.com.au> wrote in message
news:b5igaj$2vs5$1 digitaldaemon.com...
 More broadly, surely no-one doubts that this kind of requirement will

 more and more prevalent? Even the execrably pointer-phobic Java provides

 JNI for this interfacing when necessary. I guess my question can be simply
 boiled down to: Is the a D Native Interface? If not, can we have one? If
 not, how does D expect people to integrate very significant peices of
 C/C++/whatever code into D. There are tasks large enough that they would
 likely be dissuaded from using D if told they must port. And porting is

 straightforward, and is *not* an error-proof exercise.

I don't really understand the problem. D functions can be called from C by declaring the D function as extern (C). Then, it uses C calling conventions and name mangling: ----- foo.d ------------ extern (C) int myfunc(int x) { return x + 1; } ------ bar.c ------------ extern int myfunc(int x); ... i = myfunc(3); ... ----------------------------
Mar 24 2003
parent reply "Matthew Wilson" <dmd synesis.com.au> writes:
As I said in the earlier post, I want to do this

D_array_char_t   _cdecl   integer_to_string(uint32_t value)
{
  D_array_char_t   result = create a D char array of 10 elements: enough for
"4294967295"

  do the conversion from value into result

  return result;
}

The D functions I want are
 - allocate a char[] array
 - pass that same array back to the D GC if the logic of the C++ function
dictates that an error has occurred. (If this is not necesary, and the GC
automatically detects unused blocks, that's fine)

In an earlier post you said the array type looks like

struct Array
{
    int length;
    void *data;
};

so let's go with that.

Hence, in my C++ source I might want to do something like (of course, I
wouldn't use sprintf, but it suffices for this debate):

// fastconvert.cpp

extern "C" Array integer_to_string(uint32_t value)
{
  Array   result = _D_allocate_char_array(10);

  if(result.data != NULL)
  {
    sprintf(static_cast<char*>(result.data), "%d", value);
  }

  if(some condition or other)
  {
    _D_return_to_GC(result);
  }

  return result;
}

So the question is, what is _D_allocate_char_array() ? Can I simply do
something like

  Array   result;

  result.length = 10;
  result.data = _D_allocate(10);

in which case, my question is what is _D_allocate()?

Also, how do I declare integer_to_string() in the D file? Is it like

// fastconvert.d

module conversion;

char[] integer_to_string(uint value);

How does the linker know that the Array returned in C++ is the same as the
char[] in the D, and not, for example, byte[] or double[] or whatever?

This is further complicated by the fact that I want to provide 8 overloads
of integer_to_string (for the eight integral types), and want the
corresponding 8 D functions.

How can

extern "C" Array integer_to_string(sint8_t value)
extern "C" Array integer_to_string(uint8_t value)
extern "C" Array integer_to_string(sint16_t value)
extern "C" Array integer_to_string(uint16_t value)
extern "C" Array integer_to_string(sint32_t value)
extern "C" Array integer_to_string(uint32_t value)
extern "C" Array integer_to_string(sint64_t value)
extern "C" Array integer_to_string(uint64_t value)

be tied up to

char[] integer_to_string(byte value);
char[] integer_to_string(ubyte value);
char[] integer_to_string(short value);
char[] integer_to_string(ushort value);
char[] integer_to_string(int value);
char[] integer_to_string(uint value);
char[] integer_to_string(long value);
char[] integer_to_string(ulong value);

?


"Walter" <walter digitalmars.com> wrote in message
news:b5o2vk$k5u$1 digitaldaemon.com...
 "Matthew Wilson" <dmd synesis.com.au> wrote in message
 news:b5igaj$2vs5$1 digitaldaemon.com...
 More broadly, surely no-one doubts that this kind of requirement will

 more and more prevalent? Even the execrably pointer-phobic Java provides

 JNI for this interfacing when necessary. I guess my question can be


 boiled down to: Is the a D Native Interface? If not, can we have one? If
 not, how does D expect people to integrate very significant peices of
 C/C++/whatever code into D. There are tasks large enough that they would
 likely be dissuaded from using D if told they must port. And porting is

 straightforward, and is *not* an error-proof exercise.

I don't really understand the problem. D functions can be called from C by declaring the D function as extern (C). Then, it uses C calling

 and name mangling:

 ----- foo.d ------------

 extern (C) int myfunc(int x) { return x + 1; }

 ------ bar.c ------------

 extern int myfunc(int x);

 ...
     i = myfunc(3);
 ...
 ----------------------------

Mar 24 2003
parent reply "Walter" <walter digitalmars.com> writes:
"Matthew Wilson" <dmd synesis.com.au> wrote in message
news:b5o751$ne7$1 digitaldaemon.com...
 So the question is, what is _D_allocate_char_array() ? Can I simply do
 something like

   Array   result;

   result.length = 10;
   result.data = _D_allocate(10);

 in which case, my question is what is _D_allocate()?

Create a function in D: extern (C) void *_D_allocate(int i) { return new byte[i]; } and then call _D_allocate(10) from your C code.
 Also, how do I declare integer_to_string() in the D file? Is it like

 // fastconvert.d

 module conversion;

 char[] integer_to_string(uint value);

 How does the linker know that the Array returned in C++ is the same as the
 char[] in the D, and not, for example, byte[] or double[] or whatever?

The linker has no concept of function return types. Therefore, like in C++, D functions are 'mangled' with the type info. If you run obj2asm on the .obj files, you'll see the mangling. However, C functions are not mangled, therefore C functions cannot be overloaded.
 This is further complicated by the fact that I want to provide 8 overloads
 of integer_to_string (for the eight integral types), and want the
 corresponding 8 D functions.

 How can

 extern "C" Array integer_to_string(sint8_t value)
 extern "C" Array integer_to_string(uint8_t value)
 extern "C" Array integer_to_string(sint16_t value)
 extern "C" Array integer_to_string(uint16_t value)
 extern "C" Array integer_to_string(sint32_t value)
 extern "C" Array integer_to_string(uint32_t value)
 extern "C" Array integer_to_string(sint64_t value)
 extern "C" Array integer_to_string(uint64_t value)

 be tied up to

 char[] integer_to_string(byte value);
 char[] integer_to_string(ubyte value);
 char[] integer_to_string(short value);
 char[] integer_to_string(ushort value);
 char[] integer_to_string(int value);
 char[] integer_to_string(uint value);
 char[] integer_to_string(long value);
 char[] integer_to_string(ulong value);

 ?

C does not support function overloading, therefore this cannot work. You'll have to give the functions different names.
Mar 25 2003
parent reply "Luna Kid" <lunakid neuropolis.org> writes:
 This is further complicated by the fact that I want to provide 8


 of integer_to_string (for the eight integral types), and want the
 corresponding 8 D functions.

 How can

 extern "C" Array integer_to_string(sint8_t value)
 extern "C" Array integer_to_string(uint8_t value)
 extern "C" Array integer_to_string(sint16_t value)
 extern "C" Array integer_to_string(uint16_t value)
 extern "C" Array integer_to_string(sint32_t value)
 extern "C" Array integer_to_string(uint32_t value)
 extern "C" Array integer_to_string(sint64_t value)
 extern "C" Array integer_to_string(uint64_t value)

 be tied up to

 char[] integer_to_string(byte value);
 char[] integer_to_string(ubyte value);
 char[] integer_to_string(short value);
 char[] integer_to_string(ushort value);
 char[] integer_to_string(int value);
 char[] integer_to_string(uint value);
 char[] integer_to_string(long value);
 char[] integer_to_string(ulong value);

 ?

C does not support function overloading, therefore this cannot work.

 have to give the functions different names.

He wanted using C++, IIRC. Sab
Mar 25 2003
parent "Walter" <walter digitalmars.com> writes:
"Luna Kid" <lunakid neuropolis.org> wrote in message
news:b5q0ef$1tes$1 digitaldaemon.com...
 He wanted using C++, IIRC.

Ok, but D doesn't support the C++ name mangling, so you're still back to providing different names.
Apr 03 2003