I have a small Python module written in C++. This module compiles well and can be imported to Python without any errors. These are some snippets of the code:
//...multiple includes
typedef variant<sqlite3 **, ... other types> VariantData; //!ONE
class ORM{
//... private fields
public:
VariantData Connect(int idx){
if(idx == 0) {
sqlite3 * conn;
sqlite3_open("reestr.db", &conn);
return &conn; //!TWO
// how to return a pointer to conn ???
// am I doing it right ???
}
}
//... other methods
// Python stuff
BOOST_PYTHON_MODULE(corm){
to_python_converter<VariantData, variant_to_object>(); //!THREE
implicitly_convertible<sqlite3 **, VariantData>(); //!THREE
//other unimportant code
So, this code compiles without errors. But,please, pay attention to four lines of code, marked by ONE, TWO and THREE, since they are causing errors. In my interpretation at line ONE I define a variant datatype that can take different values with sqlite3 ** among them. At lines THREE I define Python stuff responsible for converting variables and passing them between C++ and Python. However, I get into trouble when I try to use this module in Python. I do it like:
>>> import corm
>>> c = corm.ORM(...initialization parameters...)
>>> r = c.Connect() # !ERROR
... No to_python (by-value) converter found for C++ type: sqlite *
I really wonder why Python is talking about sqlite * type here, while the method itself does return &conn; and so returns a variable of type sqlite3 ** (as I believe). So, in a nutshell, my question is how to return a pointer of type sqlite3 ** from Connect method.
This is a solution. I'm not sure whether it is good, but at least it works:
typedef variant<void *, ... other types> VariantData;
class ORM{
//... private fields
public:
VariantData Connect(int idx){
if(idx == 0) {
sqlite3 * conn;
sqlite3_open("reestr.db", &conn);
void * ref = ::operator new(sizeof(conn));
ref = conn;
return ref;
}
...
}
....
};
struct variant_to_object {
static PyObject* convert(VariantData const& v){
return boost::python::incref(
boost::python::object(v).ptr());
}
};
BOOST_PYTHON_MODULE(corm){
to_python_converter<VariantData, variant_to_object>();
implicitly_convertible<void *, VariantData>();
But of course, I should take care of ref pointer and delete it, when it is no longer used.
Related
I am working on a Ruby C/C++ Extension and thus far it has been going quite well. However I came across an error that I don't know what to do about it.
I have defined the following ruby data types:
static const rb_data_type_t SmartLib_File_type = {
"SmartLib::File",
{0, SmartLib_File_free, SmartLib_File_size,},
0, 0,
RUBY_TYPED_FREE_IMMEDIATELY,
};
static const rb_data_type_t SmartLib_Plotter_type = {
"SmartLib::Plotter",
{0, SmartLib_Plotter_free, SmartLib_Plotter_size,},
0, 0,
RUBY_TYPED_FREE_IMMEDIATELY,
};
both those data types are being wrapped by their corresponding C++ classes and represented by Ruby classes:
// SmartLib::File
VALUE SmartLib_File_alloc(VALUE self) {
/* allocate */
SmartLib::TransformableFile *data = new SmartLib::TransformableFile();
/* wrap */
return TypedData_Wrap_Struct(self, &SmartLib_File_type, data);
}
// SmartLib::Plotter
VALUE SmartLib_Plotter_alloc(VALUE self) {
/* allocate */
SmartLib::Plotter *data = new SmartLib::Plotter();
/* wrap */
return TypedData_Wrap_Struct(self, &SmartLib_Plotter_type, data);
}
In order to make unwrapping of those C/C++ data easier, I have also two macros defined to help with this:
#define UNWRAP_SMART_FILE(obj, fp) \
SmartLib::TransformableFile* fp;\
TypedData_Get_Struct((obj), SmartLib::TransformableFile, &SmartLib_File_type, (fp));
#define UNWRAP_SMART_PLOTTER(obj, pp) \
SmartLib::Plotter* pp;\
TypedData_Get_Struct((obj), SmartLib::Plotter, &SmartLib_Plotter_type, (pp));
Now, I have a Ruby method plot in the SmartLib::Plotter class, with the following definition:
VALUE SmartLib_Plotter_plot(VALUE self, VALUE rb_oFile, VALUE rb_sTemplatePath) {
UNWRAP_SMART_PLOTTER(self, smartPlotter);
UNWRAP_SMART_FILE(rb_oFile, smartFile);
// do stuff
return self;
}
which is callable from Ruby like so:
sf = SmartLib::File.new(file_path)
p = SmartLib::Plotter.new
p.plot(sf, template_path)
The problem arises on the UNWRAP_SMART_FILE(rb_oFile, smartFile); line int he plot method, so when the corresponding C/C++ data gets unwrapped. Ruby throws an exception:
TypeError:
wrong argument type SmartLib::File (expected SmartLib::File)
In other areas of the code the call to UNWRAP_SMART_FILE always works as expected. Also the error message clearly doesn't make sense?
Any help is kindly appreciated!
I want to pass a string "Device Name" to a void * pointer argument of a method and retrieve it to a character array later.
For this I've done as shown below.
Here I have created an action to achieve this.
ACTION_P(SetArg2ToChar, value) {*static_cast<char*>(arg2) = *value; }
Actual method to be called/mocked
bool getDictItem(WORD wIndex, BYTE bSubIndex, void * pObjData, DWORD dwLength, CSdo& sdo)
My mock method
MOCK_METHOD5(getDictItem,
bool(WORD wIndex, BYTE bSubIndex, void * pObjData, DWORD dwLength, CSdo& sdo));
in code it is called as
if( !can.getDictItem(wIndex, bSubIndex, pObjData, dwLength, tSdo) )
I want to pass a string to this pObjData (3rd argument in the list).
In my google tests, I'm doing like this.
char szDeviceName[30]= {0};
snprintf(szDeviceName, sizeof(szDeviceName), "%s", "Device Name" );
EXPECT_CALL( mockCan, getDictItem(_,_,_,_,_) )
.WillOnce(DoAll(SetArg2ToChar(szDeviceName),
Return(true)))
.RetiresOnSaturation();
/* Call a real method within which this mock method is called */
If I try to set this argument(pObjData) using "SetArgPointee<2>" directly, I get the below error.
error: 'void' is not a pointer-to-object type*
Hence I'm trying with ACTION_P
Now with this implementation, I only get the first letter of the szDeviceName variable (into this pObjData) i.e., "D" followed by 29 0's in the real code flow after this mock object is called.
I want to get the full string name set into this void * arguement.
I refered to this below question and was able progress this far. But I'm not able to pass the full string. How to set, in google mock, a void* argument to a set of values?
Any information regarding this will be helpful.
Rather then doing that, you could invoke a function (or a method) and copy the parameter.
Something like this in the source file where the test is :
int invokedPObjData;
bool FakeGetDictItem(WORD wIndex, BYTE bSubIndex, void * pObjData, DWORD dwLength, CSdo& sdo)
{
// copy data. here I assumed it is an int
invokedPObjData = *static_cast< int* >( pObjData );
return true; // or whatever makes sense
}
in test :
EXPECT_CALL( mockCan, getDictItem(_,_,_,_,_) )
.WillOnce(Call(FakeGetDictItem))
.RetiresOnSaturation();
then later in test check what needs to be checked.
The ACTION_P approach is basically OK. But as you are dealing with a C string, you can't just use the assignment operation (which just copies the first character) but instead you should use a string copy function like ACTION_P(SetArg2ToCharWithSizeArg3, value) { strcpy_s(static_cast<char*>(arg2), arg3, value); } (I couldn't resist to slightly rename the action).
I recently had a similar need and came up with this as a generic solution. It's based on the built-in SetArgPointee and has the same syntax:
template <size_t N, typename A>
class SetArgumentPointeeVoidAction {
public:
explicit SetArgumentPointeeVoidAction(const A& value) : value_(value) {}
void operator=(SetArgumentPointeeVoidAction const&) = delete;
template <typename Result, typename ArgumentTuple>
void Perform(const ArgumentTuple& args) const
{
::testing::StaticAssertTypeEq<void, Result>();
::testing::StaticAssertTypeEq<void*,
std::decay<decltype(::testing::get<N>(args))>::type>();
*static_cast<A*>(::testing::get<N>(args)) = value_;
}
private:
const A value_;
};
/**
* \brief Sets a \c void* output argument to the contents of the
* supplied object. It's on you to ensure this is safe.
* \tparam N The argument index.
* \tparam T The real argument type.
* \param x The argument to assign to the output argument.
* \return A GMock Action that performs the requested assignment.
* \note Use \c SetArgPointee when it's not a \c void*.
*/
template <size_t N, typename T>
::testing::PolymorphicAction< SetArgumentPointeeVoidAction<N, T> >
SetArgPointeeVoid(const T& x)
{
return ::testing::MakePolymorphicAction(
SetArgumentPointeeVoidAction<N, T>(x));
}
It will give you a compile error if you try to use this on an argument that isn't a void*, so it should be relatively safe as long as you ensure you supply the correct argument.
It's also possible to implement this using ACTION_TEMPLATE, which is a bit shorter, but it generates unused argument warnings, which can be irritating.
(In older versions of GMock you might have to use ::std::tr1::get instead of ::testing::get.)
Left as an exercise for the reader: it's possible to enhance this with perfect forwarding to allow this to move-construct and move-assign for a slight efficiency boost. Although if you're passing anything other than PODs around as void*s then you're probably doing it wrong.
Here is an example using ACTION_TEMPLATE allowing a string to be assigned to a void *, for reference...
ACTION_TEMPLATE(StrCpyArgToVoidPointer,
HAS_1_TEMPLATE_PARAMS(int, k),
AND_2_VALUE_PARAMS(value, size))
{
strncpy(static_cast<char *>(::testing::get<k>(args)), value, size);
return;
}
Please find the steps to set Void Pointer variable in class using invoke Method.
//Actual Function under Test
void testFunction(void)
{
uint16 Frequency;
uint8 PwmId;
uint8 DutyCycle;
Frequency = PORTEXTENDER_ZERO;
PwmId = PORTEXTENDER_ZERO;
DutyCycle = PORTEXTENDER_ZERO;
//for this mock is available and we need to set value of Ex. PwmId
IncCom_ReceiveSignal(SCC_PORT_EXTENDER_PWM_C_SET_PWM_Id, &PwmId);
if((PwmId <= PORTEXTENDER_NUM_PWM_CHANNELS) && (DutyCycle <= 100))
{
}
// Actual Defination of mock ..where we have to set void pointer
void mock_defination(PortExtender_C_SignalId_e SignalId, void* SignalDataPtr)
{
}
//cpp Test class
class testClass : public :: testing :: Test
{
protected:
/* Fixture tear down */
virtual void TearDown()
{
}
uint8 testval1{1};
public:
void setTestvalue(uint8 val) // if we want to set multiple time
{
testval1= val;
}
void test1(PortExtender_C_SignalId_e SignalId, void* SignalDataPtr) //this is method to invoke from test_F
{
* (uint8*)SignalDataPtr =testval1;
}
}
//Test Case
TEST_F(testClass,
testcase_PortExtender_CompStatusResponse_ifConditionSatisfied)
{
setTestvalue(1); //To Set Value
EXPECT_CALL(m_portExtender_SomeIpMock,m_C_Signal(SCC_PORT_EXTENDER_C_COMPONENT_STATUS_HostApplStat,_))
.WillOnce(Invoke(this,&testClass::test1));
}
I am using Boost Python, I generate a large vector of integers in C++, and I would like to access this vector in Python without copying it.
In C++ I have:
BOOST_PYTHON_MODULE(myModule)
{
class_<vector<int>>("vectorInt").def(vector_indexing_suite<vector<int>>());
def("ReturnVectorPtr", ReturnVectorPtr, return_value_policy<manage_new_object>());
}
vector<int>* ReturnVectorPtr()
{
return new vector<int>();
}
Then in python I have:
import myModule
myModule.ReturnVectorPtr()
This causes Python to crash, although I'm not even storing the return value. Any ideas on what my mistake is?
Edit:
The following code works for getting the data in the vector from C++ to python, but leaks memory. Are the vectors being copied and then not disposed?
In C++:
BOOST_PYTHON_MODULE(myModule)
{
class_<vector<int>>("vectorInt").def(vector_indexing_suite<vector<int>>());
def("ModifyVectorInPlace", ModifyVectorInPlace);
}
void ModifyVectorInPlace(vector<int>& data)
{
// Modify data...
return;
}
Then in python I have:
import myModule
vectorInt = myModule.vectorInt()
myModule.ModifyVectorInPlace(vectorInt)
What is going on?
Edit 2:
I tried the "Raw C++ Pointers" example from here, exactly as written:
https://wiki.python.org/moin/boost.python/PointersAndSmartPointers
It crashes too. It seems that I can't get a pointer to anything passed into Python for some reason...
Edit 3:
The crash appears to be a segfault from invoke.hpp, in this function:
template <class RC, class F BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, class AC)>
inline PyObject* invoke(invoke_tag_<false,false>, RC const& rc, F& f BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(1, N, AC, & ac) )
{
return rc(f( BOOST_PP_ENUM_BINARY_PARAMS_Z(1, N, ac, () BOOST_PP_INTERCEPT) ));
}
It turns out this was a bug in the interaction between Mingw-w64 and Python. I performed the procedure described here and the problem was solved:
http://ascend4.org/Setting_up_a_MinGW-w64_build_environment#Setup_Python_for_compilation_of_extensions
I have some class with Load() function, for example.
class DB {
private:
pt_db *db;
public:
DB(const char *path);
Write(const char *path);
int Load(const char *path);
};
And I want to return some status from Load() function depending on the passed argument.
For example:
Load(<correct path to the file with valid content>) // return 0 - success
Load(<non-existent path to file>) // return 1
Load(<correct file path, but the content of the file is wrong>) // return 2
Nevertheless also I'm worrying about:
Type safety - I mean I want to return some object which could only be used as status code.
int res = Load(<file path>);
int other = res * 2; // Should not be possible
Use only predefined values. With int I can return, by error, some other status like return 3 (let's suggest something wrong has happened in Load() function) and if I don't expect this error code will be passed:
int res = Load(<file path>);
if(res == 1) {}
else if (res == 2) {};
...
// Here I have that code fails by reason that Load() returned non-expected 3 value
Use best C++11 practises about it.
Could anyone help?
Enums would be a good way to return status for example:
class Fetcher{
public:
enum FetchStatus{ NO_ERROR, INVALID_FILE_PATH, INVALID_FILE_FORMAT };
private:
FetchInfo info;
public:
FetchStatus fetch(){
FetchStatus status = NO_ERROR;
//fetch data given this->info
//and update status accordingly
return status;
}
};
Another way would be to use exceptions
class Fetcher{
private:
FetchInfo info;
public:
void fetch(){
if file does not exist throw invalid file path exception
else if file is badly formatted throw invalid file format exception
else everything is good
}
Using enums as return status is more C way and using exceptions might be more C++ way, but its a matter of choice. I like the enum version as it is less code and more readable in my opinion.
I need some advice how can I bind a C/C++ structure to Ruby. I've read some manuals and I found out how to bind class methods to a class, but I still don't understand how to bind structure fields and make them accessible in Ruby.
Here is the code I'm using:
myclass = rb_define_class("Myclass", 0);
...
typedef struct nya
{
char const* name;
int age;
} Nya;
Nya* p;
VALUE vnya;
p = (Nya*)(ALLOC(Nya));
p->name = "Masha";
p->age = 24;
vnya = Data_Wrap_Struct(myclass, 0, free, p);
rb_eval_string("def foo( a ) p a end"); // This function should print structure object
rb_funcall(0, rb_intern("foo"), 1, vnya); // Here I call the function and pass the object into it
The Ruby function seems to assume that a is a pointer. It prints the numeric value of the pointer instead of it's real content (i.e., ["Masha", 24]). Obviously the Ruby function can't recognize this object —I didn't set the object's property names and types.
How can I do this? Unfortunately I can't figure it out.
You have already wrapped your pointer in a Ruby object. Now all you have to do is define how it can be accessed from the Ruby world:
/* Feel free to convert this function to a macro */
static Nya * get_nya_from(VALUE value) {
Nya * pointer = 0;
Data_Get_Struct(value, Nya, pointer);
return pointer;
}
VALUE nya_get_name(VALUE self) {
return rb_str_new_cstr(get_nya_from(self)->name);
}
VALUE nya_set_name(VALUE self, VALUE name) {
/* StringValueCStr returns a null-terminated string. I'm not sure if
it will be freed when the name gets swept by the GC, so maybe you
should create a copy of the string and store that instead. */
get_nya_from(self)->name = StringValueCStr(name);
return name;
}
VALUE nya_get_age(VALUE self) {
return INT2FIX(get_nya_from(self)->age);
}
VALUE nya_set_age(VALUE self, VALUE age) {
get_nya_from(self)->age = FIX2INT(age);
return age;
}
void init_Myclass() {
/* Associate these functions with Ruby methods. */
rb_define_method(myclass, "name", nya_get_name, 0);
rb_define_method(myclass, "name=", nya_set_name, 1);
rb_define_method(myclass, "age", nya_get_age, 0);
rb_define_method(myclass, "age=", nya_set_age, 1);
}
Now that you can access the data your structure holds, you can simply define the high level methods in Ruby:
class Myclass
def to_a
[name, age]
end
alias to_ary to_a
def to_s
to_a.join ', '
end
def inspect
to_a.inspect
end
end
For reference: README.EXT
This is not a direct answer to your question about structures, but it is a general solution to the problem of porting C++ classes to Ruby.
You could use SWIG to wrap C/C++ classes, structs and functions. In the case of a structure, it's burning a house to fry an egg. However, if you need a tool to rapidly convert C++ classes to Ruby (and 20 other languages), SWIG might be useful to you.
In your case involving a structure, you just need to create a .i file which includes (in the simplest case) the line #include <your C++ library.h>.
P.S. Once more, it's not a direct answer to your question involving this one struct, but maybe you could make use of a more general solution, in which case this may help you.
Another option is to use RubyInline - it has limited support for converting C and Ruby types (such as int, char * and float) and it also has support for accessing C structurs - see accessor method in the API.