@@ -149,6 +149,13 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
149
149
template <typename Handler>
150
150
using Value = typename Handler::Type;
151
151
152
+ // We use the same Handler for all Message types to deduplicate generated
153
+ // code.
154
+ template <typename Handler>
155
+ using CommonHandler = typename std::conditional<
156
+ std::is_base_of<MessageLite, Value<Handler>>::value,
157
+ internal::GenericTypeHandler<MessageLite>, Handler>::type;
158
+
152
159
static constexpr int kSSOCapacity = 1 ;
153
160
154
161
protected:
@@ -230,27 +237,24 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
230
237
void Delete (int index) {
231
238
ABSL_DCHECK_GE (index, 0 );
232
239
ABSL_DCHECK_LT (index, current_size_);
233
- Delete<TypeHandler>(element_at (index), arena_);
240
+ using H = CommonHandler<TypeHandler>;
241
+ Delete<H>(element_at (index), arena_);
234
242
}
235
243
236
244
// Must be called from destructor.
237
245
template <typename TypeHandler>
238
246
void Destroy () {
247
+ using H = CommonHandler<TypeHandler>;
239
248
if (arena_ != nullptr ) return ;
240
-
241
- if (using_sso ()) {
242
- if (tagged_rep_or_elem_ == nullptr ) return ;
243
- Delete<TypeHandler>(tagged_rep_or_elem_, nullptr );
244
- return ;
245
- }
246
-
247
- Rep* r = rep ();
248
- int n = r->allocated_size ;
249
- void * const * elems = r->elements ;
249
+ int n = allocated_size ();
250
+ void ** elems = elements ();
250
251
for (int i = 0 ; i < n; i++) {
251
- Delete<TypeHandler>(elems[i], nullptr );
252
+ Delete<H>(elems[i], nullptr );
253
+ }
254
+ if (!using_sso ()) {
255
+ internal::SizedDelete (rep (),
256
+ total_size_ * sizeof (elems[0 ]) + kRepHeaderSize );
252
257
}
253
- internal::SizedDelete (r, total_size_ * sizeof (elems[0 ]) + kRepHeaderSize );
254
258
}
255
259
256
260
bool NeedsDestroy () const {
@@ -281,7 +285,8 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
281
285
const int n = current_size_;
282
286
ABSL_DCHECK_GE (n, 0 );
283
287
if (n > 0 ) {
284
- ClearNonEmpty<TypeHandler>();
288
+ using H = CommonHandler<TypeHandler>;
289
+ ClearNonEmpty<H>();
285
290
}
286
291
}
287
292
@@ -295,8 +300,8 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
295
300
// calls the object-allocate and merge handlers.
296
301
ABSL_DCHECK_NE (&other, this );
297
302
if (other.current_size_ == 0 ) return ;
298
- MergeFromInternal (other,
299
- &RepeatedPtrFieldBase::MergeFromInnerLoop<TypeHandler >);
303
+ using H = CommonHandler<TypeHandler>;
304
+ MergeFromInternal (other, &RepeatedPtrFieldBase::MergeFromInnerLoop<H >);
300
305
}
301
306
302
307
inline void InternalSwap (RepeatedPtrFieldBase* PROTOBUF_RESTRICT rhs) {
@@ -332,7 +337,8 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
332
337
void RemoveLast () {
333
338
ABSL_DCHECK_GT (current_size_, 0 );
334
339
ExchangeCurrentSize (current_size_ - 1 );
335
- TypeHandler::Clear (cast<TypeHandler>(element_at (current_size_)));
340
+ using H = CommonHandler<TypeHandler>;
341
+ H::Clear (cast<H>(element_at (current_size_)));
336
342
}
337
343
338
344
template <typename TypeHandler>
@@ -348,9 +354,10 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
348
354
349
355
template <typename TypeHandler>
350
356
static inline Value<TypeHandler>* copy (Value<TypeHandler>* value) {
351
- auto * new_value = TypeHandler::NewFromPrototype (value, nullptr );
352
- TypeHandler::Merge (*value, new_value);
353
- return new_value;
357
+ using H = CommonHandler<TypeHandler>;
358
+ auto * new_value = H::NewFromPrototype (value, nullptr );
359
+ H::Merge (*value, new_value);
360
+ return cast<TypeHandler>(new_value);
354
361
}
355
362
356
363
// Used for constructing iterators.
@@ -392,7 +399,7 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
392
399
}
393
400
394
401
template <typename TypeHandler>
395
- size_t SpaceUsedExcludingSelfLong () const {
402
+ PROTOBUF_NOINLINE size_t SpaceUsedExcludingSelfLong () const {
396
403
size_t allocated_bytes =
397
404
using_sso ()
398
405
? 0
@@ -437,7 +444,8 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
437
444
// cleared objects awaiting reuse. We don't want to grow the array in
438
445
// this case because otherwise a loop calling AddAllocated() followed by
439
446
// Clear() would leak memory.
440
- Delete<TypeHandler>(element_at (current_size_), arena_);
447
+ using H = CommonHandler<TypeHandler>;
448
+ Delete<H>(element_at (current_size_), arena_);
441
449
} else if (current_size_ < allocated_size ()) {
442
450
// We have some cleared objects. We don't care about their order, so we
443
451
// can just move the first one to the end to make space.
@@ -568,8 +576,9 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
568
576
my_arena->Own (value);
569
577
} else if (my_arena != value_arena) {
570
578
auto * new_value = TypeHandler::NewFromPrototype (value, my_arena);
571
- TypeHandler::Merge (*value, new_value);
572
- TypeHandler::Delete (value, value_arena);
579
+ using H = CommonHandler<TypeHandler>;
580
+ H::Merge (*value, new_value);
581
+ H::Delete (value, value_arena);
573
582
value = new_value;
574
583
}
575
584
@@ -741,9 +750,8 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
741
750
const int n = current_size_;
742
751
void * const * elems = elements ();
743
752
int i = 0 ;
744
- ABSL_DCHECK_GT (
745
- n,
746
- 0 ); // do/while loop to avoid initial test because we know n > 0
753
+ ABSL_DCHECK_GT (n, 0 );
754
+ // do/while loop to avoid initial test because we know n > 0
747
755
do {
748
756
TypeHandler::Clear (cast<TypeHandler>(elems[i++]));
749
757
} while (i < n);
@@ -866,7 +874,8 @@ class GenericTypeHandler {
866
874
// NewFromPrototypeHelper() is not defined inline here, as we will need to do a
867
875
// virtual function dispatch anyways to go from Message* to call New/Merge. (The
868
876
// additional helper is needed as a workaround for MSVC.)
869
- MessageLite* NewFromPrototypeHelper (const MessageLite* prototype, Arena* arena);
877
+ PROTOBUF_EXPORT MessageLite* NewFromPrototypeHelper (
878
+ const MessageLite* prototype, Arena* arena);
870
879
871
880
template <>
872
881
inline MessageLite* GenericTypeHandler<MessageLite>::NewFromPrototype(
@@ -885,8 +894,8 @@ PROTOBUF_NOINLINE inline void GenericTypeHandler<GenericType>::Merge(
885
894
to->MergeFrom (from);
886
895
}
887
896
template <>
888
- void GenericTypeHandler<MessageLite>::Merge(const MessageLite& from,
889
- MessageLite* to);
897
+ PROTOBUF_EXPORT void GenericTypeHandler<MessageLite>::Merge(
898
+ const MessageLite& from, MessageLite* to);
890
899
891
900
template <>
892
901
inline void GenericTypeHandler<std::string>::Clear(std::string* value) {
@@ -1642,7 +1651,13 @@ inline Arena* RepeatedPtrField<Element>::GetOwningArena() const {
1642
1651
1643
1652
template <typename Element>
1644
1653
inline size_t RepeatedPtrField<Element>::SpaceUsedExcludingSelfLong () const {
1645
- return RepeatedPtrFieldBase::SpaceUsedExcludingSelfLong<TypeHandler>();
1654
+ // `google::protobuf::Message` has a virtual method `SpaceUsedLong`, hence we can
1655
+ // instantiate just one function for all protobuf messages.
1656
+ // Note: std::is_base_of requires that `Element` is a concrete class.
1657
+ using H = typename std::conditional<std::is_base_of<Message, Element>::value,
1658
+ internal::GenericTypeHandler<Message>,
1659
+ TypeHandler>::type;
1660
+ return RepeatedPtrFieldBase::SpaceUsedExcludingSelfLong<H>();
1646
1661
}
1647
1662
1648
1663
template <typename Element>
0 commit comments