| Index: third_party/protobuf/src/google/protobuf/repeated_field.h
|
| diff --git a/third_party/protobuf/src/google/protobuf/repeated_field.h b/third_party/protobuf/src/google/protobuf/repeated_field.h
|
| index 432236ce45b522bae1b32d3438cb2dd5006783f6..1961bc4810b0c9ee74f01bfd2c5f49422c1a62a8 100644
|
| --- a/third_party/protobuf/src/google/protobuf/repeated_field.h
|
| +++ b/third_party/protobuf/src/google/protobuf/repeated_field.h
|
| @@ -244,7 +244,7 @@ class RepeatedField {
|
| int total_size_;
|
| struct Rep {
|
| Arena* arena;
|
| - Element elements[1];
|
| + Element elements[1];
|
| };
|
| // We can not use sizeof(Rep) - sizeof(Element) due to the trailing padding on
|
| // the struct. We can not use sizeof(Arena*) as well because there might be
|
| @@ -272,6 +272,22 @@ class RepeatedField {
|
| inline Arena* GetArenaNoVirtual() const {
|
| return (rep_ == NULL) ? NULL : rep_->arena;
|
| }
|
| +
|
| + // Internal helper to delete all elements and deallocate the storage.
|
| + // If Element has a trivial destructor (for example, if it's a fundamental
|
| + // type, like int32), the loop will be removed by the optimizer.
|
| + void InternalDeallocate(Rep* rep, int size) {
|
| + if (rep != NULL) {
|
| + Element* e = &rep->elements[0];
|
| + Element* limit = &rep->elements[size];
|
| + for (; e < limit; e++) {
|
| + e->Element::~Element();
|
| + }
|
| + if (rep->arena == NULL) {
|
| + delete[] reinterpret_cast<char*>(rep);
|
| + }
|
| + }
|
| + }
|
| };
|
|
|
| template<typename Element>
|
| @@ -574,7 +590,7 @@ class GenericTypeHandler {
|
|
|
| template <typename GenericType>
|
| GenericType* GenericTypeHandler<GenericType>::NewFromPrototype(
|
| - const GenericType* prototype, ::google::protobuf::Arena* arena) {
|
| + const GenericType* /* prototype */, ::google::protobuf::Arena* arena) {
|
| return New(arena);
|
| }
|
| template <typename GenericType>
|
| @@ -610,6 +626,13 @@ inline void* GenericTypeHandler<MessageLite>::GetMaybeArenaPointer(
|
| template <>
|
| void GenericTypeHandler<MessageLite>::Merge(const MessageLite& from,
|
| MessageLite* to);
|
| +template<>
|
| +inline void GenericTypeHandler<string>::Clear(string* value) {
|
| + value->clear();
|
| +}
|
| +template<>
|
| +void GenericTypeHandler<string>::Merge(const string& from,
|
| + string* to);
|
|
|
| // Declarations of the specialization as we cannot define them here, as the
|
| // header that defines ProtocolMessage depends on types defined in this header.
|
| @@ -627,7 +650,7 @@ void GenericTypeHandler<MessageLite>::Merge(const MessageLite& from,
|
| // Message specialization bodies defined in message.cc. This split is necessary
|
| // to allow proto2-lite (which includes this header) to be independent of
|
| // Message.
|
| -DECLARE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES(Message);
|
| +DECLARE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES(Message)
|
|
|
|
|
| #undef DECLARE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES
|
| @@ -674,7 +697,7 @@ class LIBPROTOBUF_EXPORT StringTypeHandlerBase {
|
| static inline ::google::protobuf::Arena* GetArena(string*) {
|
| return NULL;
|
| }
|
| - static inline void* GetMaybeArenaPointer(string* value) {
|
| + static inline void* GetMaybeArenaPointer(string* /* value */) {
|
| return NULL;
|
| }
|
| static inline void Delete(string* value, Arena* arena) {
|
| @@ -692,7 +715,7 @@ class LIBPROTOBUF_EXPORT StringTypeHandlerBase {
|
| class StringTypeHandler : public StringTypeHandlerBase {
|
| public:
|
| static int SpaceUsed(const string& value) {
|
| - return sizeof(value) + StringSpaceUsedExcludingSelf(value);
|
| + return static_cast<int>(sizeof(value)) + StringSpaceUsedExcludingSelf(value);
|
| }
|
| };
|
|
|
| @@ -836,6 +859,15 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase {
|
| // Add an already-allocated object, skipping arena-ownership checks. The user
|
| // must guarantee that the given object is in the same arena as this
|
| // RepeatedPtrField.
|
| + // It is also useful in legacy code that uses temporary ownership to avoid
|
| + // copies. Example:
|
| + // RepeatedPtrField<T> temp_field;
|
| + // temp_field.AddAllocated(new T);
|
| + // ... // Do something with temp_field
|
| + // temp_field.ExtractSubrange(0, temp_field.size(), NULL);
|
| + // If you put temp_field on the arena this fails, because the ownership
|
| + // transfers to the arena at the "AddAllocated" call and is not released
|
| + // anymore causing a double delete. UnsafeArenaAddAllocated prevents this.
|
| void UnsafeArenaAddAllocated(Element* value);
|
|
|
| // Remove the last element and return it. Works only when operating on an
|
| @@ -992,19 +1024,8 @@ RepeatedField<Element>::RepeatedField(Iter begin, const Iter& end)
|
| template <typename Element>
|
| RepeatedField<Element>::~RepeatedField() {
|
| // See explanation in Reserve(): we need to invoke destructors here for the
|
| - // case that Element has a non-trivial destructor. If Element has a trivial
|
| - // destructor (for example, if it's a primitive type, like int32), this entire
|
| - // loop will be removed by the optimizer.
|
| - if (rep_ != NULL) {
|
| - Element* e = &rep_->elements[0];
|
| - Element* limit = &rep_->elements[total_size_];
|
| - for (; e < limit; e++) {
|
| - e->Element::~Element();
|
| - }
|
| - if (rep_->arena == NULL) {
|
| - delete[] reinterpret_cast<char*>(rep_);
|
| - }
|
| - }
|
| + // case that Element has a non-trivial destructor.
|
| + InternalDeallocate(rep_, total_size_);
|
| }
|
|
|
| template <typename Element>
|
| @@ -1240,8 +1261,8 @@ void RepeatedField<Element>::Reserve(int new_size) {
|
| if (total_size_ >= new_size) return;
|
| Rep* old_rep = rep_;
|
| Arena* arena = GetArenaNoVirtual();
|
| - new_size = max(google::protobuf::internal::kMinRepeatedFieldAllocationSize,
|
| - max(total_size_ * 2, new_size));
|
| + new_size = std::max(google::protobuf::internal::kMinRepeatedFieldAllocationSize,
|
| + std::max(total_size_ * 2, new_size));
|
| GOOGLE_CHECK_LE(static_cast<size_t>(new_size),
|
| (std::numeric_limits<size_t>::max() - kRepHeaderSize) /
|
| sizeof(Element))
|
| @@ -1274,18 +1295,10 @@ void RepeatedField<Element>::Reserve(int new_size) {
|
| if (current_size_ > 0) {
|
| MoveArray(rep_->elements, old_rep->elements, current_size_);
|
| }
|
| - if (old_rep) {
|
| - // Likewise, we need to invoke destructors on the old array. If Element has
|
| - // no destructor, this loop will disappear.
|
| - e = &old_rep->elements[0];
|
| - limit = &old_rep->elements[old_total_size];
|
| - for (; e < limit; e++) {
|
| - e->Element::~Element();
|
| - }
|
| - if (arena == NULL) {
|
| - delete[] reinterpret_cast<char*>(old_rep);
|
| - }
|
| - }
|
| +
|
| + // Likewise, we need to invoke destructors on the old array.
|
| + InternalDeallocate(old_rep, old_total_size);
|
| +
|
| }
|
|
|
| template <typename Element>
|
| @@ -2380,6 +2393,37 @@ template<typename T> class AllocatedRepeatedPtrFieldBackInsertIterator
|
| private:
|
| RepeatedPtrField<T>* field_;
|
| };
|
| +
|
| +// Almost identical to AllocatedRepeatedPtrFieldBackInsertIterator. This one
|
| +// uses the UnsafeArenaAddAllocated instead.
|
| +template<typename T>
|
| +class UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator
|
| + : public std::iterator<std::output_iterator_tag, T> {
|
| + public:
|
| + explicit UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator(
|
| + ::google::protobuf::RepeatedPtrField<T>* const mutable_field)
|
| + : field_(mutable_field) {
|
| + }
|
| + UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>& operator=(
|
| + T const* const ptr_to_value) {
|
| + field_->UnsafeArenaAddAllocated(const_cast<T*>(ptr_to_value));
|
| + return *this;
|
| + }
|
| + UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>& operator*() {
|
| + return *this;
|
| + }
|
| + UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>& operator++() {
|
| + return *this;
|
| + }
|
| + UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>& operator++(
|
| + int /* unused */) {
|
| + return *this;
|
| + }
|
| +
|
| + private:
|
| + ::google::protobuf::RepeatedPtrField<T>* field_;
|
| +};
|
| +
|
| } // namespace internal
|
|
|
| // Provides a back insert iterator for RepeatedField instances,
|
| @@ -2414,6 +2458,25 @@ AllocatedRepeatedPtrFieldBackInserter(
|
| mutable_field);
|
| }
|
|
|
| +// Similar to AllocatedRepeatedPtrFieldBackInserter, using
|
| +// UnsafeArenaAddAllocated instead of AddAllocated.
|
| +// This is slightly faster if that matters. It is also useful in legacy code
|
| +// that uses temporary ownership to avoid copies. Example:
|
| +// RepeatedPtrField<T> temp_field;
|
| +// temp_field.AddAllocated(new T);
|
| +// ... // Do something with temp_field
|
| +// temp_field.ExtractSubrange(0, temp_field.size(), NULL);
|
| +// If you put temp_field on the arena this fails, because the ownership
|
| +// transfers to the arena at the "AddAllocated" call and is not released anymore
|
| +// causing a double delete. Using UnsafeArenaAddAllocated prevents this.
|
| +template<typename T>
|
| +internal::UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>
|
| +UnsafeArenaAllocatedRepeatedPtrFieldBackInserter(
|
| + ::google::protobuf::RepeatedPtrField<T>* const mutable_field) {
|
| + return internal::UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>(
|
| + mutable_field);
|
| +}
|
| +
|
| } // namespace protobuf
|
|
|
| } // namespace google
|
|
|