www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - C++ interop, abstract struct problem

reply RSY <rsy_881 gmail.com> writes:
Hello

I try to use a C++ lib


So far so good, i managed to use that lib and get started

The problem however is this:

C++ API:
```
void preinit(IAllocator& allocator, bool load_renderdoc);
```


``IAllocator`` is an abstract struct, (a struct with virtual 
functions)

But the problem is D doesn't allow that, so apparently i need to 
use an abstract class and wrap it using: ``extern (C++, struct)``

The problem is, when passing the object to the function i get:

``dumix.obj : error LNK2019: unresolved external symbol "void 
__cdecl Lumix::gpu::preinit(struct Lumix::IAllocator *,bool)" 
(?preinit gpu Lumix  YAXPEAUIAllocator 2 _N Z) referenced in 
function _Dmain ``


Wich is wrong, it is supposed to pass as a reference, i don't 
know why it is picky

Do you guys have an idea what i do wrong, or what i should do?

Thanks!

Here is the full code:


```
import std.stdio;
import core.thread;
import core.stdc.stdio;
import core.memory;

extern (C++, Lumix)  nogc nothrow
{

     extern (C++, os)  nogc nothrow
     {
         struct InitWindowArgs
         {
             enum Flags
             {
                 NO_DECORATION = 1 << 0,
                 NO_TASKBAR_ICON = 1 << 1
             }

             const(char)* name = "hello lumix";
             bool handle_file_drops = false;
             bool fullscreen = false;
             uint flags = 0;
             void* parent = null;
         }

         void* createWindow(const ref InitWindowArgs);
     }

     align(8) struct Mutex
     {
         ubyte[8] data;
     }


     extern (C++, struct) abstract class IAllocator
     {
         void* allocate(size_t n);
         void  deallocate(void* p);
         void* reallocate(void* ptr, size_t size);
         void* allocate_aligned(size_t size, size_t alignn);
         void  deallocate_aligned(void* ptr);
         void* reallocate_aligned(void* ptr, size_t size, size_t 
alignn);
     }

     extern (C++, struct) class DefaultAllocator : IAllocator
     {
         ubyte* m_small_allocations = null;
         void*[4] m_free_lists;
         uint m_page_count = 0;
         Mutex m_mutex;

         override void* allocate(size_t n);
         override void  deallocate(void* p);
         override void* reallocate(void* ptr, size_t size);
         override void* allocate_aligned(size_t size, size_t 
alignn);
         override void  deallocate_aligned(void* ptr);
         override void* reallocate_aligned(void* ptr, size_t size, 
size_t alignn);
     }

     extern (C++, gpu)  nogc nothrow
     {
         enum InitFlags : uint
         {
             NONE = 0,
             DEBUG_OUTPUT = 1 << 0,
             VSYNC = 1 << 1
         }

         // 1505C2 ?preinit gpu Lumix  YAXAEAUIAllocator 2 _N Z
         void preinit(IAllocator allocator, bool load_renderdoc);
         bool init(void* window_handle, InitFlags flags);
         void* allocProgramHandle();
     }
}

void main()
{
     auto arg = InitWindowArgs();
     auto win = Lumix.os.createWindow(arg);

     IAllocator allocator = new DefaultAllocator();
     Lumix.gpu.preinit(allocator, false);
     Lumix.gpu.init(win, InitFlags.NONE);

     while (true)
     {
         Thread.sleep(usecs(1));
     }
}

```
Dec 28 2020
next sibling parent RSY <rsy_881 gmail.com> writes:
IAllocator struct: 
https://github.com/nem0/LumixEngine/blob/master/src/engine/allocator.h#L18


function: 
https://github.com/nem0/LumixEngine/blob/master/src/renderer/gpu/gpu.h#L208
Dec 28 2020
prev sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Monday, 28 December 2020 at 15:42:26 UTC, RSY wrote:
 ``IAllocator`` is an abstract struct, (a struct with virtual 
 functions)

 But the problem is D doesn't allow that, so apparently i need 
 to use an abstract class and wrap it using: ``extern (C++, 
 struct)``
You could try using one of the techniques on this page to make `IAllocator` a struct instead of a class: https://dlang.org/spec/cpp_interface.html#structs
Dec 28 2020
parent reply RSY <rsy_881 gmail.com> writes:
On Monday, 28 December 2020 at 16:42:19 UTC, Paul Backus wrote:
 On Monday, 28 December 2020 at 15:42:26 UTC, RSY wrote:
 ``IAllocator`` is an abstract struct, (a struct with virtual 
 functions)

 But the problem is D doesn't allow that, so apparently i need 
 to use an abstract class and wrap it using: ``extern (C++, 
 struct)``
You could try using one of the techniques on this page to make `IAllocator` a struct instead of a class: https://dlang.org/spec/cpp_interface.html#structs
Oh i wonder how i could have missed this part, thanks!! i will try this
Dec 28 2020
parent reply RSY <rsy_881 gmail.com> writes:
Hmm, something seems to be very wrong, here what i got so far

``` D
     struct IAllocator
     { }
     struct DefaultAllocator
     {
         // BASE --------------------------
         IAllocator base = IAllocator();
         alias base this;
         //--------------------------------

         ubyte* m_small_allocations = null;
         void*[4] m_free_lists;
         uint m_page_count = 0;
         Mutex m_mutex;
     }


     void preinit(ref IAllocator allocator, bool load_renderdoc);
```

The problem is the allocator data seems to be corrupted, it 
crashes on the C++ side when calling preinit


IAllocator is empty, but it doesn't get optimized as the wiki 
say, since the size of DefaultAllocator is 64 bytes on the C++ 
side, and 56 bytes on D side, i get 64 bytes with the definition 
above

Does anyone have an idea, did i translate the struct wrong?


```C++
struct LUMIX_ENGINE_API IAllocator {
	virtual ~IAllocator() {}
	virtual bool isDebug() const { return false; }

	virtual void* allocate(size_t size) = 0;
	virtual void deallocate(void* ptr) = 0;
	virtual void* reallocate(void* ptr, size_t size) = 0;

	virtual void* allocate_aligned(size_t size, size_t align) = 0;
	virtual void deallocate_aligned(void* ptr) = 0;
	virtual void* reallocate_aligned(void* ptr, size_t size, size_t 
align) = 0;

	template <typename T> void deleteObject(T* ptr) {
		if (ptr)
		{
			ptr->~T();
			deallocate_aligned(ptr);
		}
	}
};

```

and for DefaultAllocator

```c++
struct LUMIX_ENGINE_API DefaultAllocator final : IAllocator {
	struct Page;

	DefaultAllocator();
	~DefaultAllocator();

	void* allocate(size_t n) override;
	void deallocate(void* p) override;
	void* reallocate(void* ptr, size_t size) override;
	void* allocate_aligned(size_t size, size_t align) override;
	void deallocate_aligned(void* ptr) override;
	void* reallocate_aligned(void* ptr, size_t size, size_t align) 
override;

	u8* m_small_allocations = nullptr;
	Page* m_free_lists[4];
	u32 m_page_count = 0;
	Mutex m_mutex;
};

```


For Mutex:

```c++
struct alignas(8) LUMIX_ENGINE_API Mutex {
	friend struct ConditionVariable;
	
	Mutex();
	Mutex(const Mutex&) = delete;
	~Mutex();

	void enter();
	void exit();

private:
	#ifdef _WIN32
		u8 data[8];
	#else
		pthread_mutex_t mutex;
	#endif
};

```
Dec 29 2020
parent RSY <rsy_881 gmail.com> writes:
Here is a debugger view of the passed IAllocator&

https://i.imgur.com/p04Tj4a.png
Dec 29 2020