I'm an Erlang enthusiast and a newbie Erlang Prorammer.
I recently had to face a data crunching problem in Erlang. Hence I decided to use NIFs. I have two list of proplists and I have to return the hash join of the two proplists based upon a term.
To implement it I decided to learn binary manipulation in C. Also I'm using the nifpp library(C++11) to ease my learning experience. Source: https://github.com/goertzenator/nifpp
The following is the code I can think of for extracting and copying binary to another ErlNifBinary which is well documented. But I'm not able to manipulate it.
ErlNifBinary ebin, bin_term;
nifpp::get_throws(env, argv[0], ebin); // Assigns ebin to the input binary
enif_alloc_binary(16, &bin_term); // Size of new binary
memcpy(bin_term.data, ebin.data, ebin.size); // Copying the contents of binary
I have a pointer to an unsigned char
in bin_term.data
. How do I change the contents in bin_term.data
?
Also, if I return the existing copied binary, I get different outputs for the same input and not equal to the input considering the fact that I have just coped the data from the input.
return enif_make_binary(env, &bin_term);
In the erlang REPL, if I execute the function with params <<7>>
or any other binary, I get the results as <<7,127,128,29,0,0,0,0,1,0,0,0,24,1,0,0>>
or some random dynamic values each time. Can someone point as to what is the mistake in the code.
First of all, when you initialize bin_term
, you do it with static size of 16
bytes. That's why your function always returns binary bigger than expected (16 digits, if you count). So first thing you could do, is to create bin_term
with size of binary passed from Erlang
enif_alloc_binary(16, &bin_term); // Constant size
enif_alloc_binary(ebin.size, &bin_term); // Same size as binary from Erlang
And in nifpp
there is wrapper on ErlNifBinary called bianry
with which you could simply write
binary bin_term = new binary(ebin.size);
Or even add your own copying constructor.
Second this is accessing binary data. If you look how ErlNifBinary
is defined you can see that all data is accessible trough data
field (just like you expected) which is pointer to unsigned char
(array in other words, of length given by size
field).
So if you would like to for instance increase and print each of values from this binary you could do something like this
ErlNifBinary ebin, bin_term;
nifpp::get_throws(env, argv[0], ebin); // Assigns ebin to the input binary
enif_alloc_binary(ebin.size, &bin_term); // Size of new binary
memcpy(bin_term.data, ebin.data, ebin.size); // Copying the contents of binary
for(int i=0; i<bin_term.size; ++i){
bin_term.data[i] = bin_term.data[i] + 1;
std::cout << bin_term.data[i] << std::endl;
}
If you need some other data representation than array of chars (raw memory) you could look into Resource objects which in essence are smart pointers (garbage collected) to your C-memory, that could be passed around in Erlang.