Skip to content

Commit

Permalink
[fix] Rework code according to Valgrind's recommendations (#14)
Browse files Browse the repository at this point in the history
* [fix] Rework code according to Valgrind's recommendations

* [fix] Fix build pyreindexer with reindexer v.4.15

---------

Co-authored-by: Alexander.A.Utkin <[email protected]>
  • Loading branch information
AlexAUtkin and Alexander.A.Utkin authored Oct 25, 2024
1 parent 04c11a2 commit 5effedf
Show file tree
Hide file tree
Showing 9 changed files with 211 additions and 245 deletions.
148 changes: 77 additions & 71 deletions pyreindexer/lib/include/pyobjtools.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,105 +4,103 @@

namespace pyreindexer {

void pyValueSerialize(PyObject **value, reindexer::WrSerializer &wrSer) {
if (*value == Py_None) {
wrSer << "null";
} else if (PyBool_Check(*value)) {
bool v = PyLong_AsLong(*value) != 0;
wrSer << v;
} else if (PyFloat_Check(*value)) {
double v = PyFloat_AsDouble(*value);
double intpart;
if (std::modf(v, &intpart) == 0.0) {
wrSer << int64_t(v);
} else {
wrSer << v;
}
} else if (PyLong_Check(*value)) {
long v = PyLong_AsLong(*value);
wrSer << v;
} else if (PyUnicode_Check(*value)) {
const char *v = PyUnicode_AsUTF8(*value);
wrSer.PrintJsonString(v);
} else if (PyList_Check(*value)) {
pyListSerialize(value, wrSer);
} else if (PyDict_Check(*value)) {
pyDictSerialize(value, wrSer);
} else {
throw reindexer::Error(errParseJson, std::string("Unable to parse value of type ") + Py_TYPE(*value)->tp_name);
}
}
void pyValueSerialize(PyObject** value, reindexer::WrSerializer& wrSer);

void pyListSerialize(PyObject **list, reindexer::WrSerializer &wrSer) {
void pyListSerialize(PyObject** list, reindexer::WrSerializer& wrSer) {
if (!PyList_Check(*list)) {
throw reindexer::Error(errParseJson, std::string("List expected, got ") + Py_TYPE(*list)->tp_name);
}

wrSer << '[';

unsigned sz = PyList_Size(*list);
for (unsigned i = 0; i < sz; i++) {
PyObject *value = PyList_GetItem(*list, i);

pyValueSerialize(&value, wrSer);

if (i < sz - 1) {
Py_ssize_t sz = PyList_Size(*list);
for (Py_ssize_t i = 0; i < sz; ++i) {
if (i > 0) {
wrSer << ',';
}

PyObject* value = PyList_GetItem(*list, i);

pyValueSerialize(&value, wrSer);
}

wrSer << ']';
}

void pyDictSerialize(PyObject **dict, reindexer::WrSerializer &wrSer) {
void pyDictSerialize(PyObject** dict, reindexer::WrSerializer& wrSer) {
if (!PyDict_Check(*dict)) {
throw reindexer::Error(errParseJson, std::string("Dictionary expected, got ") + Py_TYPE(*dict)->tp_name);
}

wrSer << '{';

Py_ssize_t sz = PyDict_Size(*dict);
if (!sz) {
wrSer << '}';
if (sz) {
PyObject *key = nullptr, *value = nullptr;
Py_ssize_t pos = 0;

return;
}

PyObject *key, *value;
Py_ssize_t pos = 0;

while (PyDict_Next(*dict, &pos, &key, &value)) {
const char *k = PyUnicode_AsUTF8(key);
wrSer.PrintJsonString(k);
wrSer << ':';
while (PyDict_Next(*dict, &pos, &key, &value)) {
if (pos > 1) {
wrSer << ',';
}

pyValueSerialize(&value, wrSer);
const char* k = PyUnicode_AsUTF8(key);
wrSer.PrintJsonString(k);
wrSer << ':';

if (pos != sz) {
wrSer << ',';
pyValueSerialize(&value, wrSer);
}
}

wrSer << '}';
}

void PyObjectToJson(PyObject **obj, reindexer::WrSerializer &wrSer) {
void pyValueSerialize(PyObject** value, reindexer::WrSerializer& wrSer) {
if (*value == Py_None) {
wrSer << "null";
} else if (PyBool_Check(*value)) {
bool v = PyLong_AsLong(*value) != 0;
wrSer << v;
} else if (PyFloat_Check(*value)) {
double v = PyFloat_AsDouble(*value);
double intpart;
if (std::modf(v, &intpart) == 0.0) {
wrSer << int64_t(v);
} else {
wrSer << v;
}
} else if (PyLong_Check(*value)) {
long v = PyLong_AsLong(*value);
wrSer << v;
} else if (PyUnicode_Check(*value)) {
const char* v = PyUnicode_AsUTF8(*value);
wrSer.PrintJsonString(v);
} else if (PyList_Check(*value)) {
pyListSerialize(value, wrSer);
} else if (PyDict_Check(*value)) {
pyDictSerialize(value, wrSer);
} else {
throw reindexer::Error(errParseJson, std::string("Unable to parse value of type ") + Py_TYPE(*value)->tp_name);
}
}

void PyObjectToJson(PyObject** obj, reindexer::WrSerializer& wrSer) {
if (PyDict_Check(*obj)) {
pyDictSerialize(obj, wrSer);
} else if (PyList_Check(*obj) ) {
pyListSerialize(obj, wrSer);
} else {
throw reindexer::Error(errParseJson,
throw reindexer::Error(errParseJson,
std::string("PyObject must be a dictionary or a list for JSON serializing, got ") + Py_TYPE(*obj)->tp_name);
}
}

std::vector<std::string> ParseListToStrVec(PyObject **list) {
std::vector<std::string> ParseListToStrVec(PyObject** list) {
std::vector<std::string> vec;

Py_ssize_t sz = PyList_Size(*list);
for (Py_ssize_t i = 0; i < sz; i++) {
PyObject *item = PyList_GetItem(*list, i);
PyObject* item = PyList_GetItem(*list, i);

if (!PyUnicode_Check(item)) {
throw reindexer::Error(errParseJson, std::string("String expected, got ") + Py_TYPE(item)->tp_name);
Expand All @@ -114,54 +112,62 @@ std::vector<std::string> ParseListToStrVec(PyObject **list) {
return vec;
}

PyObject *pyValueFromJsonValue(const gason::JsonValue &value) {
PyObject *pyValue = nullptr;
PyObject* pyValueFromJsonValue(const gason::JsonValue& value) {
PyObject* pyValue = nullptr;

switch (value.getTag()) {
case gason::JSON_NUMBER:
pyValue = PyLong_FromSize_t(value.toNumber());
pyValue = PyLong_FromSize_t(value.toNumber()); // new ref
break;
case gason::JSON_DOUBLE:
pyValue = PyFloat_FromDouble(value.toDouble());
pyValue = PyFloat_FromDouble(value.toDouble()); // new ref
break;
case gason::JSON_STRING: {
auto sv = value.toString();
pyValue = PyUnicode_FromStringAndSize(sv.data(), sv.size());
pyValue = PyUnicode_FromStringAndSize(sv.data(), sv.size()); // new ref
break;
}
case gason::JSON_NULL:
pyValue = Py_None;
Py_INCREF(pyValue); // new ref
break;
case gason::JSON_TRUE:
pyValue = Py_True;
Py_INCREF(pyValue); // new ref
break;
case gason::JSON_FALSE:
pyValue = Py_False;
Py_INCREF(pyValue); // new ref
break;
case gason::JSON_ARRAY:
pyValue = PyList_New(0);
for (const auto &v : value) {
PyList_Append(pyValue, pyValueFromJsonValue(v.value));
pyValue = PyList_New(0); // new ref
for (const auto& v : value) {
PyObject* dictFromJson = pyValueFromJsonValue(v.value); // stolen ref
PyList_Append(pyValue, dictFromJson); // new ref
Py_XDECREF(dictFromJson);
}
break;
case gason::JSON_OBJECT:
pyValue = PyDict_New();
for (const auto &v : value) {
PyDict_SetItem(pyValue, PyUnicode_FromStringAndSize(v.key.data(), v.key.size()), pyValueFromJsonValue(v.value));
pyValue = PyDict_New(); // new ref
for (const auto& v : value) {
PyObject* dictFromJson = pyValueFromJsonValue(v.value); // stolen ref
PyObject* pyKey = PyUnicode_FromStringAndSize(v.key.data(), v.key.size()); // new ref
PyDict_SetItem(pyValue, pyKey, dictFromJson); // new refs
Py_XDECREF(pyKey);
Py_XDECREF(dictFromJson);
}
break;
}

return pyValue;
}

PyObject *PyObjectFromJson(reindexer::span<char> json) {
PyObject* PyObjectFromJson(reindexer::span<char> json) {
try {
gason::JsonParser parser;
auto root = parser.Parse(json);
// new ref
return pyValueFromJsonValue(root.value);
} catch (const gason::Exception &ex) {
return pyValueFromJsonValue(root.value); // stolen ref
} catch (const gason::Exception& ex) {
throw reindexer::Error(errParseJson, std::string("PyObjectFromJson: ") + ex.what());
}
}
Expand Down
11 changes: 3 additions & 8 deletions pyreindexer/lib/include/pyobjtools.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,9 @@

namespace pyreindexer {

void pyValueSerialize(PyObject **item, reindexer::WrSerializer &wrSer);
void pyListSerialize(PyObject **list, reindexer::WrSerializer &wrSer);
void pyDictSerialize(PyObject **dict, reindexer::WrSerializer &wrSer);
PyObject *pyValueFromJsonValue(const gason::JsonValue &value);
std::vector<std::string> ParseListToStrVec(PyObject** dict);

std::vector<std::string> ParseListToStrVec(PyObject **dict);

void PyObjectToJson(PyObject **dict, reindexer::WrSerializer &wrSer);
PyObject *PyObjectFromJson(reindexer::span<char> json);
void PyObjectToJson(PyObject** dict, reindexer::WrSerializer& wrSer);
PyObject* PyObjectFromJson(reindexer::span<char> json);

} // namespace pyreindexer
4 changes: 2 additions & 2 deletions pyreindexer/lib/include/queryresults_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ class QueryResultsWrapper {
db_->FetchResults(*this);
}

const std::vector<reindexer::AggregationResult>& GetAggregationResults() const& { return qresPtr.GetAggregationResults(); }
const std::vector<reindexer::AggregationResult>& GetAggregationResults() const&& = delete;
const std::vector<reindexer::AggregationResult>& GetAggregationResults() & { return qresPtr.GetAggregationResults(); }
const std::vector<reindexer::AggregationResult>& GetAggregationResults() && = delete;

private:
friend DBInterface;
Expand Down
Loading

0 comments on commit 5effedf

Please sign in to comment.