aboutsummaryrefslogtreecommitdiffhomepage
path: root/python/google/protobuf/pyext/message.cc
diff options
context:
space:
mode:
Diffstat (limited to 'python/google/protobuf/pyext/message.cc')
-rw-r--r--python/google/protobuf/pyext/message.cc141
1 files changed, 82 insertions, 59 deletions
diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc
index ef75acab..53736b9c 100644
--- a/python/google/protobuf/pyext/message.cc
+++ b/python/google/protobuf/pyext/message.cc
@@ -35,9 +35,6 @@
#include <map>
#include <memory>
-#ifndef _SHARED_PTR_H
-#include <google/protobuf/stubs/shared_ptr.h>
-#endif
#include <string>
#include <vector>
#include <structmember.h> // A Python header file.
@@ -605,18 +602,16 @@ void OutOfRangeError(PyObject* arg) {
template<class RangeType, class ValueType>
bool VerifyIntegerCastAndRange(PyObject* arg, ValueType value) {
- if
- GOOGLE_PREDICT_FALSE(value == -1 && PyErr_Occurred()) {
- if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
- // Replace it with the same ValueError as pure python protos instead of
- // the default one.
- PyErr_Clear();
- OutOfRangeError(arg);
- } // Otherwise propagate existing error.
- return false;
+ if (GOOGLE_PREDICT_FALSE(value == -1 && PyErr_Occurred())) {
+ if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
+ // Replace it with the same ValueError as pure python protos instead of
+ // the default one.
+ PyErr_Clear();
+ OutOfRangeError(arg);
+ } // Otherwise propagate existing error.
+ return false;
}
- if
- GOOGLE_PREDICT_FALSE(!IsValidNumericCast<RangeType>(value)) {
+ if (GOOGLE_PREDICT_FALSE(!IsValidNumericCast<RangeType>(value))) {
OutOfRangeError(arg);
return false;
}
@@ -628,26 +623,22 @@ bool CheckAndGetInteger(PyObject* arg, T* value) {
// The fast path.
#if PY_MAJOR_VERSION < 3
// For the typical case, offer a fast path.
- if
- GOOGLE_PREDICT_TRUE(PyInt_Check(arg)) {
- long int_result = PyInt_AsLong(arg);
- if
- GOOGLE_PREDICT_TRUE(IsValidNumericCast<T>(int_result)) {
- *value = static_cast<T>(int_result);
- return true;
- }
- else {
- OutOfRangeError(arg);
- return false;
- }
+ if (GOOGLE_PREDICT_TRUE(PyInt_Check(arg))) {
+ long int_result = PyInt_AsLong(arg);
+ if (GOOGLE_PREDICT_TRUE(IsValidNumericCast<T>(int_result))) {
+ *value = static_cast<T>(int_result);
+ return true;
+ } else {
+ OutOfRangeError(arg);
+ return false;
+ }
}
#endif
// This effectively defines an integer as "an object that can be cast as
// an integer and can be used as an ordinal number".
// This definition includes everything that implements numbers.Integral
// and shouldn't cast the net too wide.
- if
- GOOGLE_PREDICT_FALSE(!PyIndex_Check(arg)) {
+ if (GOOGLE_PREDICT_FALSE(!PyIndex_Check(arg))) {
FormatTypeError(arg, "int, long");
return false;
}
@@ -664,10 +655,9 @@ bool CheckAndGetInteger(PyObject* arg, T* value) {
// Unlike PyLong_AsLongLong, PyLong_AsUnsignedLongLong is very
// picky about the exact type.
PyObject* casted = PyNumber_Long(arg);
- if
- GOOGLE_PREDICT_FALSE(casted == NULL) {
- // Propagate existing error.
- return false;
+ if (GOOGLE_PREDICT_FALSE(casted == nullptr)) {
+ // Propagate existing error.
+ return false;
}
ulong_result = PyLong_AsUnsignedLongLong(casted);
Py_DECREF(casted);
@@ -690,10 +680,9 @@ bool CheckAndGetInteger(PyObject* arg, T* value) {
// Valid subclasses of numbers.Integral should have a __long__() method
// so fall back to that.
PyObject* casted = PyNumber_Long(arg);
- if
- GOOGLE_PREDICT_FALSE(casted == NULL) {
- // Propagate existing error.
- return false;
+ if (GOOGLE_PREDICT_FALSE(casted == nullptr)) {
+ // Propagate existing error.
+ return false;
}
long_result = PyLong_AsLongLong(casted);
Py_DECREF(casted);
@@ -717,10 +706,9 @@ template bool CheckAndGetInteger<uint64>(PyObject*, uint64*);
bool CheckAndGetDouble(PyObject* arg, double* value) {
*value = PyFloat_AsDouble(arg);
- if
- GOOGLE_PREDICT_FALSE(*value == -1 && PyErr_Occurred()) {
- FormatTypeError(arg, "int, long, float");
- return false;
+ if (GOOGLE_PREDICT_FALSE(*value == -1 && PyErr_Occurred())) {
+ FormatTypeError(arg, "int, long, float");
+ return false;
}
return true;
}
@@ -839,7 +827,8 @@ bool CheckAndSetString(
return true;
}
-PyObject* ToStringObject(const FieldDescriptor* descriptor, string value) {
+PyObject* ToStringObject(const FieldDescriptor* descriptor,
+ const string& value) {
if (descriptor->type() != FieldDescriptor::TYPE_STRING) {
return PyBytes_FromStringAndSize(value.c_str(), value.length());
}
@@ -1187,7 +1176,7 @@ int InitAttributes(CMessage* self, PyObject* args, PyObject* kwargs) {
continue;
}
if (descriptor->is_map()) {
- ScopedPyObjectPtr map(GetAttr(self, name));
+ ScopedPyObjectPtr map(GetAttr(reinterpret_cast<PyObject*>(self), name));
const FieldDescriptor* value_descriptor =
descriptor->message_type()->FindFieldByName("value");
if (value_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
@@ -1215,7 +1204,8 @@ int InitAttributes(CMessage* self, PyObject* args, PyObject* kwargs) {
}
}
} else if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
- ScopedPyObjectPtr container(GetAttr(self, name));
+ ScopedPyObjectPtr container(
+ GetAttr(reinterpret_cast<PyObject*>(self), name));
if (container == NULL) {
return -1;
}
@@ -1282,7 +1272,8 @@ int InitAttributes(CMessage* self, PyObject* args, PyObject* kwargs) {
}
}
} else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
- ScopedPyObjectPtr message(GetAttr(self, name));
+ ScopedPyObjectPtr message(
+ GetAttr(reinterpret_cast<PyObject*>(self), name));
if (message == NULL) {
return -1;
}
@@ -1307,8 +1298,8 @@ int InitAttributes(CMessage* self, PyObject* args, PyObject* kwargs) {
return -1;
}
}
- if (SetAttr(self, name, (new_val.get() == NULL) ? value : new_val.get()) <
- 0) {
+ if (SetAttr(reinterpret_cast<PyObject*>(self), name,
+ (new_val.get() == NULL) ? value : new_val.get()) < 0) {
return -1;
}
}
@@ -1325,6 +1316,8 @@ CMessage* NewEmptyMessage(CMessageClass* type) {
return NULL;
}
+ // Use "placement new" syntax to initialize the C++ object.
+ new (&self->owner) CMessage::OwnerRef(NULL);
self->message = NULL;
self->parent = NULL;
self->parent_field_descriptor = NULL;
@@ -1421,7 +1414,7 @@ static void Dealloc(CMessage* self) {
Py_CLEAR(self->extensions);
Py_CLEAR(self->composite_fields);
- self->owner.reset();
+ self->owner.~ThreadUnsafeSharedPtr<Message>();
Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
}
@@ -1623,9 +1616,10 @@ PyObject* HasExtension(CMessage* self, PyObject* extension) {
// * Clear the weak references from the released container to the
// parent.
-struct SetOwnerVisitor : public ChildVisitor {
+class SetOwnerVisitor : public ChildVisitor {
+ public:
// new_owner must outlive this object.
- explicit SetOwnerVisitor(const shared_ptr<Message>& new_owner)
+ explicit SetOwnerVisitor(const CMessage::OwnerRef& new_owner)
: new_owner_(new_owner) {}
int VisitRepeatedCompositeContainer(RepeatedCompositeContainer* container) {
@@ -1649,11 +1643,11 @@ struct SetOwnerVisitor : public ChildVisitor {
}
private:
- const shared_ptr<Message>& new_owner_;
+ const CMessage::OwnerRef& new_owner_;
};
// Change the owner of this CMessage and all its children, recursively.
-int SetOwner(CMessage* self, const shared_ptr<Message>& new_owner) {
+int SetOwner(CMessage* self, const CMessage::OwnerRef& new_owner) {
self->owner = new_owner;
if (ForEachCompositeField(self, SetOwnerVisitor(new_owner)) == -1)
return -1;
@@ -1686,7 +1680,7 @@ int ReleaseSubMessage(CMessage* self,
const FieldDescriptor* field_descriptor,
CMessage* child_cmessage) {
// Release the Message
- shared_ptr<Message> released_message(ReleaseMessage(
+ CMessage::OwnerRef released_message(ReleaseMessage(
self, child_cmessage->message->GetDescriptor(), field_descriptor));
child_cmessage->message = released_message.get();
child_cmessage->owner.swap(released_message);
@@ -2211,7 +2205,8 @@ static PyObject* ListFields(CMessage* self) {
return NULL;
}
- PyObject* field_value = GetAttr(self, py_field_name.get());
+ PyObject* field_value =
+ GetAttr(reinterpret_cast<PyObject*>(self), py_field_name.get());
if (field_value == NULL) {
PyErr_SetObject(PyExc_ValueError, py_field_name.get());
return NULL;
@@ -2335,7 +2330,9 @@ PyObject* InternalGetScalar(const Message* message,
break;
}
case FieldDescriptor::CPPTYPE_STRING: {
- string value = reflection->GetString(*message, field_descriptor);
+ string scratch;
+ const string& value =
+ reflection->GetStringReference(*message, field_descriptor, &scratch);
result = ToStringObject(field_descriptor, value);
break;
}
@@ -2707,7 +2704,8 @@ static bool SetCompositeField(
return PyDict_SetItem(self->composite_fields, name, value) == 0;
}
-PyObject* GetAttr(CMessage* self, PyObject* name) {
+PyObject* GetAttr(PyObject* pself, PyObject* name) {
+ CMessage* self = reinterpret_cast<CMessage*>(pself);
PyObject* value = self->composite_fields ?
PyDict_GetItem(self->composite_fields, name) : NULL;
if (value != NULL) {
@@ -2785,7 +2783,8 @@ PyObject* GetAttr(CMessage* self, PyObject* name) {
return InternalGetScalar(self->message, field_descriptor);
}
-int SetAttr(CMessage* self, PyObject* name, PyObject* value) {
+int SetAttr(PyObject* pself, PyObject* name, PyObject* value) {
+ CMessage* self = reinterpret_cast<CMessage*>(pself);
if (self->composite_fields && PyDict_Contains(self->composite_fields, name)) {
PyErr_SetString(PyExc_TypeError, "Can't set composite field");
return -1;
@@ -2837,8 +2836,8 @@ PyTypeObject CMessage_Type = {
PyObject_HashNotImplemented, // tp_hash
0, // tp_call
(reprfunc)cmessage::ToStr, // tp_str
- (getattrofunc)cmessage::GetAttr, // tp_getattro
- (setattrofunc)cmessage::SetAttr, // tp_setattro
+ cmessage::GetAttr, // tp_getattro
+ cmessage::SetAttr, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
"A ProtocolMessage", // tp_doc
@@ -2867,17 +2866,38 @@ const Message* (*GetCProtoInsidePyProtoPtr)(PyObject* msg);
Message* (*MutableCProtoInsidePyProtoPtr)(PyObject* msg);
static const Message* GetCProtoInsidePyProtoImpl(PyObject* msg) {
+ const Message* message = PyMessage_GetMessagePointer(msg);
+ if (message == NULL) {
+ PyErr_Clear();
+ return NULL;
+ }
+ return message;
+}
+
+static Message* MutableCProtoInsidePyProtoImpl(PyObject* msg) {
+ Message* message = PyMessage_GetMutableMessagePointer(msg);
+ if (message == NULL) {
+ PyErr_Clear();
+ return NULL;
+ }
+ return message;
+}
+
+const Message* PyMessage_GetMessagePointer(PyObject* msg) {
if (!PyObject_TypeCheck(msg, &CMessage_Type)) {
+ PyErr_SetString(PyExc_TypeError, "Not a Message instance");
return NULL;
}
CMessage* cmsg = reinterpret_cast<CMessage*>(msg);
return cmsg->message;
}
-static Message* MutableCProtoInsidePyProtoImpl(PyObject* msg) {
+Message* PyMessage_GetMutableMessagePointer(PyObject* msg) {
if (!PyObject_TypeCheck(msg, &CMessage_Type)) {
+ PyErr_SetString(PyExc_TypeError, "Not a Message instance");
return NULL;
}
+
CMessage* cmsg = reinterpret_cast<CMessage*>(msg);
if ((cmsg->composite_fields && PyDict_Size(cmsg->composite_fields) != 0) ||
(cmsg->extensions != NULL &&
@@ -2886,6 +2906,9 @@ static Message* MutableCProtoInsidePyProtoImpl(PyObject* msg) {
// the underlying C++ message back to the CMessage (e.g. removed repeated
// composite containers). We only allow direct mutation of the underlying
// C++ message if there is no child data in the CMessage.
+ PyErr_SetString(PyExc_ValueError,
+ "Cannot reliably get a mutable pointer "
+ "to a message with extra references");
return NULL;
}
cmessage::AssureWritable(cmsg);