Skip to content

Instantly share code, notes, and snippets.

@MartinNowak
Created November 24, 2011 16:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MartinNowak/1391734 to your computer and use it in GitHub Desktop.
Save MartinNowak/1391734 to your computer and use it in GitHub Desktop.
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
#include "array.hpp"
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
// This is header only, so we just need to create an empty compile unit.
#ifndef ARRAY_H
#define ARRAY_H
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
#include "d_new.hpp"
#include <iostream>
#include <typeinfo>
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
class Array
{
public:
Array()
: _length(100)
, _ptr(d_new<double>(_length))
{ std::cout << "Foo::Foo()" << std::endl; }
// destructor is called when being finalized
~Array()
{ std::cout << "Foo::~Foo()" << std::endl;}
virtual void printInfo()
{ std::cout << "typeid: " << typeid(Array).name() << " this:" << this << std::endl; }
virtual size_t length()
{ return _length; }
virtual double* ptr()
{ return _ptr; }
size_t _length;
double* _ptr;
};
//........................................................................................
Array* createArray()
{
return d_new<Array>();
}
#endif
module d_new;
import core.memory, std.conv;
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
alias extern(C) void function(void* p) CFinalizer;
enum Coffset = 2 * size_t.sizeof;
final class Finalizer
{
~this()
{
const func = cast(CFinalizer)(cast(void**)this)[1];
func(cast(void*)this + Coffset);
// clear the monitor slot
(cast(void**)this)[1] = null;
}
}
static assert(__traits(classInstanceSize, Finalizer) == Coffset);
//........................................................................................
extern(C) void* _d_new(size_t size, CFinalizer cfinalizer)
{
if (cfinalizer !is null)
{
auto p = GC.malloc(size + Coffset, GC.BlkAttr.FINALIZE);
emplace!Finalizer(p[0 .. Coffset]);
// using the monitor slot saves size_t.sizeof bytes
(cast(void**)p)[1] = cfinalizer;
return p + Coffset;
}
else
// assume only plain types
return GC.malloc(size, GC.BlkAttr.NO_SCAN);
}
#ifndef D_NEW_H
#define D_NEW_H
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
#include <new> // placement new
#include <cstring> // size_t, memset
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
namespace
{
template <bool b, typename T>
struct enable_if;
template <typename T>
struct enable_if<true, T>
{
typedef T type;
};
//........................................................................................
template <typename T>
struct is_class
{
struct A { char _[1]; };
struct B { char _[2]; };
template <class U> static A test(void(U::*)());
template <class U> static B test(...);
static const bool value = sizeof(test<T>(NULL)) == sizeof(A);
};
};
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
typedef void (*CFinalizer)(void*);
extern "C"
{
/* Will allocate size bytes from the garbage collector. If a
* finalizer is given, it will be called before the memory is
* reclaimed. If no finalizer is given the allocated memory is not
* scanned for nested references.
*/
void* _d_new(size_t size, CFinalizer cfinalizer);
}
//........................................................................................
// creates a new class
template <class T>
typename enable_if<is_class<T>::value, T*>::type d_new()
{
// C++ doesn't allow to take the address of a destructor create
// this helper function to work around this.
struct Dtor
{
static void destroy(void* pinst)
{
((T*)pinst)->~T();
// clear memory to help GC
memset(pinst, 0, sizeof(T));
}
};
void *p = _d_new(sizeof(T), &Dtor::destroy);
return new (p) T;
}
//........................................................................................
// creates plain types use n > 1 to allocate an array
template <class T>
typename enable_if<!is_class<T>::value, T*>::type d_new(size_t n = 1)
{
return static_cast<T*>(_d_new(sizeof(T) * n, NULL));
}
#endif // D_NEW_H
module bar;
import std.stdio;
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
extern(C++)
{
interface Array
{
void printInfo();
size_t length();
double* ptr();
}
Array createArray();
}
//........................................................................................
Array useArray(Array array)
{
double[] ary = array.ptr[0 .. array.length];
writeln("array capacity ", ary.capacity);
ary[] = 1;
Array array2;
array2 = array;
return array2;
}
//........................................................................................
void main()
{
auto array = createArray();
array.printInfo();
writeln("array ", array.ptr[0 .. array.length]);
array = useArray(array);
// reference semantic
array.printInfo();
writeln("array ", array.ptr[0 .. array.length]);
}
@MartinNowak
Copy link
Author

gcc -c foo.cpp
dmd bar.d cpp_wrapper.d foo.o -L-lstdc++
./bar

@mtachrono
Copy link

well, but you have to do some kind of "injection" in the c++ source. will it be possible to call c++'s ctor/dtor without touching the c++ sources. I just want to use dmd and link to QtCore.dll.

@MartinNowak
Copy link
Author

g++ -g -c array.cpp -I/usr/local/include
dmd -g darray d_new array.o -L-lstdc++
./darray

@MartinNowak
Copy link
Author

dropped boost dependency
g++ -g -c -Wall array.cpp
dmd -g -w darray d_new array.o -L-lstdc++
./darray

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment