COMMUNITY

Haxe access to C++ classes exposed to LUA via Swig

I have a swig interface to a C++ member function that returns a std::vectorstd::string.
In lua I can do:

`local foo = thing:getStringArray();
for i = 0, foo:size()-1 do
    print(foo[i]);
end`

In haxe I’m very close because foo[i] works so I can say

`extern class thing {
    public function getStringArray() : Array<String>;
}`
var stuff = thing:getStringArray();
trace(stuff[3])

But the it feels wrong as there is no mapping of the lua vector length to the haxe Array size.
The haxe Vector/Array concepts seem inverted from C++ w.r.t. dynamic sizing.

Is the correct path to make a CStdStringVector class and extern stuff? (I think mapping the [] operator might cause me sadness though.)

Looks like

`@:native("__getitem__") @:op([]) public function arrayRead(n:Int) : String;`

Is a no go as well.

More info

// access to C++ std::vector<std::string> as wrapped in lua
extern class CVectorString {
   private function new();
   public function size(): Int;
   public function __getitem__(n:Int) : String;
}

Is failing on the lua side with
Error in std::vector< std::string >::getitem (arg 2), expected ‘unsigned int’ got ‘string’

There’s a way forward here, but I’ll need some more details:

Generally lua externs for c libraries will wrap vector returns in a table. Is that not the case here? How do you get the vector size in pure lua code otherwise?

Regardless of how it’s returned, I believe you will need to use an abstract for the class here. You’ll need this to provide bracket access to the vector, and to “autocast” to a standard haxe Array so that it will work well with the rest of the Haxe std lib. There are some helper methods for this in TableTools and Boot.

I think it would be super helpful to get a small working example of the code you’re dealing with so I can give more precise suggestions.

I’ll try to pull out the swig/C++/lua layers.
Might take some time.

On the lua side, the std::vector std::string wrapper is overriding the getitem setitem etc. in the metatable to call the C++ vector operations. This is nice because in lua if I do

local foo = getCStringVector()
print(foo[3])

it doesn’t matter if there are 3 or 300000 items in the vector, only one gets pulled out. It’s not so nice because lua does the stupid 1 base index, vs. the 0 base for everything else.

My current work around (because my vectors are small, worst case 200 strings) is to make a helper function and inline it for the method that would return the std::vector std::string and lump the copy.

class CVectorToArray {
   @:generic
   public static function convert<T>(vec:CVectorType<T>) : Array<T> {
      var ans:Array<T> = [];
      untyped  __lua__("for i = 0,vec:size()-1 do ans[i] = vec[i] end");
      return ans;
   }
}
   private function getCStringVector() : CVectorType<String>;
   public inline function metricListArray() : Array<String> {
     return CVectorToArray.convert(this.metricList());
   }

The magic that lets the C++ through lua comes from line 52 of:

(And I know I’m an edge case, because why to haxe -> lua -> C++ instead of haxe -> C++, but we distribute lua as the configuration language and load lua at runtime.)