Or any similar data structure of dynamic length, which, can be cast easily to an array. The only workaround I have found is entering the array as a string and manually parsing it.
config var not_array: string = '[1,2,3,4,5]' ;
proc main() {
// config array workaround
writeln("I am string. Definitely not array ", not_array) ;
// parse string
not_array = not_array.replace(' ','') ;
not_array = not_array.replace('[','') ;
not_array = not_array.replace(']','') ;
var still_not_array = not_array.split(',') ;
// prepare array
var dom = 0..#still_not_array.size ;
var array: [dom] real ;
// populate array
for (i, x) in zip(dom, still_not_array) {
array[i] = x:real ;
}
writeln("Ha! Tricked you, am actually array ", array) ;
}
This works as intended, but is there a better way?
Is it possible to declare an array with config?
No, this is not yet supported in Chapel as of Chapel 1.16.
That said, there are ways to work around this as you demonstrate.
As an alternative work-around, you can utilize IO calls to write the input string to memory and then read it in as an array, e.g.
config type arrType = int;
config const arrSize = 3,
arrString = '1 2 3';
var A : [1..arrSize] arrType;
// Create a memory buffer to write in
var f = openmem();
// Create a writer on the memory buffer and write the input string
var w = f.writer();
w.writeln(arrString);
w.close();
// Create a reader on the memory buffer and read the input string as an array
var r = f.reader();
r.readln(A);
r.close();
writeln(A);
Note this requires the array size up front. I think you'd have to do some string processing like your original example to compute that on the fly.
Some resources:
IO.openmem()
IO.channel.readln()
Related
The official flutter tutorial on C/C++ interop through ffi only touches on calling a C++ function and getting a single return value.
Goal
What if I have a data buffer created on C/C++ side, but want to deliver to dart/flutter-side to show?
Problem
With #MilesBudnek 's tip, I'm testing Dart's FFI by trying to have safe memory deallocation from Dart to C/C++. The test reuses the official struct sample .
I could get the Array as a dart Pointer, but it's unclear to me how to iterate the array as a collection easily.
Code
I'm implementing a Dart-side C array binding like this:
In struct.h
struct Array
{
int* array;
int len;
};
and a pair of simple allocation/deallocation test functions:
struct Array* get_array();
int del_array(struct Array* arr);
Then on Dart side in structs.dart:
typedef get_array_func = Pointer<Array> Function();
typedef del_array_func = void Function(int arrAddress);
...
final getArrayPointer = dylib.lookup<NativeFunction<get_array_func>>('get_array');
final getArray = getArrayPointer.asFunction<get_array_func>();
final arrayPointer = getArray();
final array = arrayPointer.ref.array;
print('array.array: $array');
This gives me the print out
array.array: Pointer<Int32>: address=0x7fb0a5900000
Question
Can I convert the array pointer to a List easily? Something like:
final array = arrayPointer.ref.array.toList();
array.forEach(index, elem) => print("array[$idx]: $elem");
======
Old Question (you can skip this)
Problem
It's unclear to me how to retrieve this kind of vector data from C/C++ by dart/flutter.
Possible solutions
More importantly, how to push data from C++ side from various threads?
If there is no builtin support, off the top of my head I'd need to implement some communication schemes.
Option #1: Networking
I could do network through TCP sockets. But I'm reluctant to go there if there are easier solutions.
Option #2: file I/O
Write data to file with C/C++, and let dart/flutter poll on the file and stream data over. This is not realtime friendly.
So, are there better options?
Solved it.
According to this issue, the API asTypedList is the way to go.
Here is the code that works for me
final getArrayPointer = dylib.lookup<NativeFunction<get_array_func>>('get_array');
final getArray = getArrayPointer.asFunction<get_array_func>();
final arrayPointer = getArray();
final arr = arrayPointer.ref.arr;
print('array.array: $arr');
final arrReal = arr.asTypedList(10);
final arrType = arrReal.runtimeType;
print('arrReal: $arrReal, $arrType');
arrReal.forEach((elem) => print("array: $elem"));
This gives me:
array.array: Pointer<Int32>: address=0x7f9eebb02870
arrReal: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], Int32List
array: 0
array: 1
array: 2
array: 3
array: 4
array: 5
array: 6
array: 7
array: 8
array: 9
asTypedList will only work with pointers that relate to TypedData.
there are other cases where, for example, you want to convert an Pointer<UnsignedChar> to a Uint8List, in this case you can:
use an extension and then either cast the Pointer<UnsignedChar to a Pointer<Uint8> and then use asTypedList. In this case you have to make sure the pointer is not freed while the Uint8List is still referenced.
extension UnsignedCharPointerExtension on Pointer<UnsignedChar> {
Uint8List? toUint8List(int length) {
if (this == nullptr) {
return null;
}
return cast<Uint8>().asTypedList(length);
}
}
use an extension and don't cast the pointer but copy it manually. In this case you can free the pointer after you get the Uint8List
extension UnsignedCharPointerExtension on Pointer<UnsignedChar> {
Uint8List? toUint8List(int length) {
if (this == nullptr) {
return null;
}
final Uint8List list = Uint8List(length);
for (int i = 0; i < length; i++) {
list[i] = this[i];
}
return list;
}
}
I'm super new to C++ and am trying to build a json file that contains x0...x7 of the files that gets parsed from a pre-defined function so that it can compose a JSON string to give to R. so that it can open a socket to R and send this piece of JSON to it.
however, im kinda stuck here, here is what i have:
std::map<std::string,std::string>::const_iterator qIter;
std::string variable;
std::map<string,string> mymap;
variable = "x";
for (int i=1,i<=7,i++){
float variable+i = ( (qIter = request.getQuery().find(variable+i))
== request.getQuery().end()
)
? 0.0
: atof(qIter->second.c_str());
if ( !isLegalNumber(request.getQuery(),variable+i,variable+i) )
{
strcpy(filePath,"yourErrorFilename.html");
}
else
{
// I want to add the x0 or xn variable here into a json
// The value is now in variable 'x'of something
}
}
Any insights appreciated.
edit: here's my isLegalNumber() method
bool isLegalNumber (const std::map<std::string,std::string>&
map,
const std::string& varName,
float& value
)
{
float temp;
char* cPtr;
std::map<std::string,std::string>::const_iterator
iter = map.find(varName);
if (iter == map.end())
return(false);
temp = strtod(iter->second.c_str(),&cPtr);
if ( (*cPtr != '\0') || (cPtr == iter->second.c_str()) )
return(false);
value = temp;
return(true);
}
im trying to convert a string/ dictionary into a json,
the first question would be how to add it into a dictionary,
and second, how to convert that dictionary into JSON.
basically i want the json to look like
{
x1: value of x1,
x2: value of x2,
....
x7: value of x7
}
I'm not totally clear what you're trying to do in your example code. Specifically, I don't know what the string value variable is used for. I'm guessing you actually want to define an array of floats. You can also skip the first step where you're setting the value to either 0.0 or atof(...) since your isLegalNumber function sets it later anyway. e.g.
float x[8] = {0.0f};
// Note that arrays in C++ are zero-indexed, so your iteration variable should start at 0
for (int i=0; i<=7; i++) {
std::string varName = "x";
varName.push_back(std::to_string(i+1)); // Append the index
if ( !isLegalNumber(request.getQuery(), varName, x[i] ) {
// Error
} else {
// Add to JSON structure
}
}
Once you've got that sorted out, for working with JSON in C++, I would strongly recommend using an existing open-source library such as JSON for Modern C++, rather than rolling your own implementation. This will make it much easier to build the JSON structure you need and ensure that it is properly formatted.
That library has quite thorough documentation, and it allows you to define JSON structures using very similar syntax to the actual JSON you're trying to write, e.g.
json j2 = {
{"pi", 3.141},
{"happy", true},
{"name", "Niels"},
// ...
};
Or in your specific case, define json j; outside the loop, and then in your if case you can do:
j[varName] = x[i];
And then you can convert it to a string using std::string s = j.dump();.
I am trying to type a typemap(out) std::vector.
I want it to get to the perl code as an array instead I am getting an array of arrays which after a double dereference contains the desired data.
how can I make it an array of strings in perl?
I have tried to edit the typemap myself and to use the typemaps in the "std_vector.i" and in "std_string.i" without editing and they all give the same results.
this is the typemap code:
%typemap(out) std::vector<std::string> {
int len = $1.size();
SV *svs = new SV[len];
for (int x = 0; x < len; x++) {
SV* sv = sv_newmortal();
sv_setpvn(sv, $1[x].data(), $1[x].size());
svs[x] = SvPV(sv, $1[x].size());
}
AV *myav = av_make(len, svs);
delete[] svs;
$result = newRV_noinc((SV*) myav);
sv_2mortal($result);
argvi++;
}
my code for testing the output:
#this return a std vector<string> in the cpp code
my #commitReturn = $SomeClass->commit();
print "\n";
#this should return a string instead it returns an array.
print $commitReturn[0];
print "\n";
#this should not work, instead it returns the desired output.
print $commitReturn[0][0];
the output is:
ARRAY(0x908c88)
20790
instead of:
20790
Can't use string ("20791") as an ARRAY ref while "strict refs"
Your commit method is just returning an array reference, not an array of array references. Maybe it looks like an array of array references because you are assigning the result to an array?
In any case, without touching the typemap code, you can dereference the function call
#commitReturn = #{$SomeClass->commit()};
or create a wrapper method to dereference it for you
package SomeClass;
...
sub commit_list {
my $self = shift;
#{$self->commit()};
}
...
#commitReturn = $SomeClass->commit_list();
To return an array instead of a reference to an array, you have to manipulate the stack such that Perl knows that more than one scalar is returned.
According to the documentation:
The current value of the argument stack pointer is contained in a
variable argvi. Whenever a new output value is added, it is critical
that this value be incremented. For multiple output values, the final
value of argvi should be the total number of output values.
So the following typemap should be sufficient:
%typemap(out) std::vector<std::string> {
int len = $1.size();
for (int x = 0; x < len; x++) {
$result = sv_newmortal();
sv_setpvn($result, $1[x].data(), $1[x].size());
argvi++;
}
}
I am working on bridging between a C++ class and Swift. I know I can only interface with c and Objective C so I am writing a wrapping function in c.
I need to return some data that I have packaged in a structure and with the structure holding an array of unknown length. All this needs to be done with only c to interface with Swift.
My structure looks as follows:
struct Output {
double DataA;
long DataArrayLength;
double *DataArray;
};
I have written the following function in c to package the data:
struct Output* GetData( double InputA) {
struct Output output;
output.DataArrayLength = 100; // The length will only be known at run time and
// once I get into this function.
output.DataArray = new double[output.DataArrayLength];
///
Fill in the data array - some complicated calculations behind this.
output.DataArray[0] = 12345.0;
output.DataArray[99] = 98761.0;
///
return &output; // Getting warning Address of stack associated with local variable 'output' returned.
}
From Swift I can then call
var swoutput = GetData( 1.0)
var count = swoutput.memory.DataArrayLength
My questions are:
Is there a better way do do this? How?
How should I allocate, pass, return the Output struct? I realize the problem with the current method but not sure the best fix.
I still need to release the memory from DataArray. I think I need to do this from the Swift code. How do I do this?
You have to do:
Output* GetData( double InputA) {
Output* output = new Output;
output->DataArrayLength = 100; // The length will only be known at run time and
// once I get into this function.
output->DataArray = new double[output->DataArrayLength];
/// Fill in the data array - some complicated calculations behind this.
output->DataArray[0] = 12345.0;
output->DataArray[99] = 98761.0;
///
return output;
}
And don't forget:
void DeleteOutput(Output* output)
{
if (output == nullptr) {
return;
}
delete [] output->DataArray;
delete output;
}
I'm having problems with marshaling in VB.NET to C++, here's the code :
In the C++ DLL :
struct APP_PARAM
{
int numData;
LPCSTR *text;
int *values;
};
int App::StartApp(APP_PARAM params)
{
for (int i = 0; i < numLines; i++)
{
OutputDebugString(params.text[i]);
}
}
In VB.NET :
<StructLayoutAttribute(LayoutKind.Sequential)> _
Public Structure APP_PARAM
Public numData As Integer
Public text As System.IntPtr
Public values As System.IntPtr
End Structure
Declare Function StartApp Lib "AppSupport.dll" (ByVal params As APP_PARAM) As Integer
Sub Main()
Dim params As APP_PARAM
params.numData = 3
Dim text As String() = {"A", "B", "C"}
Dim textHandle As GCHandle = GCHandle.Alloc(text)
params.text = GCHandle.ToIntPtr(textHandle)
Dim values As Integer() = {10, 20, 30}
Dim valuesHandle As GCHandle = GCHandle.Alloc(values)
params.values = GCHandle.ToIntPtr(heightHandle)
StartApp(params)
textHandle.Free()
valuesHandle.Free()
End Sub
I checked the C++ side, the output from the OutputDebugString is garbage, the text array contains random characters. What is the correct way to do this?
GCHandle.Alloc "Allocates a Normal handle for the specified object", which "creates a handle to a managed object ... which prevents the managed object from being collected".
What you're looking for is the methods from System.Runtime.InteropServices.Marshal, which allow you to do things like copy managed objects to memory accessible by unmanaged code. Unfortunately, according to this, the pointers in your struct make it a little harder to marshal than many other things (in the sense that many other things can be automatically marshalled using the appropriate P/Invoke attributes), but it's still possible. I've tried this out and it works:
APP_PARAM param = new APP_PARAM();
string[] text = new string[] { "A", "B", "C" };
param.numData = text.Length;
// Manually allocate an array of pointers, one for each string. arr holds the array's address.
IntPtr arr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)) * text.Length);
try
{
param.text = arr;
IntPtr[] unmanagedText = new IntPtr[text.Length];
try
{
// Create a null-terminated ANSI string in unmanaged memory for each element in text.
for (int i = 0; i < text.Length; i++)
unmanagedText[i] = Marshal.StringToHGlobalAnsi(text[i]);
// Copy the addresses of the unmanaged strings into the manually allocated array.
// I don't know of any way to make an unmanaged copy of a managed array in one call.
Marshal.Copy(unmanagedText, 0, arr, unmanagedText.Length);
// param now looks like what the C++ code is expecting (except for the array of int).
StartApp(param);
}
finally
{
foreach (IntPtr str in unmanagedText)
Marshal.FreeHGlobal(str);
}
}
finally
{
Marshal.FreeHGlobal(arr);
}
You'll have to have similar allocation/free code for your array of int values, with its own try/finally blocks to make sure FreeHGlobal is called.
You need to use one of the methods from the Marshal class.
Dim str As String = "Hello World"
Dim ptr as IntPtr = Marshal.StringToHGlobalAnsi(str)
Try
SomePInvokeCall(ptr)
Finally
Marshal.FreeHGlobal(ptr)
End Try