ThePhD / sol2

Sol3 (sol2 v3.0) - a C++ <-> Lua API wrapper with advanced features and top notch performance - is here, and it's great! Documentation:
http://sol2.rtfd.io/
MIT License
4.16k stars 504 forks source link

how to make lua multidimensional array like "temp_array[2][3]" in C++ #1405

Open dotori1995-enu opened 1 year ago

dotori1995-enu commented 1 year ago

Hi i am a huge fan of your solution, sol2. and i am adapting that solution on emscripten that make wasm.

but i cant find the way to make lua multidimensional array like lua_temp_array[2][3].

On C++, there is a array, int* temp_array. temp_array is 6 size, and temp_array value is 0,1,2,3,4,5. In this situation, how can bind this temp_array with lua_temp_array?

i know, sol2 offered many ways to use C++ container in lua script like vector, map, ..... and so on. but i just want to bind temp_array with lua_temp_array using sol2.

if sol2 wouldn't have solution to adapting this situation, then i would have no choice but to use just original lua not sol2


IDE : Visual Studio Code Language : C++ Compiler: Emscripten

Thanks.

rleigh-codelibre commented 1 year ago

Can you use std::span for this? Create a std::span<std::span<int, 3>, 2> which will point to the two arrays of three elements. Then create a new usertype for this type, where the sol::meta_function::index and sol::meta_function::new_index functions will return and store a std::span<int, 3>. Next, create a new usertype for std::span<int, 3>. The index/new_index functions for this type will return and store an int. This will give you working multi-dimensional indexing within Lua.

You might need to swap the dimensions to get row-major or column-major ordering to match the C array structure. I didn't think too hard about that when writing up this reply.

If you want to vary the dimension sizes at runtime, use the std::dynamic_extent option when defining the specialised span type.

Example I've been working on today with the GLM library. Not exactly the same as std::span, but the logic here should be adaptable without much extra work.

namespace {
  template<typename T, typename U>
  auto fetchIndex(T const& c, typename T::length_type idx) -> U const& {
    if (idx < c.length()) {
      return c[idx];
    } else {
      throw std::logic_error("GLM index out of range");
    }
  }

  template<typename T, typename U>
  auto fetchIndex(T & c, typename T::length_type idx) -> U& {
    if (idx < c.length()) {
      return c[idx];
    } else {
      throw std::logic_error("GLM index out of range");
    }
  }

  template<typename T, typename U>
  auto storeIndex(T & c, typename T::length_type idx, U const& v) -> void {
    if (idx < c.length()) {
      c[idx] = v;
    } else {
      throw std::logic_error("GLM index out of range");
    }
  }
}

void luaGlmInit(sol::state& state)
{
  state.new_usertype<glm::vec4>(
      "vec4",
      sol::constructors<glm::vec4(),
                        glm::vec4(float const&),
                        glm::vec4(float const&, float const&, float const&, float const&)>(),
      sol::meta_function::multiplication, sol::resolve<glm::vec4 (glm::vec4 const&, glm::vec4 const&)>(&glm::operator*),
      sol::meta_function::division, sol::resolve<glm::vec4 (glm::vec4 const&, glm::vec4 const&)>(&glm::operator/),
      sol::meta_function::addition, sol::resolve<glm::vec4 (glm::vec4 const&, glm::vec4 const&)>(&glm::operator+),
      sol::meta_function::subtraction, sol::resolve<glm::vec4 (glm::vec4 const&, glm::vec4 const&)>(&glm::operator-),
      sol::meta_function::index, sol::resolve<const float& (glm::vec4 const&, glm::length_t)>(fetchIndex),
      sol::meta_function::new_index, sol::resolve<void (glm::vec4&, glm::length_t, float const&)>(storeIndex)
  );

  state.new_usertype<glm::mat4>(
      "mat4",
      sol::constructors<glm::mat4(),
                        glm::mat4(float const&),
                        glm::mat4(float const&, float const&, float const&, float const&,
                                  float const&, float const&, float const&, float const&,
                                  float const&, float const&, float const&, float const&,
                                  float const&, float const&, float const&, float const&)>(),
      sol::meta_function::multiplication, sol::resolve<glm::mat4 (glm::mat4 const&, glm::mat4 const&)>(&glm::operator*),
      sol::meta_function::addition, sol::resolve<glm::mat4 (glm::mat4 const&, glm::mat4 const&)>(&glm::operator+),
      sol::meta_function::subtraction, sol::resolve<glm::mat4 (glm::mat4 const&, glm::mat4 const&)>(&glm::operator-),
      sol::meta_function::index, sol::resolve<glm::vec4& (glm::mat4 &, glm::length_t)>(fetchIndex),
      sol::meta_function::new_index, sol::resolve<void (glm::mat4&, glm::length_t, glm::vec4 const&)>(storeIndex)
  );
}

Test code:

TEST_F(LuaGLM, ArrayIndexing)
{
  lua->script(
      "b=mat4.new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)\n"
      "print(b)\n"
      "print(\"b[0] = \" .. tostring(b[0]))\n"
      "print(\"b[1] = \" .. tostring(b[1]))\n"
      "print(\"b[2] = \" .. tostring(b[2]))\n"
      "print(\"b[3] = \" .. tostring(b[3]))\n"
      "print(b[3])\n"
      "b[2][3] = 99.3\n"
      "print(b)\n");
}

==>

mat4x4((1.000000, 2.000000, 3.000000, 4.000000), (5.000000, 6.000000, 7.000000, 8.000000), (9.000000, 10.000000, 11.000000, 12.000000), (13.000000, 14.000000, 15.000000, 16.000000))
b[0] = vec4(1.000000, 2.000000, 3.000000, 4.000000)
b[1] = vec4(5.000000, 6.000000, 7.000000, 8.000000)
b[2] = vec4(9.000000, 10.000000, 11.000000, 12.000000)
b[3] = vec4(13.000000, 14.000000, 15.000000, 16.000000)
vec4(13.000000, 14.000000, 15.000000, 16.000000)
mat4x4((1.000000, 2.000000, 3.000000, 4.000000), (5.000000, 6.000000, 7.000000, 8.000000), (9.000000, 10.000000, 11.000000, 99.300003), (13.000000, 14.000000, 15.000000, 16.000000))
dotori1995-enu commented 1 year ago

it is a greate example. i pull off my problem thank to your kindness. I couldn’t have done it without you.