diff options
Diffstat (limited to 'python/google/protobuf/pyext/message.h')
-rw-r--r-- | python/google/protobuf/pyext/message.h | 132 |
1 files changed, 82 insertions, 50 deletions
diff --git a/python/google/protobuf/pyext/message.h b/python/google/protobuf/pyext/message.h index cc0012e9..d754e62a 100644 --- a/python/google/protobuf/pyext/message.h +++ b/python/google/protobuf/pyext/message.h @@ -37,11 +37,11 @@ #include <Python.h> #include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif #include <string> +#include <google/protobuf/stubs/common.h> +#include <google/protobuf/pyext/thread_unsafe_shared_ptr.h> + namespace google { namespace protobuf { @@ -52,17 +52,10 @@ class Descriptor; class DescriptorPool; class MessageFactory; -#ifdef _SHARED_PTR_H -using std::shared_ptr; -using std::string; -#else -using internal::shared_ptr; -#endif - namespace python { struct ExtensionDict; -struct PyDescriptorPool; +struct PyMessageFactory; typedef struct CMessage { PyObject_HEAD; @@ -71,7 +64,9 @@ typedef struct CMessage { // proto tree. Every Python CMessage holds a reference to it in // order to keep it alive as long as there's a Python object that // references any part of the tree. - shared_ptr<Message> owner; + + typedef ThreadUnsafeSharedPtr<Message> OwnerRef; + OwnerRef owner; // Weak reference to a parent CMessage object. This is NULL for any top-level // message and is set for any child message (i.e. a child submessage or a @@ -112,24 +107,48 @@ typedef struct CMessage { // Similar to composite_fields, acting as a cache, but also contains the // required extension dict logic. ExtensionDict* extensions; + + // Implements the "weakref" protocol for this object. + PyObject* weakreflist; } CMessage; +extern PyTypeObject CMessageClass_Type; extern PyTypeObject CMessage_Type; + +// The (meta) type of all Messages classes. +// It allows us to cache some C++ pointers in the class object itself, they are +// faster to extract than from the type's dictionary. + +struct CMessageClass { + // This is how CPython subclasses C structures: the base structure must be + // the first member of the object. + PyHeapTypeObject super; + + // C++ descriptor of this message. + const Descriptor* message_descriptor; + + // Owned reference, used to keep the pointer above alive. + PyObject* py_message_descriptor; + + // The Python MessageFactory used to create the class. It is needed to resolve + // fields descriptors, including extensions fields; its C++ MessageFactory is + // used to instantiate submessages. + // We own the reference, because it's important to keep the factory alive. + PyMessageFactory* py_message_factory; + + PyObject* AsPyObject() { + return reinterpret_cast<PyObject*>(this); + } +}; + + namespace cmessage { // Internal function to create a new empty Message Python object, but with empty // pointers to the C++ objects. // The caller must fill self->message, self->owner and eventually self->parent. -CMessage* NewEmptyMessage(PyObject* type, const Descriptor* descriptor); - -// Release a submessage from its proto tree, making it a new top-level messgae. -// A new message will be created if this is a read-only default instance. -// -// Corresponds to reflection api method ReleaseMessage. -int ReleaseSubMessage(CMessage* self, - const FieldDescriptor* field_descriptor, - CMessage* child_cmessage); +CMessage* NewEmptyMessage(CMessageClass* type); // Retrieves the C++ descriptor of a Python Extension descriptor. // On error, return NULL with an exception set. @@ -206,37 +225,44 @@ PyObject* HasFieldByDescriptor( PyObject* HasField(CMessage* self, PyObject* arg); // Initializes values of fields on a newly constructed message. -int InitAttributes(CMessage* self, PyObject* kwargs); +// Note that positional arguments are disallowed: 'args' must be NULL or the +// empty tuple. +int InitAttributes(CMessage* self, PyObject* args, PyObject* kwargs); PyObject* MergeFrom(CMessage* self, PyObject* arg); -// Retrieves an attribute named 'name' from CMessage 'self'. Returns -// the attribute value on success, or NULL on failure. +// This method does not do anything beyond checking that no other extension +// has been registered with the same field number on this class. +PyObject* RegisterExtension(PyObject* cls, PyObject* extension_handle); + +// Retrieves an attribute named 'name' from 'self', which is interpreted as a +// CMessage. Returns the attribute value on success, or null on failure. // // Returns a new reference. -PyObject* GetAttr(CMessage* self, PyObject* name); +PyObject* GetAttr(PyObject* self, PyObject* name); -// Set the value of the attribute named 'name', for CMessage 'self', -// to the value 'value'. Returns -1 on failure. -int SetAttr(CMessage* self, PyObject* name, PyObject* value); +// Set the value of the attribute named 'name', for 'self', which is interpreted +// as a CMessage, to the value 'value'. Returns -1 on failure. +int SetAttr(PyObject* self, PyObject* name, PyObject* value); PyObject* FindInitializationErrors(CMessage* self); // Set the owner field of self and any children of self, recursively. // Used when self is being released and thus has a new owner (the // released Message.) -int SetOwner(CMessage* self, const shared_ptr<Message>& new_owner); +int SetOwner(CMessage* self, const CMessage::OwnerRef& new_owner); int AssureWritable(CMessage* self); -// Returns the "best" DescriptorPool for the given message. -// This is often equivalent to message.DESCRIPTOR.pool, but not always, when -// the message class was created from a MessageFactory using a custom pool which -// uses the generated pool as an underlay. +// Returns the message factory for the given message. +// This is equivalent to message.MESSAGE_FACTORY // -// The returned pool is suitable for finding fields and building submessages, +// The returned factory is suitable for finding fields and building submessages, // even in the case of extensions. -PyDescriptorPool* GetDescriptorPoolForMessage(CMessage* message); +// Returns a *borrowed* reference, and never fails because we pass a CMessage. +PyMessageFactory* GetFactoryForMessage(CMessage* message); + +PyObject* SetAllowOversizeProtos(PyObject* m, PyObject* arg); } // namespace cmessage @@ -249,25 +275,25 @@ PyDescriptorPool* GetDescriptorPoolForMessage(CMessage* message); #define GOOGLE_CHECK_GET_INT32(arg, value, err) \ int32 value; \ - if (!CheckAndGetInteger(arg, &value, kint32min_py, kint32max_py)) { \ + if (!CheckAndGetInteger(arg, &value)) { \ return err; \ } #define GOOGLE_CHECK_GET_INT64(arg, value, err) \ int64 value; \ - if (!CheckAndGetInteger(arg, &value, kint64min_py, kint64max_py)) { \ + if (!CheckAndGetInteger(arg, &value)) { \ return err; \ } #define GOOGLE_CHECK_GET_UINT32(arg, value, err) \ uint32 value; \ - if (!CheckAndGetInteger(arg, &value, kPythonZero, kuint32max_py)) { \ + if (!CheckAndGetInteger(arg, &value)) { \ return err; \ } #define GOOGLE_CHECK_GET_UINT64(arg, value, err) \ uint64 value; \ - if (!CheckAndGetInteger(arg, &value, kPythonZero, kuint64max_py)) { \ + if (!CheckAndGetInteger(arg, &value)) { \ return err; \ } @@ -290,20 +316,11 @@ PyDescriptorPool* GetDescriptorPoolForMessage(CMessage* message); } -extern PyObject* kPythonZero; -extern PyObject* kint32min_py; -extern PyObject* kint32max_py; -extern PyObject* kuint32max_py; -extern PyObject* kint64min_py; -extern PyObject* kint64max_py; -extern PyObject* kuint64max_py; - #define FULL_MODULE_NAME "google.protobuf.pyext._message" void FormatTypeError(PyObject* arg, char* expected_types); template<class T> -bool CheckAndGetInteger( - PyObject* arg, T* value, PyObject* min, PyObject* max); +bool CheckAndGetInteger(PyObject* arg, T* value); bool CheckAndGetDouble(PyObject* arg, double* value); bool CheckAndGetFloat(PyObject* arg, float* value); bool CheckAndGetBool(PyObject* arg, bool* value); @@ -314,7 +331,8 @@ bool CheckAndSetString( const Reflection* reflection, bool append, int index); -PyObject* ToStringObject(const FieldDescriptor* descriptor, string value); +PyObject* ToStringObject(const FieldDescriptor* descriptor, + const string& value); // Check if the passed field descriptor belongs to the given message. // If not, return false and set a Python exception (a KeyError) @@ -323,6 +341,20 @@ bool CheckFieldBelongsToMessage(const FieldDescriptor* field_descriptor, extern PyObject* PickleError_class; +const Message* PyMessage_GetMessagePointer(PyObject* msg); +Message* PyMessage_GetMutableMessagePointer(PyObject* msg); + +bool InitProto2MessageModule(PyObject *m); + +#if LANG_CXX11 +// These are referenced by repeated_scalar_container, and must +// be explicitly instantiated. +extern template bool CheckAndGetInteger<int32>(PyObject*, int32*); +extern template bool CheckAndGetInteger<int64>(PyObject*, int64*); +extern template bool CheckAndGetInteger<uint32>(PyObject*, uint32*); +extern template bool CheckAndGetInteger<uint64>(PyObject*, uint64*); +#endif + } // namespace python } // namespace protobuf |