How can rust safely drop a cpp array through FFI? - rust

I have a array T* which is created like the following
T* array = new T[len];
// Some initialization codes
We know we can delete the array like
delete [] array;
However, I am writing a Rust FFI program with C++. I have sent this array pointer to the Rust part of my code, and I want to delete the code now.
So I can implement a function ffi_delete_array_of_T on the C++ part, and the Rust part code will call the function through FFI, attached with the argument array.
void ffi_delete_array_of_T(void * arr) {
delete [] reinterpret_cast<T *>(arr);
}
However, I already have a function which can delete single element of T.
void ffi_delete_pointer_of_T(void * arr) {
delete reinterpret_cast<T *>(arr);
}
These two functions are so similar that I wonder if I can combined them into one, so I don't need to write two copy.
void ffi_delete_whatever_of_T(void * arr, bool is_array) {
if (is_array)
delete [] reinterpret_cast<T *>(arr);
else
delete reinterpret_cast<T *>(arr);
}
However, I still think the above codes redundant. I wonder if I only give ffi_delete_pointer_of_T, is it possible the Rust do some magic, and have ffi_delete_array_of_T for me?
To the best of my knowledge, it is not possible. C++ can delete [] a array without hint of length, because it has already stored the length of array somewhere when array is allocated. However, the Rust part don't know the actual length of this array.
However, I still wonder if there are some other ways to do that?

Related

Populating a std::vector map using the operator[]?

Am I overcomplicating this? Since I recently learned that with std::vector you can use the [] operator and it will add the entry if missing.
I have something a little more detailed:
using WeekendFutureItemHistMap = std::map<CString, std::vector<COleDateTime>>;
using WeekendFutureHistMap = std::map<WeekendHistAssign, WeekendFutureItemHistMap>;
WeekendHistAssign is just an enum class.
In my function I am populating it this way:
if (m_mapScheduleFutureHist[eHistAssign].find(strName) != m_mapScheduleFutureHist[eHistAssign].end())
m_mapScheduleFutureHist[eHistAssign][strName].push_back(datAssign);
else
{
m_mapScheduleFutureHist[eHistAssign].emplace(strName, std::vector<COleDateTime>{datAssign});
}
According to the std::vector operator[] it states:
Returns a reference to the element at specified location pos. No bounds checking is performed.
As a result it seemed the right thing to do is test for the existing first as done.
Did I overcomplicate it?
std::vector<int> v;
v.resize(100);
v[0]=1;
v[1]=10;
...

Convert an iterable object to tuple in python C api

I have an iterable PyObject that I need to pass as the list of arguments to a Python callable, ala
xs = [1,2,5,7]
some_function(*xs)
However, PyObject_CallObject only allows tuples to be passed as the arguments' container.
I'm not sure, though, what is the best way to create a new tuple containing the elements of an iterable. Here's a tentative code:
PyObject* unpack_call(PyObject* callable, PyObject* args) {
PyObject* tuple;
if (PyTuple_Check(args)) {
tuple = args;
} else {
PyObject* iter = PyObject_GetIter(args);
if (!iter) return NULL;
tuple = PyTuple_New(0);
for (Py_ssize_t pos=0; ; ++pos) {
PyObject* arg = PyIter_Next(iter);
if (!arg) break;
PyTuple_SetItem(tuple,pos,arg);
}
}
return PyObject_CallObject(callable,tuple);
}
I'm not sure if I need to grow the size of the tuple myself or not. What's confusing me is the sentence in the documentation saying:
The tuple will always grow or shrink at the end.
I'm also not sure if I need to increment or decrement reference counts for any of these objects.
You're much better using PySequence_Tuple which can create a tuple directly from an iterable. There's probably other similar options to do this too.
If you did want to do it your way then you do need to call PyTuple_Resize each time you add to it (or resize it in chunks possibly). What the sentence
The tuple will always grow or shrink at the end.
tells you is that extra space is at the end of the tuple.
PyTuple_SetItem steals a reference, so you don't need to touch the reference count of the items you're adding. You should be doing some error checking though - PyIter_Next can raise an exception. You also need to decref iter and the tuple when you're done with them.

Is it possible to define a CAPL function returning a text string?

I develop CAPL scripts in Vector CANoe, and I need to define several functions returning text strings. In C, I would write something like this:
char * ErrorCodeToMsg(int code)
or
char [] ErrorCodeToMsg(int code)
In CAPL, both definitions fail with a parse error. The only working solution I came up with so far is:
variables {
char retval[256];
}
void ErrorCodeToMsg(int code) {
char [] msg = "Hello word";
strncpy(retval, msg, 256);
}
Of course this is very ugly, because each call to ErrorCodeToMsg requires two statements instead of one. Is there a better way?
You have to do it as you would do with string-based functions :
void ErrorCodeToMsg(char buffer[], int code){
buffer = myListOfCodes[code];
}
The value will be stored in the buffer using its reference value. It is not possible to return string in Capl. This is why you can't access String System variables using the # Selector.
I have implemented a workaround for functions which return string constants. It consists in defining an array of possible return values char errorMsg[][] and defining a function int ErrorCodeToMsg(errno) which is returns and index in that array, so it is called like this:
write("Error: %s", errorMsg[ErrorCodeToMsg(errno)]);
Note that this method is error-prone when coded manually, because it's easy to get the function and the array out of sync after a modification. In my case, error codes are defined in a specification (XML file), so that array of error messages and the ErrorCodeToMsg function are automatically generated.

Inconsistencies when using UnsafeMutablePointer with String or Character types

I'm currently trying to implement my own DynamicArray data type in Swift. To do so I'm using pointers a bit. As my root I'm using an UnsafeMutablePointer of a generic type T:
struct DynamicArray<T> {
private var root: UnsafeMutablePointer<T> = nil
private var capacity = 0 {
didSet {
//...
}
}
//...
init(capacity: Int) {
root = UnsafeMutablePointer<T>.alloc(capacity)
self.capacity = capacity
}
init(count: Int, repeatedValue: T) {
self.init(capacity: count)
for index in 0..<count {
(root + index).memory = repeatedValue
}
self.count = count
}
//...
}
Now as you can see I've also implemented a capacity property which tells me how much memory is currently allocated for root. Accordingly one can create an instance of DynamicArray using the init(capacity:) initializer, which allocates the appropriate amount of memory, and sets the capacity property.
But then I also implemented the init(count:repeatedValue:) initializer, which first allocates the needed memory using init(capacity: count). It then sets each segment in that part of memory to the repeatedValue.
When using the init(count:repeatedValue:) initializer with number types like Int, Double, or Float it works perfectly fine. Then using Character, or String though it crashes. It doesn't crash consistently though, but actually works sometimes, as can be seen here, by compiling a few times.
var a = DynamicArray<Character>(count: 5, repeatedValue: "A")
println(a.description) //prints [A, A, A, A, A]
//crashes most of the time
var b = DynamicArray<Int>(count: 5, repeatedValue: 1)
println(a.description) //prints [1, 1, 1, 1, 1]
//works consistently
Why is this happening? Does it have to do with String and Character holding values of different length?
Update #1:
Now #AirspeedVelocity addressed the problem with init(count:repeatedValue:). The DynamicArray contains another initializer though, which at first worked in a similar fashion as init(count:repeatedValue:). I changed it to work, as #AirspeedVelocity described for init(count:repeatedValue:) though:
init<C: CollectionType where C.Generator.Element == T, C.Index.Distance == Int>(collection: C) {
let collectionCount = countElements(collection)
self.init(capacity: collectionCount)
root.initializeFrom(collection)
count = collectionCount
}
I'm using the initializeFrom(source:) method as described here. And since collection conforms to CollectionType it should work fine.
I'm now getting this error though:
<stdin>:144:29: error: missing argument for parameter 'count' in call
root.initializeFrom(collection)
^
Is this just a misleading error message again?
Yes, chances are this doesn’t crash with basic inert types like integers but does with strings or arrays because they are more complex and allocate memory for themselves on creation/destruction.
The reason it’s crashing is that UnsafeMutablePointer memory needs to be initialized before it’s used (and similarly, needs to de-inited with destroy before it is deallocated).
So instead of assigning to the memory property, you should use the initialize method:
for index in 0..<count {
(root + index).initialize(repeatedValue)
}
Since initializing from another collection of values is so common, there’s another version of initialize that takes one. You could use that in conjunction with another helper struct, Repeat, that is a collection of the same value repeated multiple times:
init(count: Int, repeatedValue: T) {
self.init(capacity: count)
root.initializeFrom(Repeat(count: count, repeatedValue: repeatedValue))
self.count = count
}
However, there’s something else you need to be aware of which is that this code is currently inevitably going to leak memory. The reason being, you will need to destroy the contents and dealloc the pointed-to memory at some point before your DynamicArray struct is destroyed, otherwise you’ll leak. Since you can’t have a deinit in a struct, only a class, this won’t be possible to do automatically (this is assuming you aren’t expecting users of your array to do this themselves manually before it goes out of scope).
Additionally, if you want to implement value semantics (as with Array and String) via copy-on-write, you’ll also need a way of detecting if your internal buffer is being referenced multiple times. Take a look at ManagedBufferPointer to see a class that handles this for you.

Obtaining a plain char* from a string in D?

I'm having an absolute hell of a time trying to figure out how to get a plain, mutable C string (a char*) from a D string (a immutable(char)[]) to that I can pass the character data to legacy C code. toStringz doesn't work, as I get an error saying that I "cannot implicitly convert expression (toStringz(this.fileName())) of type immutable(char)* to char*". Do I need to recreate a new, mutable array of char and copy the characters over?
If you can change the header of the D interface of that legacy C code, and you are sure that legacy C code will not modify the string, you could make it accept a const(char)*, e.g.
char* strncpy(char* dest, const(char)* src, size_t count);
// ^^^^^^^^^^^^
Yeah, it's not pretty, because the result is immutable.
This is why I always return a mutable copy of new arrays in my code. There's no point in making them immutable.
Solutions:
You could just do
char[] buffer = (myString ~ '\0').dup; //Concatenate a null terminator, then dup
then use buffer.ptr as the pointer.
However:
This wastes a string. A better approach might be:
char[] buffer = myString.dup;
buffer ~= '\0'; //Hopefully this doesn't reallocate
and using buffer.ptr afterwards.
Another solution is to use a method like this one:
char* toStringz(in char[] s)
{
string result;
if (s.length > 0 && s[$ - 1] == '\0') //Is it null-terminated?
{ result = s.dup; }
else { result = new char[s.length + 1]; result[0 .. s.length][] = s[]; }
return result.ptr;
}
This one is the most efficient but also the longest.
(Edit: Whoops, I had a typo in the if; fixed it.)
If you want to pass a mutable char* to a C function, you're going to need to allocate a mutable char[]. string isn't going to work, because it's immutable(char)[]. You can't alter immutable variables, so there is no way to pass a string to a function (C or otherwise) which needs to alter its elements.
So, if you have a string, and you need to pass it to a function which takes a char[], then you can use to!(char[]) or dup and get a mutable copy of it. In addition, if you want to pass it to a C function, you're going to need to append a '\0' to it so that it's zero-terminated. The easiest way to do that is just to do ~= '\0' on the char[], but the more efficient way would probably be to do something like this:
auto cstring = new char[](str.length + 1);
cstring[0 .. str.length] = str[];
cstring[$ - 1] = '\0';
In either case, you then pass cstring.ptr to the C function that you're calling.
If you know that the C function that you're calling isn't going to alter the string, then you can either do as KennyTM suggests and alter the C function's signature in D to take a const(char)*, or you can cast the string. e.g.
auto cstring = toStringz(str);
cfunc(cast(char*)cstring.ptr);
Altering the C function's signature would be more correct and less error-prone though.
It sounds like we may be altering std.conv.to to be smart enough to turn strings into zero-terminated strings when cast to char*, const(char)*, etc. So, once that's done, getting a zero-terminated mutable string should be easier, but for the moment, you pretty much just need to copy the string and append a '\0' to it so that it's zero-terminated. But regardless, you're never going to be able to pass a string to a C function which needs to modify it, because a string can't be mutated.
Without any context on which function you're calling it's hard to say what is the right solution.
Typically, if the C function wants to modify or write to the string it probably expects you to provide a buffer and a length. Usually what I do is:
Allocate a buffer:
auto buffer = new char[](256); // your own length instead of 256 here
And call the C function:
CWriteString(buffer.ptr, buffer.length);
You can try the following :
char a[]="abc";
char *p=a;
Now you can pass pointer 'p' to the array in any function.
Hope it works.

Resources