LCOV - code coverage report
Current view: top level - usr/include/google/protobuf - arena.h (source / functions) Hit Total Coverage
Test: ctest_coverage.info Lines: 6 29 20.7 %
Date: 2023-11-06 10:06:49 Functions: 0 45 0.0 %

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

Generated by: LCOV version 1.16