Thread overview
C++ interop, abstract struct problem
Dec 28
RSY
Dec 28
RSY
Dec 28
RSY
Dec 29
RSY
Dec 29
RSY
December 28
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));
    }
}

```
December 28
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
December 28
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
December 28
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
December 29
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
};

```

December 29
Here is a debugger view of the passed IAllocator&

https://i.imgur.com/p04Tj4a.png