How to export array data through node addon - c++

I'm using node 0.12.x, I want to return some array data from node addon written by c++
Isolate* isolate = args.GetIsolate();
MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.Holder());
obj->value_ += 1;
args.GetReturnValue().Set(Number::New(isolate, obj->value_));
This is a sample for returning Number data.

using namespace v8;
Create an array:
Local<Array> myArray = Array::New(isolate);
You can then create objects with properties (or just integers) and push them into the array:
for (int i = 0; i < n; i++) {
Local<Object> obj = Object::New(isolate);
obj->Set(String::NewFromUtf8(isolate, "tag1"), "test");
myArray->Set(i, obj);
}
args.GetReturnValue().Set(myArray);
If you're writing native code for node.js I highly recommend using nan:
https://github.com/nodejs/nan

Related

C++ CLR unmanaged BYTE* to managed System::array<Byte>^ without loop

I tried to find working solution on my qestion, but not found.
I want to "connect" managed C# .NET code with native C++ code (DLL). My C++ returns unmanaged BYTE* pointer and count of elements.
How to initialize new array<Byte>^ from BYTE* without loop? Because it may be to 5 Megabytes. (Encrypting data)
Help if you can please.
EDIT:
With loop it works:
array<Byte>^ a = gcnew array<Byte>(resultDataSize);
for (int i = 0; i < resultDataSize; i++)
{
a[i] = resultData[i];
}
But I'd like get something like:
a = new array<Byte>(resultData, resultDataSize);
EDIT 2:
Now in my C++ i have function:
void Decrypt(BYTE* dataToDecrypt, DWORD dataToDecryptLength, wchar_t* senderName, wchar_t* receiverName, BYTE** result, DWORD* resultSize)
{
...
*result = main.Data;
*resultSize = main.Length;
}
Where main is a class with BYTE* Data and DWORD Length and other functions.
In my CLR:
array<Byte>^ Decrypt(array<Byte>^ dataToDecrypt, String^ senderName, String^ receiverName)
{
...
BYTE* resultData = nullptr;
DWORD resultDataSize = 0;
// Call my c++
DecryptFunction(dataToDecryptBytes, dataToDecrypt->Length, sender, receiver, &resultData, &resultDataSize);
array<Byte>^ result = gcnew array<Byte>(resultDataSize);
for (int i = 0; i < resultDataSize; i++)
{
result[i] = resultData[i];
}
....
return result;
}
In C#:
byte[] data = ...;
...
byte[] decrypted = provider.Decrypt(data, "user1", "user2");
...

Pass Node.js Buffer to C++ addon

test.js
buf = new Buffer(100);
for (var i = 0; i < 100; i++) buf[i] = i
addon.myFync(buf);
addon.cpp
Handle<Value> set(const Arguments& args) {
char *buf = SOMETHING(args[0]);
return Undefined();
}
How to get the pointer to a data of the buffer inside the C++ function?
What should I write in place of SOMETHING(args[0])?
I have node_buffer.h opened in my editor, but I cannot figure out.
Node version = v0.10.29
You can do:
char* buf = node::Buffer::Data(args[0]);
to directly access the bytes of a Buffer.
According to the node.js node binding documentation the 'arg[0]' value argument can be accessed as:
String::AsciiValue v(args[0]->ToString());

v8: Array of objects

I'm transforming a parser for v8 in NodeJS. Currently I have the following structure
struct Node {
short tag;
std::string data;
Node(std::string input, short tagId) {
tag = tagId;
data = input;
}
};
std::vector<Node> elems;
And I'm populating the vector from loop like this:
elems.push_back(Node(STRING, 3));
My goal is return a javascript object like this:
[
{ tag: 2, data: "asdsad" },
{ tag: 2, data: "asdsad" },
{ tag: 2, data: "asdsad" }
]
But since the V8 documentation is crappy, I couldn't figure out how to do it. My best shot was to make
Local<Value> data[2] = {
Local<Value>::New(Integer::New(2)),
String::New("test")
};
but I can't figure out how to make it an array and return it.
I'm using this example as template.
Here's what you might try (node v0.10.x):
// in globals
static Persistent<String> data_symbol;
static Persistent<String> tag_symbol;
// in addon initialization function
data_symbol = NODE_PSYMBOL("data");
tag_symbol = NODE_PSYMBOL("tag");
// in some function somewhere
HandleScope scope;
Local<Array> nodes = Array::New();
for (unsigned int i = 0; i < elems.length; ++i) {
HandleScope scope;
Local<Object> node_obj = Object::New();
node_obj->Set(data_symbol, String::New(elems[i].data.c_str()));
node_obj->Set(tag_symbol, Integer::New(elems[i].tag));
nodes->Set(i, node_obj);
}
return scope.Close(nodes);
I was looking for a solution for Node 5, and it seems mscdex's answer is outdated now. Hope this helps someone.
HandleScope scope(isolate);
Local<Array> nodes = Array::New(isolate);
for (unsigned int i = 0; i < elems.length; ++i) {
HandleScope scope(isolate);
Local<Object> node = Object::New(isolate);
node->Set(String::NewFromUtf8(isolate, "data"), String::New(isolate, elems[i].data.c_str()));
node->Set(String::NewFromUtf8(isolate, "tag"), Integer::New(isolate, elems[i].tag));
nodes->Set(i, node);
}
args.GetReturnValue().Set(nodes);

memory overlapping in an initialization of a class

My problem is I have a header file in which I store all my classes and in my cpp file I have my initializations of these classes, the initialization is not dynamic I have a number of arrays of different classes.
Now the problem is when I started expanding the classes in my header, adding more members and methods,the initialization of 1 specific class start throwing assertions at me of memory overlapping and suggested using memmove() instead of memcpy(), though I use neither of them in that class.
I tried replacing this class with a downgraded version of it that worked in older versions of my source but it still threw the same assertion at me I don't know what part of the code is relevant here is the assertion is being asserted in the initialization of the class without any pointer to what exactly is wrong.
this is my initialization of the class :
Shuriken(cpFloat m,cpVect veloc,cpFloat elast,cpFloat myu) : Spark() , Bang1() , ShurikenFlame()
{
smass = m;
sv = veloc;
se = elast;
su = myu;
ToDraw = false;
Removed = true;
AllocatedBombAnim = false;
DrawFlamedShuriken = false;
DeployFlameBang = false;
PassedLine = false;
hitfruit = false;
FruitIsBeingHit = false;
ToRemoveBody = false;
DummyAdded = false;
HitBossBanana = false;
fruitnum = 11;//11 means it has no fruit
Sec_FlameCounter = 3;
LitShuriken_UVs[0] = CIwFVec2(0, 0);
LitShuriken_UVs[2] = CIwFVec2(1.0/4, 1.0/4);
LitShuriken_UVs[3] = CIwFVec2(1.0/4, 0);
LitShuriken_UVs[1] = CIwFVec2(0, 1.0/4);
Sparkle_UVs[0] = CIwFVec2(0, 0);
Sparkle_UVs[2] = CIwFVec2(1.0/2, 1.0/4);
Sparkle_UVs[3] = CIwFVec2(1.0/2, 0);
Sparkle_UVs[1] = CIwFVec2(0, 1.0/4);
lastPos = cpvzero;
lastAngle = 0;
struct cpVect initShurikenBody_Verts[35] =
{
cpv(-128.01,41.26),
cpv(-58.74,45.42),
cpv(-47.79,32.04),
cpv(-40.06,33.94),
cpv(-20.63,48.29),
cpv(-16.13,55.67),
cpv(-25.33,69.7),
cpv(0,134.67),
cpv(25.34,70.16),
cpv(16.14,55.67),
cpv(20.75,48.1),
cpv(39.98,34.04),
cpv(47.96,32.15),
cpv(58.86,45.38),
cpv(128.01,41.26),
cpv(74.55,-2.82),
cpv(57.95,1.45),
cpv(52.25,-5.19),
cpv(45.16,-26.79),
cpv(45.77,-35.34),
cpv(61.86,-41.64),
cpv(79.1,-108.95),
cpv(20.79,-71.41),
cpv(19.62,-54.33),
cpv(11.91,-51.14),
cpv(-12.02,-51.11),
cpv(-19.64,-54.26),
cpv(-20.81,-71.4),
cpv(-79.11,-108.95),
cpv(-61.87,-41.6),
cpv(-45.77,-35.03),
cpv(-45.18,-26.75),
cpv(-52.23,-5.35),
cpv(-57.88,1.31),
cpv(-74.48,-2.8),
};
struct cpVect initShurikenShape_Verts1[5] =
{
cpv(-128.01,41.26),
cpv(-58.74,45.42),
cpv(-47.79,32.04),
cpv(-57.88,1.31),
cpv(-74.48,-2.8),
};
struct cpVect initShurikenShape_Verts2[5] =
{
cpv(0,134.67),
cpv(25.34,70.16),
cpv(16.14,55.67),
cpv(-16.13,55.67),
cpv(-25.33,69.7),
};
struct cpVect initShurikenShape_Verts3[5] =
{
cpv(47.96,32.15),
cpv(58.86,45.38),
cpv(128.01,41.26),
cpv(74.55,-2.82),
cpv(57.95,1.45),
};
struct cpVect initShurikenShape_Verts4[5] =
{
cpv(79.1,-108.95),
cpv(20.79,-71.41),
cpv(19.62,-54.33),
cpv(45.77,-35.34),
cpv(61.86,-41.64),
};
struct cpVect initShurikenShape_Verts5[5] =
{
cpv(-79.11,-108.95),
cpv(-61.87,-41.6),
cpv(-45.77,-35.03),
cpv(-19.64,-54.26),
cpv(-20.81,-71.4),
};
struct cpVect initShurikenShape_Verts6[4] =
{
cpv(-47.79,32.04),
cpv(-40.06,33.94),
cpv(-52.23,-5.35),
cpv(-57.88,1.31),
};
struct cpVect initShurikenShape_Verts7[4] =
{
cpv(-20.63,48.29),
cpv(-16.13,55.67),
cpv(16.14,55.67),
cpv(20.75,48.1),
};
struct cpVect initShurikenShape_Verts8[4] =
{
cpv(39.98,34.04),
cpv(47.96,32.15),
cpv(57.95,1.45),
cpv(52.25,-5.19),
};
struct cpVect initShurikenShape_Verts9[4] =
{
cpv(45.16,-26.79),
cpv(45.77,-35.34),
cpv(19.62,-54.33),
cpv(11.91,-51.14),
};
struct cpVect initShurikenShape_Verts10[4] =
{
cpv(-12.02,-51.11),
cpv(-19.64,-54.26),
cpv(-45.77,-35.03),
cpv(-45.18,-26.75),
};
struct cpVect initShurikenShape_Verts11[10] =
{
cpv(-40.06,33.94),
cpv(-20.63,48.29),
cpv(20.75,48.1),
cpv(39.98,34.04),
cpv(52.25,-5.19),
cpv(45.16,-26.79),
cpv(11.91,-51.14),
cpv(-12.02,-51.11),
cpv(-45.18,-26.75),
cpv(-52.23,-5.35),
};
for(int i=0;i<5;i++)
ShurikenShape_Verts1[i] = initShurikenShape_Verts1[i];
for(int i=0;i<5;i++)
ShurikenShape_Verts2[i] = initShurikenShape_Verts2[i];
for(int i=0;i<5;i++)
ShurikenShape_Verts3[i] = initShurikenShape_Verts3[i];
for(int i=0;i<5;i++)
ShurikenShape_Verts4[i] = initShurikenShape_Verts4[i];
for(int i=0;i<5;i++)
ShurikenShape_Verts5[i] = initShurikenShape_Verts5[i];
for(int i=0;i<4;i++)
ShurikenShape_Verts6[i] = initShurikenShape_Verts6[i];
for(int i=0;i<4;i++)
ShurikenShape_Verts7[i] = initShurikenShape_Verts7[i];
for(int i=0;i<4;i++)
ShurikenShape_Verts8[i] = initShurikenShape_Verts8[i];
for(int i=0;i<4;i++)
ShurikenShape_Verts9[i] = initShurikenShape_Verts9[i];
for(int i=0;i<4;i++)
ShurikenShape_Verts10[i] = initShurikenShape_Verts10[i];
for(int i=0;i<10;i++)
ShurikenShape_Verts11[i] = initShurikenShape_Verts11[i];
for(int i=0;i<35;i++)
ShurikenBody_Verts[i] = initShurikenBody_Verts[i];
}
I am using Visual Studio 2010 with Marmalade SDK and I am writing in C++.
Thanks for any help,
Anton
Ok, so if we assume that ShurikenShape_Verts1 is either a regular C style array or a C++ style std::array and has the type cpVect, and cpVect is a POD struct:
for(int i=0;i<5;i++)
ShurikenShape_Verts1[i] = initShurikenShape_Verts1[i];
can be copied as:
memcpy(ShurikenShape_Verts1, initShurikenShape_Verts1,
sizeof(initShurikenShape_Verts1));
However, I have made some assumptions here, since you haven't posted enough code. I'd hate to start a "can post this, can you post that" type thread, asking for a large number of other bits of your code, but it also means that I may not have answered the question correctly, since I don't know for sure that your cpVect is indeed a POD struct, for example.
(I'd submit a comment but I don't have enough of a stackoverflow "reputation" to do so:-()
I would seriously stand back and look at why you are trying to copy this stuff to start with. Copying lots of stuff is comparatively slow. Far better to use a pointer to the existing array or a reference, which depends on your style.
If by "cpVect is just 2 floats made into a vector" you mean vector, then don't use memcpy or whatever. This is just going to give you heap issues later. Remember that these work by allocating behind the scenes. If you use memcpy you are going to get two objects pointing to the same content, and when the first goes out of scope that content will be freed.

How to train in Matlab a model, save it to disk, and load in C++ program?

I am using libsvm version 3.16. I have done some training in Matlab, and created a model. Now I would like to save this model to disk and load this model in my C++ program. So far I have found the following alternatives:
This answer explains how to save a model from C++, which is based on this website. Not exactly what I need, but could be adapted. (This requires development time).
I could find the best training parameters (kernel,C) in Matlab and re-train everything in C++. (Will require doing the training in C++ each time I change a parameter. It's not scalable).
Thus, both of these options are not satisfactory,
Does anyone have an idea?
My solution was to retrain in C++ because I couldn't find a nice way to directly save the model. Here's my code. You'll need to adapt it and clean it up a bit. The biggest change you'll have to make it not hard coding the svm_parameter values like I did. You'll also have to replace FilePath with std::string. I'm copying, pasting and making small edits here in SO so the formatting won't e perfect:
Used like this:
auto targetsPath = FilePath("targets.txt");
auto observationsPath = FilePath("observations.txt");
auto targetsMat = MatlabMatrixFileReader::Read(targetsPath, ',');
auto observationsMat = MatlabMatrixFileReader::Read(observationsPath, ',');
auto v = MiscVector::ConvertVecOfVecToVec(targetsMat);
auto model = SupportVectorRegressionModel{ observationsMat, v };
std::vector<double> observation{ { // 32 feature observation
0.883575729725847,0.919446119013878,0.95359403450317,
0.968233630936732,0.91891307107125,0.887897763183844,
0.937588566544751,0.920582702918882,0.888864454119387,
0.890066735260163,0.87911085669864,0.903745573664995,
0.861069296586979,0.838606194934074,0.856376230548304,
0.863011311537075,0.807688936997926,0.740434984165146,
0.738498042748759,0.736410940165691,0.697228384912424,
0.608527698289016,0.632994967880269,0.66935784966765,
0.647761430696238,0.745961037635717,0.560761134660957,
0.545498063585615,0.590854855113663,0.486827902942118,
0.187128866890822,- 0.0746523069562551
} };
double prediction = model.Predict(observation);
miscvector.h
static vector<double> ConvertVecOfVecToVec(const vector<vector<double>> &mat)
{
vector<double> targetsVec;
targetsVec.reserve(mat.size());
for (size_t i = 0; i < mat.size(); i++)
{
targetsVec.push_back(mat[i][0]);
}
return targetsVec;
}
libsvmtargetobjectconvertor.h
#pragma once
#include "machinelearning.h"
struct svm_node;
class LibSvmTargetObservationConvertor
{
public:
svm_node ** LibSvmTargetObservationConvertor::ConvertObservations(const vector<MlObservation> &observations, size_t numFeatures) const
{
svm_node **svmObservations = (svm_node **)malloc(sizeof(svm_node *) * observations.size());
for (size_t rowI = 0; rowI < observations.size(); rowI++)
{
svm_node *row = (svm_node *)malloc(sizeof(svm_node) * numFeatures);
for (size_t colI = 0; colI < numFeatures; colI++)
{
row[colI].index = colI;
row[colI].value = observations[rowI][colI];
}
row[numFeatures].index = -1; // apparently needed
svmObservations[rowI] = row;
}
return svmObservations;
}
svm_node* LibSvmTargetObservationConvertor::ConvertMatToSvmNode(const MlObservation &observation) const
{
size_t numFeatures = observation.size();
svm_node *obsNode = (svm_node *)malloc(sizeof(svm_node) * numFeatures);
for (size_t rowI = 0; rowI < numFeatures; rowI++)
{
obsNode[rowI].index = rowI;
obsNode[rowI].value = observation[rowI];
}
obsNode[numFeatures].index = -1; // apparently needed
return obsNode;
}
};
machinelearning.h
#pragma once
#include <vector>
using std::vector;
using MlObservation = vector<double>;
using MlTarget = double;
//machinelearningmodel.h
#pragma once
#include <vector>
#include "machinelearning.h"
class MachineLearningModel
{
public:
virtual ~MachineLearningModel() {}
virtual double Predict(const MlObservation &observation) const = 0;
};
matlabmatrixfilereader.h
#pragma once
#include <vector>
using std::vector;
class FilePath;
// Matrix created with command:
// dlmwrite('my_matrix.txt', somematrix, 'delimiter', ',', 'precision', 15);
// In these files, each row is a matrix row. Commas separate elements on a row.
// There is no space at the end of a row. There is a blank line at the bottom of the file.
// File format:
// 0.4,0.7,0.8
// 0.9,0.3,0.5
// etc.
static class MatlabMatrixFileReader
{
public:
static vector<vector<double>> Read(const FilePath &asciiFilePath, char delimiter)
{
vector<vector<double>> values;
vector<double> valueline;
std::ifstream fin(asciiFilePath.Path());
string item, line;
while (getline(fin, line))
{
std::istringstream in(line);
while (getline(in, item, delimiter))
{
valueline.push_back(atof(item.c_str()));
}
values.push_back(valueline);
valueline.clear();
}
fin.close();
return values;
}
};
supportvectorregressionmodel.h
#pragma once
#include <vector>
using std::vector;
#include "machinelearningmodel.h"
#include "svm.h" // libsvm
class FilePath;
class SupportVectorRegressionModel : public MachineLearningModel
{
public:
SupportVectorRegressionModel::~SupportVectorRegressionModel()
{
svm_free_model_content(model_);
svm_destroy_param(&param_);
svm_free_and_destroy_model(&model_);
}
SupportVectorRegressionModel::SupportVectorRegressionModel(const vector<MlObservation>& observations, const vector<MlTarget>& targets)
{
// assumes all observations have same number of features
size_t numFeatures = observations[0].size();
//setup targets
//auto v = ConvertVecOfVecToVec(targetsMat);
double *targetsPtr = const_cast<double *>(&targets[0]); // why aren't the targets const?
LibSvmTargetObservationConvertor conv;
svm_node **observationsPtr = conv.ConvertObservations(observations, numFeatures);
// setup observations
//svm_node **observations = BuildObservations(observationsMat, numFeatures);
// setup problem
svm_problem problem;
problem.l = targets.size();
problem.y = targetsPtr;
problem.x = observationsPtr;
// specific to out training sets
// TODO: This is hard coded.
// Bust out these values for use in constructor
param_.C = 0.4; // cost
param_.svm_type = 4; // SVR
param_.kernel_type = 2; // radial
param_.nu = 0.6; // SVR nu
// These values are the defaults used in the Matlab version
// as found in svm_model_matlab.c
param_.gamma = 1.0 / (double)numFeatures;
param_.coef0 = 0;
param_.cache_size = 100; // in MB
param_.shrinking = 1;
param_.probability = 0;
param_.degree = 3;
param_.eps = 1e-3;
param_.p = 0.1;
param_.shrinking = 1;
param_.probability = 0;
param_.nr_weight = 0;
param_.weight_label = NULL;
param_.weight = NULL;
// suppress command line output
svm_set_print_string_function([](auto c) {});
model_ = svm_train(&problem, &param_);
}
double SupportVectorRegressionModel::Predict(const vector<double>& observation) const
{
LibSvmTargetObservationConvertor conv;
svm_node *obsNode = conv.ConvertMatToSvmNode(observation);
double prediction = svm_predict(model_, obsNode);
return prediction;
}
SupportVectorRegressionModel::SupportVectorRegressionModel(const FilePath & modelFile)
{
model_ = svm_load_model(modelFile.Path().c_str());
}
private:
svm_model *model_;
svm_parameter param_;
};
Option 1 is actually pretty reasonable. If you save the model in libsvm's C format through matlab, then it is straightforward to work with the model in C/C++ using functions provided by libsvm. Trying to work with matlab-formatted data in C++ will probably be much more difficult.
The main function in "svm-predict.c" (located in the root directory of the libsvm package) probably has most of what you need:
if((model=svm_load_model(argv[i+1]))==0)
{
fprintf(stderr,"can't open model file %s\n",argv[i+1]);
exit(1);
}
To predict a label for example x using the model, you can run
int predict_label = svm_predict(model,x);
The trickiest part of this will be to transfer your data into the libsvm format (unless your data is in the libsvm text file format, in which case you can just use the predict function in "svm-predict.c").
A libsvm vector, x, is an array of struct svm_node that represents a sparse array of data. Each svm_node has an index and a value, and the vector must be terminated by an index that is set to -1. For instance, to encode the vector [0,1,0,5], you could do the following:
struct svm_node *x = (struct svm_node *) malloc(3*sizeof(struct svm_node));
x[0].index=2; //NOTE: libsvm indices start at 1
x[0].value=1.0;
x[1].index=4;
x[1].value=5.0;
x[2].index=-1;
For SVM types other than the classifier (C_SVC), look at the predict function in "svm-predict.c".