Skip to main content
added 30 characters in body
Source Link
kh40tika
  • 684
  • 4
  • 13
auto temp_link_p = WSLoopbackOpen(env_p, &err);
if (err != WSEOK) { /* error ... */ }
array_meterp am;
long depth;
mlapi__token leaf_token; // this token seems unused

if (!WSGetArrayTypeWithDepthAndLeafType(link_p, temp_link_p, &am, &depth, &leaf_token)) {
    /* error ... */
}

size_t total_size = 1;
const char *head_p;
int argcount;
vector<int> shape;
vector<string> heads;

for (int i=0; i<depth; ++i) {
    WSGetFunction(temp_link_p, &head_p, &argcount);
    total_size *= argcount;
    shape.push_back(argcount);
    heads.push_back(string(head_p));
    WSReleaseSymbol(link_p, head_p);
}

auto elem_token = WSGetRawType(link_p);

switch (elem_token) {
case WSTK_CDOUBLE:
    total_size *= sizeof(double);
    break;
case WSTK_CFLOAT:
    total_size *= sizeof(float);
    break;
/* case ... */
default:
    /* error ... */
    break;
}

void *array_data = malloc(total_size);
WSGetBinaryNumberArrayData(link_p, am, array_data, total_size, elem_token);
WSReleaseGetArrayState(link_p, temp_link_p, am);
WSClose(temp_link_p);

for (int i=0; i<16; ++i) {
printf("%f\n", ((double*)array_data)[i]);
}
/* do stuff with array */

free(array_data);
vector<int> shape;
vector<string> heads;
size_t total_size = 1;
const char *head_p;
int argcount;
int elem_token;
auto mark = WSCreateMark(link_p);

do {
    WSGetFunction(link_p, &head_p, &argcount);
    total_size *= argcount;
    shape.push_back(argcount);
    heads.push_back(string(head_p));
    WSReleaseSymbol(link_p, head_p);
    elem_token = WSGetRawType(link_p);
} while (elem_token == WSTKFUNC);

switch (elem_token) {
case WSTK_CDOUBLE:
    total_size *= sizeof(double);
    break;
case WSTK_CFLOAT:
    total_size *= sizeof(float);
    break;
/* case ... */
default:
    /* error ... */
    break;
}

WSSeekToMark(link_p, mark, 0);
WSDestroyMark(link_p, mark);

void *array_data;
long *received_dims;
char **received_heads;
long received_depth;

WSGetBinaryNumberArray(
    link_p, &array_data, &received_dims, &received_heads, &received_depth, elem_token);

/* do stuff with array */

// there is a int/long mismatch on received_dims, I don't understand why
WSReleaseBinaryNumberArray(
    link_p, array_data, (int*)received_dims, received_heads, total_size, elem_token);
 
free(array_data);
  • array_meterp is pointer to an opaque internal struct, likely holding array metadata.

  • WSGetBinaryNumberArray* is using platform specific type tokens. They can be found in wstp.h.

  • As of WSTP v4, WSGet*Array (e.g WSGetInteger64Array) are wrappers to WSGetBinaryNumberArray.

  • Temporary link in method 1 just store function heads, attempts to retrieve full exrepssion may fail.

  • Generally the heads in each level are "List".

  • The last head can be "Complex" in case of complex data type. E.g a complex unitary matrix would have 3 depth levelsList, List, and Complex.

auto temp_link_p = WSLoopbackOpen(env_p, &err);
if (err != WSEOK) { /* error ... */ }
array_meterp am;
long depth;
mlapi__token leaf_token; // this token seems unused

if (!WSGetArrayTypeWithDepthAndLeafType(link_p, temp_link_p, &am, &depth, &leaf_token)) {
    /* error ... */
}

size_t total_size = 1;
const char *head_p;
int argcount;
vector<int> shape;
vector<string> heads;

for (int i=0; i<depth; ++i) {
    WSGetFunction(temp_link_p, &head_p, &argcount);
    total_size *= argcount;
    shape.push_back(argcount);
    heads.push_back(string(head_p));
    WSReleaseSymbol(link_p, head_p);
}

auto elem_token = WSGetRawType(link_p);

switch (elem_token) {
case WSTK_CDOUBLE:
    total_size *= sizeof(double);
    break;
case WSTK_CFLOAT:
    total_size *= sizeof(float);
    break;
default:
    /* error ... */
    break;
}

void *array_data = malloc(total_size);
WSGetBinaryNumberArrayData(link_p, am, array_data, total_size, elem_token);
WSReleaseGetArrayState(link_p, temp_link_p, am);
WSClose(temp_link_p);

for (int i=0; i<16; ++i) {
printf("%f\n", ((double*)array_data)[i]);
}
/* do stuff with array */

free(array_data);
vector<int> shape;
vector<string> heads;
size_t total_size = 1;
const char *head_p;
int argcount;
int elem_token;
auto mark = WSCreateMark(link_p);

do {
    WSGetFunction(link_p, &head_p, &argcount);
    total_size *= argcount;
    shape.push_back(argcount);
    heads.push_back(string(head_p));
    WSReleaseSymbol(link_p, head_p);
    elem_token = WSGetRawType(link_p);
} while (elem_token == WSTKFUNC);

switch (elem_token) {
case WSTK_CDOUBLE:
    total_size *= sizeof(double);
    break;
case WSTK_CFLOAT:
    total_size *= sizeof(float);
    break;
default:
    /* error ... */
    break;
}

WSSeekToMark(link_p, mark, 0);
WSDestroyMark(link_p, mark);

void *array_data;
long *received_dims;
char **received_heads;
long received_depth;

WSGetBinaryNumberArray(
    link_p, &array_data, &received_dims, &received_heads, &received_depth, elem_token);

/* do stuff with array */

// there is a int/long mismatch on received_dims, I don't understand why
WSReleaseBinaryNumberArray(
    link_p, array_data, (int*)received_dims, received_heads, total_size, elem_token);
 
free(array_data);
  • array_meterp is pointer to an opaque internal struct, likely holding array metadata.

  • WSGetBinaryNumberArray* is using platform specific type tokens. They can be found in wstp.h.

  • As of WSTP v4, WSGet*Array (e.g WSGetInteger64Array) are wrappers to WSGetBinaryNumberArray.

  • Temporary link in method 1 just store function heads, attempts to retrieve full exrepssion may fail.

  • Generally the heads in each level are "List".

  • The last head can be "Complex" in case of complex data type. E.g a complex unitary matrix would have 3 depth levels.

auto temp_link_p = WSLoopbackOpen(env_p, &err);
if (err != WSEOK) { /* error ... */ }
array_meterp am;
long depth;
mlapi__token leaf_token; // this token seems unused

if (!WSGetArrayTypeWithDepthAndLeafType(link_p, temp_link_p, &am, &depth, &leaf_token)) {
    /* error ... */
}

size_t total_size = 1;
const char *head_p;
int argcount;
vector<int> shape;
vector<string> heads;

for (int i=0; i<depth; ++i) {
    WSGetFunction(temp_link_p, &head_p, &argcount);
    total_size *= argcount;
    shape.push_back(argcount);
    heads.push_back(string(head_p));
    WSReleaseSymbol(link_p, head_p);
}

auto elem_token = WSGetRawType(link_p);

switch (elem_token) {
case WSTK_CDOUBLE:
    total_size *= sizeof(double);
    break;
case WSTK_CFLOAT:
    total_size *= sizeof(float);
    break;
/* case ... */
default:
    /* error ... */
    break;
}

void *array_data = malloc(total_size);
WSGetBinaryNumberArrayData(link_p, am, array_data, total_size, elem_token);
WSReleaseGetArrayState(link_p, temp_link_p, am);
WSClose(temp_link_p);

for (int i=0; i<16; ++i) {
printf("%f\n", ((double*)array_data)[i]);
}
/* do stuff with array */

free(array_data);
vector<int> shape;
vector<string> heads;
size_t total_size = 1;
const char *head_p;
int argcount;
int elem_token;
auto mark = WSCreateMark(link_p);

do {
    WSGetFunction(link_p, &head_p, &argcount);
    total_size *= argcount;
    shape.push_back(argcount);
    heads.push_back(string(head_p));
    WSReleaseSymbol(link_p, head_p);
    elem_token = WSGetRawType(link_p);
} while (elem_token == WSTKFUNC);

switch (elem_token) {
case WSTK_CDOUBLE:
    total_size *= sizeof(double);
    break;
case WSTK_CFLOAT:
    total_size *= sizeof(float);
    break;
/* case ... */
default:
    /* error ... */
    break;
}

WSSeekToMark(link_p, mark, 0);
WSDestroyMark(link_p, mark);

void *array_data;
long *received_dims;
char **received_heads;
long received_depth;

WSGetBinaryNumberArray(
    link_p, &array_data, &received_dims, &received_heads, &received_depth, elem_token);

/* do stuff with array */

// there is a int/long mismatch on received_dims, I don't understand why
WSReleaseBinaryNumberArray(
    link_p, array_data, (int*)received_dims, received_heads, total_size, elem_token);
  • array_meterp is pointer to an opaque internal struct, likely holding array metadata.

  • WSGetBinaryNumberArray* is using platform specific type tokens. They can be found in wstp.h.

  • As of WSTP v4, WSGet*Array (e.g WSGetInteger64Array) are wrappers to WSGetBinaryNumberArray.

  • Temporary link in method 1 just store function heads, attempts to retrieve full exrepssion may fail.

  • Generally the heads in each level are "List".

  • The last head can be "Complex" in case of complex data type. E.g a complex unitary matrix would have List, List, and Complex.

added 93 characters in body
Source Link
Szabolcs
  • 236.5k
  • 31
  • 641
  • 1.3k
#include "wstp.h"

int err;
auto env_p = WSInitialize((void*)0);
auto link_p = WSOpenString(env_p, "someLink -linkmode connect", &err);
if (err != WSEOK) { /* error ... */ }

auto token = WSGetType(link_p);
auto raw_token = WSGetRawType(link_p);
#include "wstp.h"

int err;
auto env_p = WSInitialize((void*)0);
auto link_p = WSOpenString(env_p, "someLink -linkmode connect", &err);
if (err != WSEOK) { /* error ... */ }

auto token = WSGetType(link_p);
auto raw_token = WSGetRawType(link_p);
auto temp_link_p = WSLoopbackOpen(env_p, &err);
if (err != WSEOK) { /* error ... */ }
array_meterp am;
long depth;
mlapi__token leaf_token; // this token seems unused

if (!WSGetArrayTypeWithDepthAndLeafType(link_p, temp_link_p, &am, &depth, &leaf_token)) {
    /* error ... */
}

size_t total_size = 1;
const char *head_p;
int argcount;
vector<int> shape;
vector<string> heads;

for (int i=0; i<depth; ++i) {
    WSGetFunction(temp_link_p, &head_p, &argcount);
    total_size *= argcount;
    shape.push_back(argcount);
    heads.push_back(string(head_p));
    WSReleaseSymbol(link_p, head_p);
}

auto elem_token = WSGetRawType(link_p);

switch (elem_token) {
case WSTK_CDOUBLE:
    total_size *= sizeof(double);
    break;
case WSTK_CFLOAT:
    total_size *= sizeof(float);
    break;
default:
    /* error ... */
    break;
}

void *array_data = malloc(total_size);
WSGetBinaryNumberArrayData(link_p, am, array_data, total_size, elem_token);
WSReleaseGetArrayState(link_p, temp_link_p, am);
WSClose(temp_link_p);

for (int i=0; i<16; ++i) {
printf("%f\n", ((double*)array_data)[i]);
}
/* do stuff with array */

free(array_data);
auto temp_link_p = WSLoopbackOpen(env_p, &err);
if (err != WSEOK) { /* error ... */ }
array_meterp am;
long depth;
mlapi__token leaf_token; // this token seems unused

if (!WSGetArrayTypeWithDepthAndLeafType(link_p, temp_link_p, &am, &depth, &leaf_token)) {
    /* error ... */
}

size_t total_size = 1;
const char *head_p;
int argcount;
vector<int> shape;
vector<string> heads;

for (int i=0; i<depth; ++i) {
    WSGetFunction(temp_link_p, &head_p, &argcount);
    total_size *= argcount;
    shape.push_back(argcount);
    heads.push_back(string(head_p));
    WSReleaseSymbol(link_p, head_p);
}

auto elem_token = WSGetRawType(link_p);

switch (elem_token) {
case WSTK_CDOUBLE:
    total_size *= sizeof(double);
    break;
case WSTK_CFLOAT:
    total_size *= sizeof(float);
    break;
default:
    /* error ... */
    break;
}

void *array_data = malloc(total_size);
WSGetBinaryNumberArrayData(link_p, am, array_data, total_size, elem_token);
WSReleaseGetArrayState(link_p, temp_link_p, am);
WSClose(temp_link_p);

for (int i=0; i<16; ++i) {
printf("%f\n", ((double*)array_data)[i]);
}
/* do stuff with array */

free(array_data);
vector<int> shape;
vector<string> heads;
size_t total_size = 1;
const char *head_p;
int argcount;
int elem_token;
auto mark = WSCreateMark(link_p);

do {
    WSGetFunction(link_p, &head_p, &argcount);
    total_size *= argcount;
    shape.push_back(argcount);
    heads.push_back(string(head_p));
    WSReleaseSymbol(link_p, head_p);
    elem_token = WSGetRawType(link_p);
} while (elem_token == WSTKFUNC);

switch (elem_token) {
case WSTK_CDOUBLE:
    total_size *= sizeof(double);
    break;
case WSTK_CFLOAT:
    total_size *= sizeof(float);
    break;
default:
    /* error ... */
    break;
}

WSSeekToMark(link_p, mark, 0);
WSDestroyMark(link_p, mark);

void *array_data;
long *received_dims;
char **received_heads;
long received_depth;

WSGetBinaryNumberArray(
    link_p, &array_data, &received_dims, &received_heads, &received_depth, elem_token);

/* do stuff with array */

// there is a int/long mismatch on received_dims, I don't understand why
WSReleaseBinaryNumberArray(
    link_p, array_data, (int*)received_dims, received_heads, total_size, elem_token);

free(array_data);
vector<int> shape;
vector<string> heads;
size_t total_size = 1;
const char *head_p;
int argcount;
int elem_token;
auto mark = WSCreateMark(link_p);

do {
    WSGetFunction(link_p, &head_p, &argcount);
    total_size *= argcount;
    shape.push_back(argcount);
    heads.push_back(string(head_p));
    WSReleaseSymbol(link_p, head_p);
    elem_token = WSGetRawType(link_p);
} while (elem_token == WSTKFUNC);

switch (elem_token) {
case WSTK_CDOUBLE:
    total_size *= sizeof(double);
    break;
case WSTK_CFLOAT:
    total_size *= sizeof(float);
    break;
default:
    /* error ... */
    break;
}

WSSeekToMark(link_p, mark, 0);
WSDestroyMark(link_p, mark);

void *array_data;
long *received_dims;
char **received_heads;
long received_depth;

WSGetBinaryNumberArray(
    link_p, &array_data, &received_dims, &received_heads, &received_depth, elem_token);

/* do stuff with array */

// there is a int/long mismatch on received_dims, I don't understand why
WSReleaseBinaryNumberArray(
    link_p, array_data, (int*)received_dims, received_heads, total_size, elem_token);

free(array_data);
WSTP_PATH=$MATHEMATICA_HOME/SystemFiles/Links/WSTP/DeveloperKit/Linux-x86-64/CompilerAdditions
g++ a.cpp -g -I$WSTP_PATH -L$WSTP_PATH -lWSTP64i4 -luuid -lrt -ldl
WSTP_PATH=$MATHEMATICA_HOME/SystemFiles/Links/WSTP/DeveloperKit/Linux-x86-64/CompilerAdditions
g++ a.cpp -g -I$WSTP_PATH -L$WSTP_PATH -lWSTP64i4 -luuid -lrt -ldl
#include "wstp.h"

int err;
auto env_p = WSInitialize((void*)0);
auto link_p = WSOpenString(env_p, "someLink -linkmode connect", &err);
if (err != WSEOK) { /* error ... */ }

auto token = WSGetType(link_p);
auto raw_token = WSGetRawType(link_p);
auto temp_link_p = WSLoopbackOpen(env_p, &err);
if (err != WSEOK) { /* error ... */ }
array_meterp am;
long depth;
mlapi__token leaf_token; // this token seems unused

if (!WSGetArrayTypeWithDepthAndLeafType(link_p, temp_link_p, &am, &depth, &leaf_token)) {
    /* error ... */
}

size_t total_size = 1;
const char *head_p;
int argcount;
vector<int> shape;
vector<string> heads;

for (int i=0; i<depth; ++i) {
    WSGetFunction(temp_link_p, &head_p, &argcount);
    total_size *= argcount;
    shape.push_back(argcount);
    heads.push_back(string(head_p));
    WSReleaseSymbol(link_p, head_p);
}

auto elem_token = WSGetRawType(link_p);

switch (elem_token) {
case WSTK_CDOUBLE:
    total_size *= sizeof(double);
    break;
case WSTK_CFLOAT:
    total_size *= sizeof(float);
    break;
default:
    /* error ... */
    break;
}

void *array_data = malloc(total_size);
WSGetBinaryNumberArrayData(link_p, am, array_data, total_size, elem_token);
WSReleaseGetArrayState(link_p, temp_link_p, am);
WSClose(temp_link_p);

for (int i=0; i<16; ++i) {
printf("%f\n", ((double*)array_data)[i]);
}
/* do stuff with array */

free(array_data);
vector<int> shape;
vector<string> heads;
size_t total_size = 1;
const char *head_p;
int argcount;
int elem_token;
auto mark = WSCreateMark(link_p);

do {
    WSGetFunction(link_p, &head_p, &argcount);
    total_size *= argcount;
    shape.push_back(argcount);
    heads.push_back(string(head_p));
    WSReleaseSymbol(link_p, head_p);
    elem_token = WSGetRawType(link_p);
} while (elem_token == WSTKFUNC);

switch (elem_token) {
case WSTK_CDOUBLE:
    total_size *= sizeof(double);
    break;
case WSTK_CFLOAT:
    total_size *= sizeof(float);
    break;
default:
    /* error ... */
    break;
}

WSSeekToMark(link_p, mark, 0);
WSDestroyMark(link_p, mark);

void *array_data;
long *received_dims;
char **received_heads;
long received_depth;

WSGetBinaryNumberArray(
    link_p, &array_data, &received_dims, &received_heads, &received_depth, elem_token);

/* do stuff with array */

// there is a int/long mismatch on received_dims, I don't understand why
WSReleaseBinaryNumberArray(
    link_p, array_data, (int*)received_dims, received_heads, total_size, elem_token);

free(array_data);
WSTP_PATH=$MATHEMATICA_HOME/SystemFiles/Links/WSTP/DeveloperKit/Linux-x86-64/CompilerAdditions
g++ a.cpp -g -I$WSTP_PATH -L$WSTP_PATH -lWSTP64i4 -luuid -lrt -ldl
#include "wstp.h"

int err;
auto env_p = WSInitialize((void*)0);
auto link_p = WSOpenString(env_p, "someLink -linkmode connect", &err);
if (err != WSEOK) { /* error ... */ }

auto token = WSGetType(link_p);
auto raw_token = WSGetRawType(link_p);
auto temp_link_p = WSLoopbackOpen(env_p, &err);
if (err != WSEOK) { /* error ... */ }
array_meterp am;
long depth;
mlapi__token leaf_token; // this token seems unused

if (!WSGetArrayTypeWithDepthAndLeafType(link_p, temp_link_p, &am, &depth, &leaf_token)) {
    /* error ... */
}

size_t total_size = 1;
const char *head_p;
int argcount;
vector<int> shape;
vector<string> heads;

for (int i=0; i<depth; ++i) {
    WSGetFunction(temp_link_p, &head_p, &argcount);
    total_size *= argcount;
    shape.push_back(argcount);
    heads.push_back(string(head_p));
    WSReleaseSymbol(link_p, head_p);
}

auto elem_token = WSGetRawType(link_p);

switch (elem_token) {
case WSTK_CDOUBLE:
    total_size *= sizeof(double);
    break;
case WSTK_CFLOAT:
    total_size *= sizeof(float);
    break;
default:
    /* error ... */
    break;
}

void *array_data = malloc(total_size);
WSGetBinaryNumberArrayData(link_p, am, array_data, total_size, elem_token);
WSReleaseGetArrayState(link_p, temp_link_p, am);
WSClose(temp_link_p);

for (int i=0; i<16; ++i) {
printf("%f\n", ((double*)array_data)[i]);
}
/* do stuff with array */

free(array_data);
vector<int> shape;
vector<string> heads;
size_t total_size = 1;
const char *head_p;
int argcount;
int elem_token;
auto mark = WSCreateMark(link_p);

do {
    WSGetFunction(link_p, &head_p, &argcount);
    total_size *= argcount;
    shape.push_back(argcount);
    heads.push_back(string(head_p));
    WSReleaseSymbol(link_p, head_p);
    elem_token = WSGetRawType(link_p);
} while (elem_token == WSTKFUNC);

switch (elem_token) {
case WSTK_CDOUBLE:
    total_size *= sizeof(double);
    break;
case WSTK_CFLOAT:
    total_size *= sizeof(float);
    break;
default:
    /* error ... */
    break;
}

WSSeekToMark(link_p, mark, 0);
WSDestroyMark(link_p, mark);

void *array_data;
long *received_dims;
char **received_heads;
long received_depth;

WSGetBinaryNumberArray(
    link_p, &array_data, &received_dims, &received_heads, &received_depth, elem_token);

/* do stuff with array */

// there is a int/long mismatch on received_dims, I don't understand why
WSReleaseBinaryNumberArray(
    link_p, array_data, (int*)received_dims, received_heads, total_size, elem_token);

free(array_data);
WSTP_PATH=$MATHEMATICA_HOME/SystemFiles/Links/WSTP/DeveloperKit/Linux-x86-64/CompilerAdditions
g++ a.cpp -g -I$WSTP_PATH -L$WSTP_PATH -lWSTP64i4 -luuid -lrt -ldl
Source Link
kh40tika
  • 684
  • 4
  • 13

Following a dedicated discussion with @Szabolcs, very helpful comments from @ihojnicki, and information from an old thread, I successfully implemented NumPy array sender/receiver in PyWSTP.

Assume we are trying to receive a Real64 array in C++.

(* server.m *)
LinkOpen["someLink", LinkMode->Listen];
LinkWrite[link, RandomReal[1., {4,4}]];
InputString[];
LinkClose[link];

The kernel does send packed array in packed form. However, in order to successfully receive packed array, one must call WSGetRawType to retrieve low level type tokens:

#include "wstp.h"

int err;
auto env_p = WSInitialize((void*)0);
auto link_p = WSOpenString(env_p, "someLink -linkmode connect", &err);
if (err != WSEOK) { /* error ... */ }

auto token = WSGetType(link_p);
auto raw_token = WSGetRawType(link_p);

Here token will be WSTKFUNC, however raw_token is WSTKARRAY. The problem here is how to determine data type and size of the multidimensional array. From this point on, two methods can be used (as of WSTPv4):

Method 1 - Create a temporary loopback link to store array metadata

auto temp_link_p = WSLoopbackOpen(env_p, &err);
if (err != WSEOK) { /* error ... */ }
array_meterp am;
long depth;
mlapi__token leaf_token; // this token seems unused

if (!WSGetArrayTypeWithDepthAndLeafType(link_p, temp_link_p, &am, &depth, &leaf_token)) {
    /* error ... */
}

size_t total_size = 1;
const char *head_p;
int argcount;
vector<int> shape;
vector<string> heads;

for (int i=0; i<depth; ++i) {
    WSGetFunction(temp_link_p, &head_p, &argcount);
    total_size *= argcount;
    shape.push_back(argcount);
    heads.push_back(string(head_p));
    WSReleaseSymbol(link_p, head_p);
}

auto elem_token = WSGetRawType(link_p);

switch (elem_token) {
case WSTK_CDOUBLE:
    total_size *= sizeof(double);
    break;
case WSTK_CFLOAT:
    total_size *= sizeof(float);
    break;
default:
    /* error ... */
    break;
}

void *array_data = malloc(total_size);
WSGetBinaryNumberArrayData(link_p, am, array_data, total_size, elem_token);
WSReleaseGetArrayState(link_p, temp_link_p, am);
WSClose(temp_link_p);

for (int i=0; i<16; ++i) {
printf("%f\n", ((double*)array_data)[i]);
}
/* do stuff with array */

free(array_data);

Method 2 - Set mark, read metadata manually, then seek back and read data

vector<int> shape;
vector<string> heads;
size_t total_size = 1;
const char *head_p;
int argcount;
int elem_token;
auto mark = WSCreateMark(link_p);

do {
    WSGetFunction(link_p, &head_p, &argcount);
    total_size *= argcount;
    shape.push_back(argcount);
    heads.push_back(string(head_p));
    WSReleaseSymbol(link_p, head_p);
    elem_token = WSGetRawType(link_p);
} while (elem_token == WSTKFUNC);

switch (elem_token) {
case WSTK_CDOUBLE:
    total_size *= sizeof(double);
    break;
case WSTK_CFLOAT:
    total_size *= sizeof(float);
    break;
default:
    /* error ... */
    break;
}

WSSeekToMark(link_p, mark, 0);
WSDestroyMark(link_p, mark);

void *array_data;
long *received_dims;
char **received_heads;
long received_depth;

WSGetBinaryNumberArray(
    link_p, &array_data, &received_dims, &received_heads, &received_depth, elem_token);

/* do stuff with array */

// there is a int/long mismatch on received_dims, I don't understand why
WSReleaseBinaryNumberArray(
    link_p, array_data, (int*)received_dims, received_heads, total_size, elem_token);

free(array_data);

Observations

  • array_meterp is pointer to an opaque internal struct, likely holding array metadata.

  • WSGetBinaryNumberArray* is using platform specific type tokens. They can be found in wstp.h.

  • As of WSTP v4, WSGet*Array (e.g WSGetInteger64Array) are wrappers to WSGetBinaryNumberArray.

  • Temporary link in method 1 just store function heads, attempts to retrieve full exrepssion may fail.

  • Generally the heads in each level are "List".

  • The last head can be "Complex" in case of complex data type. E.g a complex unitary matrix would have 3 depth levels.

The full code can be found here. Under linux, compile via:

WSTP_PATH=$MATHEMATICA_HOME/SystemFiles/Links/WSTP/DeveloperKit/Linux-x86-64/CompilerAdditions
g++ a.cpp -g -I$WSTP_PATH -L$WSTP_PATH -lWSTP64i4 -luuid -lrt -ldl

Credits to @ihojnicki, and @Szabolcs.