• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 // This file defines an Arena allocator for better allocation performance.
32 
33 #ifndef GOOGLE_PROTOBUF_ARENA_H__
34 #define GOOGLE_PROTOBUF_ARENA_H__
35 
36 #include <limits>
37 #include <type_traits>
38 #include <utility>
39 #ifdef max
40 #undef max  // Visual Studio defines this macro
41 #endif
42 #if defined(_MSC_VER) && !defined(_LIBCPP_STD_VER) && !_HAS_EXCEPTIONS
43 // Work around bugs in MSVC <typeinfo> header when _HAS_EXCEPTIONS=0.
44 #include <exception>
45 #include <typeinfo>
46 namespace std {
47 using type_info = ::type_info;
48 }
49 #else
50 #include <typeinfo>
51 #endif
52 
53 #include <google/protobuf/arena_impl.h>
54 #include <google/protobuf/port.h>
55 #include <type_traits>
56 
57 #include <google/protobuf/port_def.inc>
58 
59 #ifdef SWIG
60 #error "You cannot SWIG proto headers"
61 #endif
62 
63 namespace google {
64 namespace protobuf {
65 
66 struct ArenaOptions;  // defined below
67 
68 }  // namespace protobuf
69 }  // namespace google
70 
71 
72 namespace google {
73 namespace protobuf {
74 
75 class Arena;    // defined below
76 class Message;  // defined in message.h
77 class MessageLite;
78 
79 namespace arena_metrics {
80 
81 void EnableArenaMetrics(ArenaOptions* options);
82 
83 }  // namespace arena_metrics
84 
85 namespace internal {
86 
87 struct ArenaStringPtr;  // defined in arenastring.h
88 class LazyField;        // defined in lazy_field.h
89 
90 template <typename Type>
91 class GenericTypeHandler;  // defined in repeated_field.h
92 
93 // Templated cleanup methods.
94 template <typename T>
arena_destruct_object(void * object)95 void arena_destruct_object(void* object) {
96   reinterpret_cast<T*>(object)->~T();
97 }
98 template <typename T>
arena_delete_object(void * object)99 void arena_delete_object(void* object) {
100   delete reinterpret_cast<T*>(object);
101 }
arena_free(void * object,size_t size)102 inline void arena_free(void* object, size_t size) {
103 #if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation)
104   ::operator delete(object, size);
105 #else
106   (void)size;
107   ::operator delete(object);
108 #endif
109 }
110 
111 }  // namespace internal
112 
113 // ArenaOptions provides optional additional parameters to arena construction
114 // that control its block-allocation behavior.
115 struct ArenaOptions {
116   // This defines the size of the first block requested from the system malloc.
117   // Subsequent block sizes will increase in a geometric series up to a maximum.
118   size_t start_block_size;
119 
120   // This defines the maximum block size requested from system malloc (unless an
121   // individual arena allocation request occurs with a size larger than this
122   // maximum). Requested block sizes increase up to this value, then remain
123   // here.
124   size_t max_block_size;
125 
126   // An initial block of memory for the arena to use, or NULL for none. If
127   // provided, the block must live at least as long as the arena itself. The
128   // creator of the Arena retains ownership of the block after the Arena is
129   // destroyed.
130   char* initial_block;
131 
132   // The size of the initial block, if provided.
133   size_t initial_block_size;
134 
135   // A function pointer to an alloc method that returns memory blocks of size
136   // requested. By default, it contains a ptr to the malloc function.
137   //
138   // NOTE: block_alloc and dealloc functions are expected to behave like
139   // malloc and free, including Asan poisoning.
140   void* (*block_alloc)(size_t);
141   // A function pointer to a dealloc method that takes ownership of the blocks
142   // from the arena. By default, it contains a ptr to a wrapper function that
143   // calls free.
144   void (*block_dealloc)(void*, size_t);
145 
ArenaOptionsArenaOptions146   ArenaOptions()
147       : start_block_size(kDefaultStartBlockSize),
148         max_block_size(kDefaultMaxBlockSize),
149         initial_block(NULL),
150         initial_block_size(0),
151         block_alloc(&::operator new),
152         block_dealloc(&internal::arena_free),
153         on_arena_init(NULL),
154         on_arena_reset(NULL),
155         on_arena_destruction(NULL),
156         on_arena_allocation(NULL) {}
157 
158  private:
159   // Hooks for adding external functionality such as user-specific metrics
160   // collection, specific debugging abilities, etc.
161   // Init hook (if set) will always be called at Arena init time. Init hook may
162   // return a pointer to a cookie to be stored in the arena. Reset and
163   // destruction hooks will then be called with the same cookie pointer. This
164   // allows us to save an external object per arena instance and use it on the
165   // other hooks (Note: If init hook returns NULL, the other hooks will NOT be
166   // called on this arena instance).
167   // on_arena_reset and on_arena_destruction also receive the space used in the
168   // arena just before the reset.
169   void* (*on_arena_init)(Arena* arena);
170   void (*on_arena_reset)(Arena* arena, void* cookie, uint64 space_used);
171   void (*on_arena_destruction)(Arena* arena, void* cookie, uint64 space_used);
172 
173   // type_info is promised to be static - its lifetime extends to
174   // match program's lifetime (It is given by typeid operator).
175   // Note: typeid(void) will be passed as allocated_type every time we
176   // intentionally want to avoid monitoring an allocation. (i.e. internal
177   // allocations for managing the arena)
178   void (*on_arena_allocation)(const std::type_info* allocated_type,
179                               uint64 alloc_size, void* cookie);
180 
181   // Constants define default starting block size and max block size for
182   // arena allocator behavior -- see descriptions above.
183   static const size_t kDefaultStartBlockSize = 256;
184   static const size_t kDefaultMaxBlockSize = 8192;
185 
186   friend void arena_metrics::EnableArenaMetrics(ArenaOptions*);
187   friend class Arena;
188   friend class ArenaOptionsTestFriend;
189 };
190 
191 // Support for non-RTTI environments. (The metrics hooks API uses type
192 // information.)
193 #if PROTOBUF_RTTI
194 #define RTTI_TYPE_ID(type) (&typeid(type))
195 #else
196 #define RTTI_TYPE_ID(type) (NULL)
197 #endif
198 
199 // Arena allocator. Arena allocation replaces ordinary (heap-based) allocation
200 // with new/delete, and improves performance by aggregating allocations into
201 // larger blocks and freeing allocations all at once. Protocol messages are
202 // allocated on an arena by using Arena::CreateMessage<T>(Arena*), below, and
203 // are automatically freed when the arena is destroyed.
204 //
205 // This is a thread-safe implementation: multiple threads may allocate from the
206 // arena concurrently. Destruction is not thread-safe and the destructing
207 // thread must synchronize with users of the arena first.
208 //
209 // An arena provides two allocation interfaces: CreateMessage<T>, which works
210 // for arena-enabled proto2 message types as well as other types that satisfy
211 // the appropriate protocol (described below), and Create<T>, which works for
212 // any arbitrary type T. CreateMessage<T> is better when the type T supports it,
213 // because this interface (i) passes the arena pointer to the created object so
214 // that its sub-objects and internal allocations can use the arena too, and (ii)
215 // elides the object's destructor call when possible. Create<T> does not place
216 // any special requirements on the type T, and will invoke the object's
217 // destructor when the arena is destroyed.
218 //
219 // The arena message allocation protocol, required by CreateMessage<T>, is as
220 // follows:
221 //
222 // - The type T must have (at least) two constructors: a constructor with no
223 //   arguments, called when a T is allocated on the heap; and a constructor with
224 //   a Arena* argument, called when a T is allocated on an arena. If the
225 //   second constructor is called with a NULL arena pointer, it must be
226 //   equivalent to invoking the first (no-argument) constructor.
227 //
228 // - The type T must have a particular type trait: a nested type
229 //   |InternalArenaConstructable_|. This is usually a typedef to |void|. If no
230 //   such type trait exists, then the instantiation CreateMessage<T> will fail
231 //   to compile.
232 //
233 // - The type T *may* have the type trait |DestructorSkippable_|. If this type
234 //   trait is present in the type, then its destructor will not be called if and
235 //   only if it was passed a non-NULL arena pointer. If this type trait is not
236 //   present on the type, then its destructor is always called when the
237 //   containing arena is destroyed.
238 //
239 // - One- and two-user-argument forms of CreateMessage<T>() also exist that
240 //   forward these constructor arguments to T's constructor: for example,
241 //   CreateMessage<T>(Arena*, arg1, arg2) forwards to a constructor T(Arena*,
242 //   arg1, arg2).
243 //
244 // This protocol is implemented by all arena-enabled proto2 message classes as
245 // well as protobuf container types like RepeatedPtrField and Map. The protocol
246 // is internal to protobuf and is not guaranteed to be stable. Non-proto types
247 // should not rely on this protocol.
248 class PROTOBUF_EXPORT alignas(8) Arena final {
249  public:
250   // Arena constructor taking custom options. See ArenaOptions below for
251   // descriptions of the options available.
Arena(const ArenaOptions & options)252   explicit Arena(const ArenaOptions& options) : impl_(options) {
253     Init(options);
254   }
255 
256   // Block overhead.  Use this as a guide for how much to over-allocate the
257   // initial block if you want an allocation of size N to fit inside it.
258   //
259   // WARNING: if you allocate multiple objects, it is difficult to guarantee
260   // that a series of allocations will fit in the initial block, especially if
261   // Arena changes its alignment guarantees in the future!
262   static const size_t kBlockOverhead = internal::ArenaImpl::kBlockHeaderSize +
263                                        internal::ArenaImpl::kSerialArenaSize;
264 
265   // Default constructor with sensible default options, tuned for average
266   // use-cases.
Arena()267   Arena() : impl_(ArenaOptions()) { Init(ArenaOptions()); }
268 
~Arena()269   ~Arena() {
270     if (hooks_cookie_) {
271       CallDestructorHooks();
272     }
273   }
274 
Init(const ArenaOptions & options)275   void Init(const ArenaOptions& options) {
276     on_arena_allocation_ = options.on_arena_allocation;
277     on_arena_reset_ = options.on_arena_reset;
278     on_arena_destruction_ = options.on_arena_destruction;
279     // Call the initialization hook
280     if (options.on_arena_init != NULL) {
281       hooks_cookie_ = options.on_arena_init(this);
282     } else {
283       hooks_cookie_ = NULL;
284     }
285   }
286 
287   // API to create proto2 message objects on the arena. If the arena passed in
288   // is NULL, then a heap allocated object is returned. Type T must be a message
289   // defined in a .proto file with cc_enable_arenas set to true, otherwise a
290   // compilation error will occur.
291   //
292   // RepeatedField and RepeatedPtrField may also be instantiated directly on an
293   // arena with this method.
294   //
295   // This function also accepts any type T that satisfies the arena message
296   // allocation protocol, documented above.
297   template <typename T, typename... Args>
CreateMessage(Arena * arena,Args &&...args)298   PROTOBUF_ALWAYS_INLINE static T* CreateMessage(Arena* arena, Args&&... args) {
299     static_assert(
300         InternalHelper<T>::is_arena_constructable::value,
301         "CreateMessage can only construct types that are ArenaConstructable");
302     // We must delegate to CreateMaybeMessage() and NOT CreateMessageInternal()
303     // because protobuf generated classes specialize CreateMaybeMessage() and we
304     // need to use that specialization for code size reasons.
305     return Arena::CreateMaybeMessage<T>(arena, std::forward<Args>(args)...);
306   }
307 
308   // API to create any objects on the arena. Note that only the object will
309   // be created on the arena; the underlying ptrs (in case of a proto2 message)
310   // will be still heap allocated. Proto messages should usually be allocated
311   // with CreateMessage<T>() instead.
312   //
313   // Note that even if T satisfies the arena message construction protocol
314   // (InternalArenaConstructable_ trait and optional DestructorSkippable_
315   // trait), as described above, this function does not follow the protocol;
316   // instead, it treats T as a black-box type, just as if it did not have these
317   // traits. Specifically, T's constructor arguments will always be only those
318   // passed to Create<T>() -- no additional arena pointer is implicitly added.
319   // Furthermore, the destructor will always be called at arena destruction time
320   // (unless the destructor is trivial). Hence, from T's point of view, it is as
321   // if the object were allocated on the heap (except that the underlying memory
322   // is obtained from the arena).
323   template <typename T, typename... Args>
Create(Arena * arena,Args &&...args)324   PROTOBUF_ALWAYS_INLINE static T* Create(Arena* arena, Args&&... args) {
325     return CreateNoMessage<T>(arena, is_arena_constructable<T>(),
326                               std::forward<Args>(args)...);
327   }
328 
329   // Create an array of object type T on the arena *without* invoking the
330   // constructor of T. If `arena` is null, then the return value should be freed
331   // with `delete[] x;` (or `::operator delete[](x);`).
332   // To ensure safe uses, this function checks at compile time
333   // (when compiled as C++11) that T is trivially default-constructible and
334   // trivially destructible.
335   template <typename T>
CreateArray(Arena * arena,size_t num_elements)336   PROTOBUF_ALWAYS_INLINE static T* CreateArray(Arena* arena,
337                                                size_t num_elements) {
338     static_assert(std::is_pod<T>::value,
339                   "CreateArray requires a trivially constructible type");
340     static_assert(std::is_trivially_destructible<T>::value,
341                   "CreateArray requires a trivially destructible type");
342     GOOGLE_CHECK_LE(num_elements, std::numeric_limits<size_t>::max() / sizeof(T))
343         << "Requested size is too large to fit into size_t.";
344     if (arena == NULL) {
345       return static_cast<T*>(::operator new[](num_elements * sizeof(T)));
346     } else {
347       return arena->CreateInternalRawArray<T>(num_elements);
348     }
349   }
350 
351   // Returns the total space allocated by the arena, which is the sum of the
352   // sizes of the underlying blocks. This method is relatively fast; a counter
353   // is kept as blocks are allocated.
SpaceAllocated()354   uint64 SpaceAllocated() const { return impl_.SpaceAllocated(); }
355   // Returns the total space used by the arena. Similar to SpaceAllocated but
356   // does not include free space and block overhead. The total space returned
357   // may not include space used by other threads executing concurrently with
358   // the call to this method.
SpaceUsed()359   uint64 SpaceUsed() const { return impl_.SpaceUsed(); }
360   // DEPRECATED. Please use SpaceAllocated() and SpaceUsed().
361   //
362   // Combines SpaceAllocated and SpaceUsed. Returns a pair of
363   // <space_allocated, space_used>.
364   PROTOBUF_DEPRECATED_MSG("Please use SpaceAllocated() and SpaceUsed()")
SpaceAllocatedAndUsed()365   std::pair<uint64, uint64> SpaceAllocatedAndUsed() const {
366     return std::make_pair(SpaceAllocated(), SpaceUsed());
367   }
368 
369   // Frees all storage allocated by this arena after calling destructors
370   // registered with OwnDestructor() and freeing objects registered with Own().
371   // Any objects allocated on this arena are unusable after this call. It also
372   // returns the total space used by the arena which is the sums of the sizes
373   // of the allocated blocks. This method is not thread-safe.
Reset()374   PROTOBUF_NOINLINE uint64 Reset() {
375     // Call the reset hook
376     if (on_arena_reset_ != NULL) {
377       on_arena_reset_(this, hooks_cookie_, impl_.SpaceAllocated());
378     }
379     return impl_.Reset();
380   }
381 
382   // Adds |object| to a list of heap-allocated objects to be freed with |delete|
383   // when the arena is destroyed or reset.
384   template <typename T>
Own(T * object)385   PROTOBUF_NOINLINE void Own(T* object) {
386     OwnInternal(object, std::is_convertible<T*, Message*>());
387   }
388 
389   // Adds |object| to a list of objects whose destructors will be manually
390   // called when the arena is destroyed or reset. This differs from Own() in
391   // that it does not free the underlying memory with |delete|; hence, it is
392   // normally only used for objects that are placement-newed into
393   // arena-allocated memory.
394   template <typename T>
OwnDestructor(T * object)395   PROTOBUF_NOINLINE void OwnDestructor(T* object) {
396     if (object != NULL) {
397       impl_.AddCleanup(object, &internal::arena_destruct_object<T>);
398     }
399   }
400 
401   // Adds a custom member function on an object to the list of destructors that
402   // will be manually called when the arena is destroyed or reset. This differs
403   // from OwnDestructor() in that any member function may be specified, not only
404   // the class destructor.
OwnCustomDestructor(void * object,void (* destruct)(void *))405   PROTOBUF_NOINLINE void OwnCustomDestructor(void* object,
406                                              void (*destruct)(void*)) {
407     impl_.AddCleanup(object, destruct);
408   }
409 
410   // Retrieves the arena associated with |value| if |value| is an arena-capable
411   // message, or NULL otherwise. If possible, the call resolves at compile time.
412   // Note that we can often devirtualize calls to `value->GetArena()` so usually
413   // calling this method is unnecessary.
414   template <typename T>
GetArena(const T * value)415   PROTOBUF_ALWAYS_INLINE static Arena* GetArena(const T* value) {
416     return GetArenaInternal(value);
417   }
418 
419   template <typename T>
420   class InternalHelper {
421     template <typename U>
422     static char DestructorSkippable(const typename U::DestructorSkippable_*);
423     template <typename U>
424     static double DestructorSkippable(...);
425 
426     typedef std::integral_constant<
427         bool, sizeof(DestructorSkippable<T>(static_cast<const T*>(0))) ==
428                       sizeof(char) ||
429                   std::is_trivially_destructible<T>::value>
430         is_destructor_skippable;
431 
432     template <typename U>
433     static char ArenaConstructable(
434         const typename U::InternalArenaConstructable_*);
435     template <typename U>
436     static double ArenaConstructable(...);
437 
438     typedef std::integral_constant<bool, sizeof(ArenaConstructable<T>(
439                                              static_cast<const T*>(0))) ==
440                                              sizeof(char)>
441         is_arena_constructable;
442 
443     template <typename U,
444               typename std::enable_if<
445                   std::is_same<Arena*, decltype(std::declval<const U>()
446                                                     .GetArena())>::value,
447                   int>::type = 0>
448     static char HasGetArena(decltype(&U::GetArena));
449     template <typename U>
450     static double HasGetArena(...);
451 
452     typedef std::integral_constant<bool, sizeof(HasGetArena<T>(nullptr)) ==
453                                              sizeof(char)>
454         has_get_arena;
455 
456     template <typename... Args>
Construct(void * ptr,Args &&...args)457     static T* Construct(void* ptr, Args&&... args) {
458       return new (ptr) T(std::forward<Args>(args)...);
459     }
460 
GetArena(const T * p)461     static Arena* GetArena(const T* p) { return p->GetArenaNoVirtual(); }
462 
463     friend class Arena;
464   };
465 
466   // Helper typetraits that indicates support for arenas in a type T at compile
467   // time. This is public only to allow construction of higher-level templated
468   // utilities.
469   //
470   // is_arena_constructable<T>::value is true if the message type T has arena
471   // support enabled, and false otherwise.
472   //
473   // is_destructor_skippable<T>::value is true if the message type T has told
474   // the arena that it is safe to skip the destructor, and false otherwise.
475   //
476   // This is inside Arena because only Arena has the friend relationships
477   // necessary to see the underlying generated code traits.
478   template <typename T>
479   struct is_arena_constructable : InternalHelper<T>::is_arena_constructable {};
480   template <typename T>
481   struct is_destructor_skippable : InternalHelper<T>::is_destructor_skippable {
482   };
483 
484  private:
485   template <typename T>
486   struct has_get_arena : InternalHelper<T>::has_get_arena {};
487 
488   template <typename T, typename... Args>
CreateMessageInternal(Arena * arena,Args &&...args)489   PROTOBUF_ALWAYS_INLINE static T* CreateMessageInternal(Arena* arena,
490                                                          Args&&... args) {
491     static_assert(
492         InternalHelper<T>::is_arena_constructable::value,
493         "CreateMessage can only construct types that are ArenaConstructable");
494     if (arena == NULL) {
495       return new T(nullptr, std::forward<Args>(args)...);
496     } else {
497       return arena->DoCreateMessage<T>(std::forward<Args>(args)...);
498     }
499   }
500 
501   // This specialization for no arguments is necessary, because its behavior is
502   // slightly different.  When the arena pointer is nullptr, it calls T()
503   // instead of T(nullptr).
504   template <typename T>
CreateMessageInternal(Arena * arena)505   PROTOBUF_ALWAYS_INLINE static T* CreateMessageInternal(Arena* arena) {
506     static_assert(
507         InternalHelper<T>::is_arena_constructable::value,
508         "CreateMessage can only construct types that are ArenaConstructable");
509     if (arena == NULL) {
510       return new T();
511     } else {
512       return arena->DoCreateMessage<T>();
513     }
514   }
515 
516   template <typename T, typename... Args>
CreateInternal(Arena * arena,Args &&...args)517   PROTOBUF_ALWAYS_INLINE static T* CreateInternal(Arena* arena,
518                                                   Args&&... args) {
519     if (arena == NULL) {
520       return new T(std::forward<Args>(args)...);
521     } else {
522       return arena->DoCreate<T>(std::is_trivially_destructible<T>::value,
523                                 std::forward<Args>(args)...);
524     }
525   }
526 
527   void CallDestructorHooks();
528   void OnArenaAllocation(const std::type_info* allocated_type, size_t n) const;
AllocHook(const std::type_info * allocated_type,size_t n)529   inline void AllocHook(const std::type_info* allocated_type, size_t n) const {
530     if (PROTOBUF_PREDICT_FALSE(hooks_cookie_ != NULL)) {
531       OnArenaAllocation(allocated_type, n);
532     }
533   }
534 
535   // Allocate and also optionally call on_arena_allocation callback with the
536   // allocated type info when the hooks are in place in ArenaOptions and
537   // the cookie is not null.
538   template <typename T>
AllocateInternal(bool skip_explicit_ownership)539   PROTOBUF_ALWAYS_INLINE void* AllocateInternal(bool skip_explicit_ownership) {
540     const size_t n = internal::AlignUpTo8(sizeof(T));
541     AllocHook(RTTI_TYPE_ID(T), n);
542     // Monitor allocation if needed.
543     if (skip_explicit_ownership) {
544       return impl_.AllocateAligned(n);
545     } else {
546       return impl_.AllocateAlignedAndAddCleanup(
547           n, &internal::arena_destruct_object<T>);
548     }
549   }
550 
551   // CreateMessage<T> requires that T supports arenas, but this private method
552   // works whether or not T supports arenas. These are not exposed to user code
553   // as it can cause confusing API usages, and end up having double free in
554   // user code. These are used only internally from LazyField and Repeated
555   // fields, since they are designed to work in all mode combinations.
556   template <typename Msg, typename... Args>
DoCreateMaybeMessage(Arena * arena,std::true_type,Args &&...args)557   PROTOBUF_ALWAYS_INLINE static Msg* DoCreateMaybeMessage(Arena* arena,
558                                                           std::true_type,
559                                                           Args&&... args) {
560     return CreateMessageInternal<Msg>(arena, std::forward<Args>(args)...);
561   }
562 
563   template <typename T, typename... Args>
DoCreateMaybeMessage(Arena * arena,std::false_type,Args &&...args)564   PROTOBUF_ALWAYS_INLINE static T* DoCreateMaybeMessage(Arena* arena,
565                                                         std::false_type,
566                                                         Args&&... args) {
567     return CreateInternal<T>(arena, std::forward<Args>(args)...);
568   }
569 
570   template <typename T, typename... Args>
CreateMaybeMessage(Arena * arena,Args &&...args)571   PROTOBUF_ALWAYS_INLINE static T* CreateMaybeMessage(Arena* arena,
572                                                       Args&&... args) {
573     return DoCreateMaybeMessage<T>(arena, is_arena_constructable<T>(),
574                                    std::forward<Args>(args)...);
575   }
576 
577   template <typename T, typename... Args>
CreateNoMessage(Arena * arena,std::true_type,Args &&...args)578   PROTOBUF_ALWAYS_INLINE static T* CreateNoMessage(Arena* arena, std::true_type,
579                                                    Args&&... args) {
580     // User is constructing with Create() despite the fact that T supports arena
581     // construction.  In this case we have to delegate to CreateInternal(), and
582     // we can't use any CreateMaybeMessage() specialization that may be defined.
583     return CreateInternal<T>(arena, std::forward<Args>(args)...);
584   }
585 
586   template <typename T, typename... Args>
CreateNoMessage(Arena * arena,std::false_type,Args &&...args)587   PROTOBUF_ALWAYS_INLINE static T* CreateNoMessage(Arena* arena,
588                                                    std::false_type,
589                                                    Args&&... args) {
590     // User is constructing with Create() and the type does not support arena
591     // construction.  In this case we can delegate to CreateMaybeMessage() and
592     // use any specialization that may be available for that.
593     return CreateMaybeMessage<T>(arena, std::forward<Args>(args)...);
594   }
595 
596   // Just allocate the required size for the given type assuming the
597   // type has a trivial constructor.
598   template <typename T>
CreateInternalRawArray(size_t num_elements)599   PROTOBUF_ALWAYS_INLINE T* CreateInternalRawArray(size_t num_elements) {
600     GOOGLE_CHECK_LE(num_elements, std::numeric_limits<size_t>::max() / sizeof(T))
601         << "Requested size is too large to fit into size_t.";
602     const size_t n = internal::AlignUpTo8(sizeof(T) * num_elements);
603     // Monitor allocation if needed.
604     AllocHook(RTTI_TYPE_ID(T), n);
605     return static_cast<T*>(impl_.AllocateAligned(n));
606   }
607 
608   template <typename T, typename... Args>
DoCreate(bool skip_explicit_ownership,Args &&...args)609   PROTOBUF_ALWAYS_INLINE T* DoCreate(bool skip_explicit_ownership,
610                                      Args&&... args) {
611     return new (AllocateInternal<T>(skip_explicit_ownership))
612         T(std::forward<Args>(args)...);
613   }
614   template <typename T, typename... Args>
DoCreateMessage(Args &&...args)615   PROTOBUF_ALWAYS_INLINE T* DoCreateMessage(Args&&... args) {
616     return InternalHelper<T>::Construct(
617         AllocateInternal<T>(InternalHelper<T>::is_destructor_skippable::value),
618         this, std::forward<Args>(args)...);
619   }
620 
621   // CreateInArenaStorage is used to implement map field. Without it,
622   // Map need to call generated message's protected arena constructor,
623   // which needs to declare Map as friend of generated message.
624   template <typename T>
CreateInArenaStorage(T * ptr,Arena * arena)625   static void CreateInArenaStorage(T* ptr, Arena* arena) {
626     CreateInArenaStorageInternal(ptr, arena,
627                                  typename is_arena_constructable<T>::type());
628     RegisterDestructorInternal(
629         ptr, arena,
630         typename InternalHelper<T>::is_destructor_skippable::type());
631   }
632 
633   template <typename T>
CreateInArenaStorageInternal(T * ptr,Arena * arena,std::true_type)634   static void CreateInArenaStorageInternal(T* ptr, Arena* arena,
635                                            std::true_type) {
636     InternalHelper<T>::Construct(ptr, arena);
637   }
638   template <typename T>
CreateInArenaStorageInternal(T * ptr,Arena *,std::false_type)639   static void CreateInArenaStorageInternal(T* ptr, Arena* /* arena */,
640                                            std::false_type) {
641     new (ptr) T();
642   }
643 
644   template <typename T>
RegisterDestructorInternal(T *,Arena *,std::true_type)645   static void RegisterDestructorInternal(T* /* ptr */, Arena* /* arena */,
646                                          std::true_type) {}
647   template <typename T>
RegisterDestructorInternal(T * ptr,Arena * arena,std::false_type)648   static void RegisterDestructorInternal(T* ptr, Arena* arena,
649                                          std::false_type) {
650     arena->OwnDestructor(ptr);
651   }
652 
653   // These implement Own(), which registers an object for deletion (destructor
654   // call and operator delete()). The second parameter has type 'true_type' if T
655   // is a subtype of Message and 'false_type' otherwise. Collapsing
656   // all template instantiations to one for generic Message reduces code size,
657   // using the virtual destructor instead.
658   template <typename T>
OwnInternal(T * object,std::true_type)659   PROTOBUF_ALWAYS_INLINE void OwnInternal(T* object, std::true_type) {
660     if (object != NULL) {
661       impl_.AddCleanup(object, &internal::arena_delete_object<Message>);
662     }
663   }
664   template <typename T>
OwnInternal(T * object,std::false_type)665   PROTOBUF_ALWAYS_INLINE void OwnInternal(T* object, std::false_type) {
666     if (object != NULL) {
667       impl_.AddCleanup(object, &internal::arena_delete_object<T>);
668     }
669   }
670 
671   // Implementation for GetArena(). Only message objects with
672   // InternalArenaConstructable_ tags can be associated with an arena, and such
673   // objects must implement a GetArenaNoVirtual() method.
674   template <typename T, typename std::enable_if<
675                             is_arena_constructable<T>::value, int>::type = 0>
GetArenaInternal(const T * value)676   PROTOBUF_ALWAYS_INLINE static Arena* GetArenaInternal(const T* value) {
677     return InternalHelper<T>::GetArena(value);
678   }
679   template <typename T,
680             typename std::enable_if<!is_arena_constructable<T>::value &&
681                                         has_get_arena<T>::value,
682                                     int>::type = 0>
GetArenaInternal(const T * value)683   PROTOBUF_ALWAYS_INLINE static Arena* GetArenaInternal(const T* value) {
684     return value->GetArena();
685   }
686   template <typename T,
687             typename std::enable_if<!is_arena_constructable<T>::value &&
688                                         !has_get_arena<T>::value,
689                                     int>::type = 0>
GetArenaInternal(const T * value)690   PROTOBUF_ALWAYS_INLINE static Arena* GetArenaInternal(const T* value) {
691     (void) value;
692     return nullptr;
693   }
694 
695   // For friends of arena.
AllocateAligned(size_t n)696   void* AllocateAligned(size_t n) {
697     AllocHook(NULL, n);
698     return impl_.AllocateAligned(internal::AlignUpTo8(n));
699   }
700 
701   internal::ArenaImpl impl_;
702 
703   void (*on_arena_allocation_)(const std::type_info* allocated_type,
704                                uint64 alloc_size, void* cookie);
705   void (*on_arena_reset_)(Arena* arena, void* cookie, uint64 space_used);
706   void (*on_arena_destruction_)(Arena* arena, void* cookie, uint64 space_used);
707 
708   // The arena may save a cookie it receives from the external on_init hook
709   // and then use it when calling the on_reset and on_destruction hooks.
710   void* hooks_cookie_;
711 
712   template <typename Type>
713   friend class internal::GenericTypeHandler;
714   friend struct internal::ArenaStringPtr;  // For AllocateAligned.
715   friend class internal::LazyField;        // For CreateMaybeMessage.
716   friend class MessageLite;
717   template <typename Key, typename T>
718   friend class Map;
719 };
720 
721 // Defined above for supporting environments without RTTI.
722 #undef RTTI_TYPE_ID
723 
724 }  // namespace protobuf
725 }  // namespace google
726 
727 #include <google/protobuf/port_undef.inc>
728 
729 #endif  // GOOGLE_PROTOBUF_ARENA_H__
730