FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Turn rapidjson.Decoder into heap type by VestniK · Pull Request #227 · python-rapidjson/python-rapidjson · GitHub

Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension .cpp  (1) All 1 file type selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
123 changes: 78 additions & 45 deletions rapidjson.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include <algorithm>
#include <cmath>
#include <memory>
#include <string>
#include <vector>

Expand All @@ -28,6 +29,53 @@
using namespace rapidjson;


#if PY_VERSION_HEX < 0x030A0000
// Fallback for Py_TPFLAGS_IMMUTABLETYPE which is added in 3.10
#define Py_TPFLAGS_IMMUTABLETYPE 0
#endif


static uint32_t
py_version_hex() noexcept {
#if PY_VERSION_HEX < 0x030B0000
static const uint32_t once_fetched_ver = [] {
constexpr uint32_t ver_fallback = 0x03000000;

auto* ver_tuple = PySys_GetObject("version_info");
if (!ver_tuple)
return ver_fallback;

long major, minor, micro, serial;
const char* releaselevel;
if (!PyArg_ParseTuple(ver_tuple, "lllsl", &major, &minor, &micro, &releaselevel, &serial))
return ver_fallback;

return uint32_t(((major & 0xFF) << 24) | ((minor & 0xFF) << 16) | ((micro & 0xFF) << 8));
}();
return once_fetched_ver;
#else
return Py_Version;
#endif
}


struct PyDerefer {
void operator() (PyObject* obj) const noexcept {Py_DecRef(obj);}
};
using PyStrongRef = std::unique_ptr<PyObject, PyDerefer>;


static PyStrongRef
inline from_module_and_spec(PyObject& module, PyType_Spec& spec) noexcept {
#if PY_VERSION_HEX >= 0x03090000
PyStrongRef type{PyType_FromModuleAndSpec(&module, &spec, NULL)};
#else
PyStrongRef type{PyType_FromSpec(&spec)};
#endif
return type;
}


/* On some MacOS combo, using Py_IS_XXX() macros does not work (see
https://github.com/python-rapidjson/python-rapidjson/issues/78).
OTOH, MSVC < 2015 does not have std::isxxx() (see
Expand Down Expand Up @@ -208,6 +256,7 @@ static PyObject* do_decode(PyObject* decoder,
unsigned uuidMode, unsigned parseMode);
static PyObject* decoder_call(PyObject* self, PyObject* args, PyObject* kwargs);
static PyObject* decoder_new(PyTypeObject* type, PyObject* args, PyObject* kwargs);
static int decoder_traverse(PyObject *op, visitproc visit, void *arg);


static PyObject* do_encode(PyObject* value, PyObject* defaultFn, bool ensureAscii,
Expand Down Expand Up @@ -1890,46 +1939,22 @@ static PyMemberDef decoder_members[] = {
};


static PyTypeObject Decoder_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"rapidjson.Decoder", /* tp_name */
sizeof(DecoderObject), /* tp_basicsize */
0, /* tp_itemsize */
0, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
(ternaryfunc) decoder_call, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
decoder_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
decoder_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
decoder_new, /* tp_new */
PyObject_Del, /* tp_free */
static PyType_Slot Decoder_Type_Slot[] = {
{Py_tp_doc, const_cast<char*>(decoder_doc)},
{Py_tp_call, reinterpret_cast<void*>(decoder_call)},
{Py_tp_members, decoder_members},
{Py_tp_new, reinterpret_cast<void*>(decoder_new)},
{Py_tp_traverse, reinterpret_cast<void*>(decoder_traverse)},
{0, NULL}
};


static PyType_Spec Decoder_Type_Spec = {
"rapidjson.Decoder", /* name */
sizeof(DecoderObject), /* basicsize */
0, /* itemsize */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE, /* flags */

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

The type is flagged as Py_TPFLAGS_IMMUTABLETYPE to make this change more "noop-like". All static types are immutable. Decoder type remains immutable after it's transformation into heap-type. This flag can be dropped if it's ok to make Decoder to be closer to regular types defined in python.

Decoder_Type_Slot /* slots */
};


Expand Down Expand Up @@ -2291,6 +2316,16 @@ decoder_new(PyTypeObject* type, PyObject* args, PyObject* kwargs)
}


static int
decoder_traverse(PyObject *op, visitproc visit, void *arg)
{
if (py_version_hex() >= 0x03090000)
Py_VISIT(Py_TYPE(op));
return 0;
}



/////////////
// Encoder //
/////////////
Expand Down Expand Up @@ -3884,7 +3919,8 @@ module_exec(PyObject* m)
PyObject* decimalModule;
PyObject* uuidModule;

if (PyType_Ready(&Decoder_Type) < 0)
auto decoder_type = from_module_and_spec(*m, Decoder_Type_Spec);
if (!decoder_type)
return -1;

if (PyType_Ready(&Encoder_Type) < 0)
Expand Down Expand Up @@ -4067,11 +4103,8 @@ module_exec(PyObject* m)
)
return -1;

Py_INCREF(&Decoder_Type);
if (PyModule_AddObject(m, "Decoder", (PyObject*) &Decoder_Type) < 0) {
Py_DECREF(&Decoder_Type);
if (PyModule_AddObject(m, "Decoder", decoder_type.get()) < 0)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Using RAII here prolongates lifetime of a strong reference to decoder type to the end of the module exec function. It shouldn't affect type object lifetime since there are other strong references to it. But using RAII make the code smaller and less error prone.

return -1;
}

Py_INCREF(&Encoder_Type);
if (PyModule_AddObject(m, "Encoder", (PyObject*) &Encoder_Type) < 0) {
Expand Down

Back | FazBrowse Home | New Git URL