Skip to content

Commit 5f9b3e0

Browse files
committed
Convert Python bytes and strings to Elixir binaries without copying
1 parent 7fbd743 commit 5f9b3e0

File tree

1 file changed

+12
-16
lines changed

1 file changed

+12
-16
lines changed

c_src/pythonx/pythonx.cpp

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -266,16 +266,14 @@ void raise_if_failed(ErlNifEnv *env, Py_ssize_t size) {
266266
}
267267
}
268268

269-
ERL_NIF_TERM py_object_to_binary_term(ErlNifEnv *env, PyObjectPtr py_object) {
269+
ERL_NIF_TERM py_str_to_binary_term(ErlNifEnv *env, PyObjectPtr py_object) {
270270
Py_ssize_t size;
271271
auto buffer = PyUnicode_AsUTF8AndSize(py_object, &size);
272272
raise_if_failed(env, buffer);
273273

274-
ERL_NIF_TERM binary_term;
275-
auto data = enif_make_new_binary(env, size, &binary_term);
276-
memcpy(data, buffer, size);
277-
278-
return binary_term;
274+
Py_IncRef(py_object);
275+
auto ex_object_resource = fine::make_resource<ExObjectResource>(py_object);
276+
return fine::make_resource_binary(env, ex_object_resource, buffer, size);
279277
}
280278

281279
fine::Ok<> init(ErlNifEnv *env, std::string python_dl_path,
@@ -583,7 +581,7 @@ fine::Term unicode_to_string(ErlNifEnv *env, ExObject ex_object) {
583581
ensure_initialized();
584582
auto gil_guard = PyGILGuard();
585583

586-
return py_object_to_binary_term(env, ex_object.resource->py_object);
584+
return py_str_to_binary_term(env, ex_object.resource->py_object);
587585
}
588586

589587
FINE_NIF(unicode_to_string, ERL_NIF_DIRTY_JOB_CPU_BOUND);
@@ -745,7 +743,7 @@ fine::Term format_exception(ErlNifEnv *env, ExError error) {
745743
auto py_line = PyList_GetItem(py_lines, i);
746744
raise_if_failed(env, py_line);
747745

748-
terms.push_back(py_object_to_binary_term(env, py_line));
746+
terms.push_back(py_str_to_binary_term(env, py_line));
749747
}
750748

751749
return enif_make_list_from_array(env, terms.data(),
@@ -803,7 +801,7 @@ fine::Term decode_once(ErlNifEnv *env, ExObject ex_object) {
803801
raise_if_failed(env, py_str);
804802
auto py_str_guard = PyDecRefGuard(py_str);
805803

806-
auto binary_term = py_object_to_binary_term(env, py_str);
804+
auto binary_term = py_str_to_binary_term(env, py_str);
807805

808806
return fine::encode(
809807
env, std::make_tuple(atoms::integer, fine::Term(binary_term)));
@@ -904,7 +902,7 @@ fine::Term decode_once(ErlNifEnv *env, ExObject ex_object) {
904902
auto is_unicode = PyObject_IsInstance(py_object, py_str_type);
905903
raise_if_failed(env, is_unicode);
906904
if (is_unicode) {
907-
return py_object_to_binary_term(env, py_object);
905+
return py_str_to_binary_term(env, py_object);
908906
}
909907

910908
auto py_bytes_type = PyDict_GetItemString(py_builtins, "bytes");
@@ -917,11 +915,9 @@ fine::Term decode_once(ErlNifEnv *env, ExObject ex_object) {
917915
auto result = PyBytes_AsStringAndSize(py_object, &buffer, &size);
918916
raise_if_failed(env, result);
919917

920-
ERL_NIF_TERM binary_term;
921-
auto data = enif_make_new_binary(env, size, &binary_term);
922-
memcpy(data, buffer, size);
923-
924-
return binary_term;
918+
Py_IncRef(py_object);
919+
auto ex_object_resource = fine::make_resource<ExObjectResource>(py_object);
920+
return fine::make_resource_binary(env, ex_object_resource, buffer, size);
925921
}
926922

927923
auto py_set_type = PyDict_GetItemString(py_builtins, "set");
@@ -1341,7 +1337,7 @@ eval(ErlNifEnv *env, ErlNifBinary code, std::string code_md5,
13411337
continue;
13421338
}
13431339

1344-
auto key_term = py_object_to_binary_term(env, py_key);
1340+
auto key_term = py_str_to_binary_term(env, py_key);
13451341
key_terms.push_back(key_term);
13461342

13471343
// Incref before making the resource

0 commit comments

Comments
 (0)