Thread overview
Re: C(/C++) interoperability
Mar 22, 2003
Matthew Wilson
Mar 22, 2003
Ilya Minkov
Mar 22, 2003
Matthew Wilson
Mar 24, 2003
Walter
Mar 25, 2003
Matthew Wilson
Mar 25, 2003
Walter
Mar 25, 2003
Luna Kid
Apr 03, 2003
Walter
March 22, 2003
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.


March 22, 2003
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.

March 22, 2003
"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
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.
>

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.
>


March 24, 2003
"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
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.

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);
...
----------------------------


March 25, 2003
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
> 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.
>
> 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);
> ...
> ----------------------------
>
>


March 25, 2003
"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.


March 25, 2003
> > 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.


He wanted using C++, IIRC.

Sab


April 03, 2003
"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.