Adding Arrays of Objects


#1

I was wondering if Chai Script supported adding an array of objects so that the script could access them. I looked through the documentation and examples but could not find one related to passing arrays back and forth. For example:

In the host cost,

MyObject **objects; //of length N
chai.add(var(**objects), "objects"); 

In the script,

for(var i=0; i<N; ++i) {
    print(objects[i]->name);
}

However during run-time, it crashes because it does not see ‘objects’ as an array object. I also tried the same approach but with an array of integers and got the same result, not recognizing it as an array. Does ChaiScript not support this currently, or am I calling chai.add incorrectly?

Thanks!


#2

ChaiScript does support pointers and pointers to pointers to some extent. However, what you are doing with the ** is actually double-dereferencing your pointer and adding the very first object of your array to ChaiScript.

I am a bit confused as to what you intend to do, since that is a **. Are you trying to add an array of pointers? Or a pointer to an array?

There are solutions to get either working, but the best thing to do, the most memory safe option that would work the best with ChaiScript, is to use a vector:

std::vector<chaiscript::Boxed_Value> objectVec;
for (int i = 0; i < N; ++i)
{
  objectVec.push_back(chaiscript::var(std::ref(*objects[i]))); // this would push_back a reference given **objects (ChaiScript likes references better than pointers)

  // or
  objectVec.push_back(chaiscript::var(objects[i])); // this would push_back a pointer given **objects

  // or

  objectVec.push_back(chaiscript::var(*objects[i])); // this would push_back a copy given **objects
}

chai.add(objectVec, "objects"); // copies vector

// or if you want to share objectVec with your C++ code

chai.add(std::ref(objectVec), "objects"); // chaiscript shares the reference with C++

In general, I strongly suggest you move away from using raw pointers and raw arrays in your C++. std::vector provides the same performance for element access and can grow and can destroy itself properly. Similarly for std::unique_ptr: automatically managed and the same performance as a raw pointer for dereferencing of the value.

If for some reason you absolutely must pass a pointer into ChaiScript and treat that as an array inside your script, let me know. There are methods of handling that also.


#3

Thank you! I got ChaiScript to see the objects array using your first example in the loop, and then sharing the reference with C++.

I have another question about how to access a vector data member from an object within ChaiScript.

struct MyObject {
   int number;
   std::vector<int> x; //of length NX
}

std::vector<MyObject*> objects; //of length N

std::vector<chaiscript::Boxed_Value> objectVec;
for(int i=0;i<N;++i) {
   objectVec.push_back(chaiscript::var(objects[i]));
}

chai.add(chaiscript::var(objectVec), "objects"); //'pass' into ChaiScript

Now when I add in the data members:

chai.add(chaiscript::fun(&MyObject::number), "number"); //works fine 
chai.add(chaiscript::fun(&MyObject::x), "x"); //ChaiScript does not see as vector

For example, inside a ChaiScript I’d like to access the x vector like so:

for( var obj_id=0; obj_id < N; ++obj_id) { //loop over all objects
  for( var i = 0; var < NX; ++var) { //loop over all 'x' elements
    print(to_string(objects[obj_id].x[i])); //gives error
  }
}

Is it possible to wrap x into a std::function somehow, in order to trick ChaiScript into seeing it as a vector?


#4

The method you are using is fine. The problem is that ChaiScript, by default, understands one kind of vector: std::vector<Boxed_Value> This is a limitation of C++, there’s no way to automagically work with every type of vector instantiation.

The easiest method to get std::vector<int> working is:

chai.add(standard_library::vector_type<std::vector<int> >("IntVector"));

There are a handful of similar functions documented here: http://chaiscript.com/docs/5/namespacechaiscript_1_1bootstrap_1_1standard__library.html to help you expose various C++ standard library (STL) types.

And you can see how they are used during system bootstrap time, as far as what’s added to the engine by default:


#5

I mimicked what chaiscript_stdlib.hpp was doing, and made a test module:

class TestLib {
    public:
       static ModulePtr library() {
          using namespace bootstrap;
          ModulePtr lib = Bootstrap::bootstrap();
          
          lib->add(standard_library::vector_type< std::vector<int> > ("IntVector"));
          return lib;
       }
 };

and then changed the way the ChaiScript object was created to use the new module,

chaiscript::ChaiScript chai(TestLib::library());

Does this mean that ChaiScript can now see “IntVector” as a type? Do I have to cast &MyObject::x when adding it to ChaiScript in order to get it to use the “IntVector” type?

I could not figure out how to get ChaiScript to use the “IntVector” definition when adding std::vector<int> x by using chai.add(fun(&MyObject::x), "x") I could copy x into a new std::vector<chaiscript::Boxed_Value> however this would not be very good with lots of vectors, each with thousands of elements.

Thanks!


#6

Yes, at that point IntVector is a type that ChaiScript can see, and it will automatically be associated with anything that’s of an std::vector<int> type. Exposing it either via a module or direction to the ChaiScript engine should have worked.

If you’re still having problems, perhaps you should post the entire example you have and we can sort it out.


#7

Ah ok, it turns out I was just accessing the x variable incorrectly from within my ChaiScript. When I fixed that, it was able to see x as a vector fine.

Thanks for your help!


#8

Great, glad to hear it. Feel free to promote the project you are working that uses ChaiScript.