/src/LPM/external.protobuf/include/google/protobuf/arena.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Protocol Buffers - Google's data interchange format |
2 | | // Copyright 2008 Google Inc. All rights reserved. |
3 | | // |
4 | | // Use of this source code is governed by a BSD-style |
5 | | // license that can be found in the LICENSE file or at |
6 | | // https://developers.google.com/open-source/licenses/bsd |
7 | | |
8 | | // This file defines an Arena allocator for better allocation performance. |
9 | | |
10 | | #ifndef GOOGLE_PROTOBUF_ARENA_H__ |
11 | | #define GOOGLE_PROTOBUF_ARENA_H__ |
12 | | |
13 | | #include <cstddef> |
14 | | #include <cstdint> |
15 | | #include <limits> |
16 | | #include <new> // IWYU pragma: keep for operator new(). |
17 | | #include <string> |
18 | | #include <type_traits> |
19 | | #include <utility> |
20 | | #include <vector> |
21 | | #if defined(_MSC_VER) && !defined(_LIBCPP_STD_VER) && !_HAS_EXCEPTIONS |
22 | | // Work around bugs in MSVC <typeinfo> header when _HAS_EXCEPTIONS=0. |
23 | | #include <exception> |
24 | | #include <typeinfo> |
25 | | namespace std { |
26 | | using type_info = ::type_info; |
27 | | } |
28 | | #endif |
29 | | |
30 | | #include "absl/base/attributes.h" |
31 | | #include "google/protobuf/stubs/common.h" |
32 | | #include "absl/log/absl_check.h" |
33 | | #include "absl/utility/internal/if_constexpr.h" |
34 | | #include "google/protobuf/arena_align.h" |
35 | | #include "google/protobuf/arena_allocation_policy.h" |
36 | | #include "google/protobuf/port.h" |
37 | | #include "google/protobuf/serial_arena.h" |
38 | | #include "google/protobuf/thread_safe_arena.h" |
39 | | |
40 | | // Must be included last. |
41 | | #include "google/protobuf/port_def.inc" |
42 | | |
43 | | #ifdef SWIG |
44 | | #error "You cannot SWIG proto headers" |
45 | | #endif |
46 | | |
47 | | namespace google { |
48 | | namespace protobuf { |
49 | | |
50 | | struct ArenaOptions; // defined below |
51 | | class Arena; // defined below |
52 | | class Message; // defined in message.h |
53 | | class MessageLite; |
54 | | template <typename Key, typename T> |
55 | | class Map; |
56 | | namespace internal { |
57 | | struct RepeatedFieldBase; |
58 | | } // namespace internal |
59 | | |
60 | | namespace arena_metrics { |
61 | | |
62 | | void EnableArenaMetrics(ArenaOptions* options); |
63 | | |
64 | | } // namespace arena_metrics |
65 | | |
66 | | namespace TestUtil { |
67 | | class ReflectionTester; // defined in test_util.h |
68 | | } // namespace TestUtil |
69 | | |
70 | | namespace internal { |
71 | | |
72 | | struct ArenaTestPeer; // defined in arena_test_util.h |
73 | | class InternalMetadata; // defined in metadata_lite.h |
74 | | class LazyField; // defined in lazy_field.h |
75 | | class EpsCopyInputStream; // defined in parse_context.h |
76 | | class UntypedMapBase; // defined in map.h |
77 | | class RepeatedPtrFieldBase; // defined in repeated_ptr_field.h |
78 | | class TcParser; // defined in generated_message_tctable_impl.h |
79 | | |
80 | | template <typename Type> |
81 | | class GenericTypeHandler; // defined in repeated_field.h |
82 | | |
83 | | template <typename T> |
84 | 0 | void arena_delete_object(void* object) { |
85 | 0 | delete reinterpret_cast<T*>(object); |
86 | 0 | } |
87 | | } // namespace internal |
88 | | |
89 | | // ArenaOptions provides optional additional parameters to arena construction |
90 | | // that control its block-allocation behavior. |
91 | | struct ArenaOptions { |
92 | | // This defines the size of the first block requested from the system malloc. |
93 | | // Subsequent block sizes will increase in a geometric series up to a maximum. |
94 | | size_t start_block_size = internal::AllocationPolicy::kDefaultStartBlockSize; |
95 | | |
96 | | // This defines the maximum block size requested from system malloc (unless an |
97 | | // individual arena allocation request occurs with a size larger than this |
98 | | // maximum). Requested block sizes increase up to this value, then remain |
99 | | // here. |
100 | | size_t max_block_size = internal::AllocationPolicy::kDefaultMaxBlockSize; |
101 | | |
102 | | // An initial block of memory for the arena to use, or nullptr for none. If |
103 | | // provided, the block must live at least as long as the arena itself. The |
104 | | // creator of the Arena retains ownership of the block after the Arena is |
105 | | // destroyed. |
106 | | char* initial_block = nullptr; |
107 | | |
108 | | // The size of the initial block, if provided. |
109 | | size_t initial_block_size = 0; |
110 | | |
111 | | // A function pointer to an alloc method that returns memory blocks of size |
112 | | // requested. By default, it contains a ptr to the malloc function. |
113 | | // |
114 | | // NOTE: block_alloc and dealloc functions are expected to behave like |
115 | | // malloc and free, including Asan poisoning. |
116 | | void* (*block_alloc)(size_t) = nullptr; |
117 | | // A function pointer to a dealloc method that takes ownership of the blocks |
118 | | // from the arena. By default, it contains a ptr to a wrapper function that |
119 | | // calls free. |
120 | | void (*block_dealloc)(void*, size_t) = nullptr; |
121 | | |
122 | | private: |
123 | 0 | internal::AllocationPolicy AllocationPolicy() const { |
124 | 0 | internal::AllocationPolicy res; |
125 | 0 | res.start_block_size = start_block_size; |
126 | 0 | res.max_block_size = max_block_size; |
127 | 0 | res.block_alloc = block_alloc; |
128 | 0 | res.block_dealloc = block_dealloc; |
129 | 0 | return res; |
130 | 0 | } |
131 | | |
132 | | friend class Arena; |
133 | | friend class ArenaOptionsTestFriend; |
134 | | }; |
135 | | |
136 | | // Arena allocator. Arena allocation replaces ordinary (heap-based) allocation |
137 | | // with new/delete, and improves performance by aggregating allocations into |
138 | | // larger blocks and freeing allocations all at once. Protocol messages are |
139 | | // allocated on an arena by using Arena::Create<T>(Arena*), below, and are |
140 | | // automatically freed when the arena is destroyed. |
141 | | // |
142 | | // This is a thread-safe implementation: multiple threads may allocate from the |
143 | | // arena concurrently. Destruction is not thread-safe and the destructing |
144 | | // thread must synchronize with users of the arena first. |
145 | | class PROTOBUF_EXPORT PROTOBUF_ALIGNAS(8) Arena final { |
146 | | public: |
147 | | // Default constructor with sensible default options, tuned for average |
148 | | // use-cases. |
149 | 0 | inline Arena() : impl_() {} |
150 | | |
151 | | // Construct an arena with default options, except for the supplied |
152 | | // initial block. It is more efficient to use this constructor |
153 | | // instead of passing ArenaOptions if the only configuration needed |
154 | | // by the caller is supplying an initial block. |
155 | | inline Arena(char* initial_block, size_t initial_block_size) |
156 | 0 | : impl_(initial_block, initial_block_size) {} |
157 | | |
158 | | // Arena constructor taking custom options. See ArenaOptions above for |
159 | | // descriptions of the options available. |
160 | | explicit Arena(const ArenaOptions& options) |
161 | | : impl_(options.initial_block, options.initial_block_size, |
162 | 0 | options.AllocationPolicy()) {} |
163 | | |
164 | | // Block overhead. Use this as a guide for how much to over-allocate the |
165 | | // initial block if you want an allocation of size N to fit inside it. |
166 | | // |
167 | | // WARNING: if you allocate multiple objects, it is difficult to guarantee |
168 | | // that a series of allocations will fit in the initial block, especially if |
169 | | // Arena changes its alignment guarantees in the future! |
170 | | static const size_t kBlockOverhead = |
171 | | internal::ThreadSafeArena::kBlockHeaderSize + |
172 | | internal::ThreadSafeArena::kSerialArenaSize; |
173 | | |
174 | | inline ~Arena() = default; |
175 | | |
176 | | // Deprecated. Use Create<T> instead. TODO: depreate OSS version |
177 | | // once internal migration to Arena::Create is done. |
178 | | template <typename T, typename... Args> |
179 | | ABSL_DEPRECATED("Use Create") |
180 | | static T* CreateMessage(Arena* arena, Args&&... args) { |
181 | | using Type = std::remove_const_t<T>; |
182 | | static_assert( |
183 | | is_arena_constructable<Type>::value, |
184 | | "CreateMessage can only construct types that are ArenaConstructable"); |
185 | | return Create<Type>(arena, std::forward<Args>(args)...); |
186 | | } |
187 | | |
188 | | // Allocates an object type T if the arena passed in is not nullptr; |
189 | | // otherwise, returns a heap-allocated object. |
190 | | template <typename T, typename... Args> |
191 | 0 | PROTOBUF_NDEBUG_INLINE static T* Create(Arena* arena, Args&&... args) { |
192 | 0 | return absl::utility_internal::IfConstexprElse< |
193 | 0 | is_arena_constructable<T>::value>( |
194 | | // Arena-constructable |
195 | 0 | [arena](auto&&... args) { |
196 | 0 | using Type = std::remove_const_t<T>; |
197 | 0 | #ifdef __cpp_if_constexpr |
198 | | // DefaultConstruct/CopyConstruct are optimized for messages, which |
199 | | // are both arena constructible and destructor skippable and they |
200 | | // assume much. Don't use these functions unless the invariants |
201 | | // hold. |
202 | 0 | if constexpr (is_destructor_skippable<T>::value) { |
203 | 0 | constexpr auto construct_type = GetConstructType<T, Args&&...>(); |
204 | | // We delegate to DefaultConstruct/CopyConstruct where appropriate |
205 | | // because protobuf generated classes have external templates for |
206 | | // these functions for code size reasons. When `if constexpr` is not |
207 | | // available always use the fallback. |
208 | 0 | if constexpr (construct_type == ConstructType::kDefault) { |
209 | 0 | return static_cast<Type*>(DefaultConstruct<Type>(arena)); |
210 | 0 | } else if constexpr (construct_type == ConstructType::kCopy) { |
211 | 0 | return static_cast<Type*>(CopyConstruct<Type>(arena, &args...)); |
212 | 0 | } |
213 | 0 | } |
214 | 0 | #endif |
215 | 0 | return CreateArenaCompatible<Type>(arena, |
216 | 0 | std::forward<Args>(args)...); |
217 | 0 | }, |
218 | | // Non arena-constructable |
219 | 0 | [arena](auto&&... args) { |
220 | 0 | if (PROTOBUF_PREDICT_FALSE(arena == nullptr)) { |
221 | 0 | return new T(std::forward<Args>(args)...); |
222 | 0 | } |
223 | 0 | return new (arena->AllocateInternal<T>()) |
224 | 0 | T(std::forward<Args>(args)...); |
225 | 0 | }, Unexecuted instantiation: _ZZN6google8protobuf5Arena6CreateINS0_8internal16InternalMetadata9ContainerINSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEEEJEEEPT_PS1_DpOT0_ENKUlDpOT_E0_clIJEEEDaSM_ Unexecuted instantiation: _ZZN6google8protobuf5Arena6CreateINSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJEEEPT_PS1_DpOT0_ENKUlDpOT_E0_clIJEEEDaSI_ Unexecuted instantiation: _ZZN6google8protobuf5Arena6CreateINSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJS9_EEEPT_PS1_DpOT0_ENKUlDpOT_E0_clIJS9_EEEDaSI_ Unexecuted instantiation: _ZZN6google8protobuf5Arena6CreateINS0_8internal16InternalMetadata9ContainerINS0_15UnknownFieldSetEEEJEEEPT_PS1_DpOT0_ENKUlDpOT_E0_clIJEEEDaSG_ |
226 | 0 | std::forward<Args>(args)...); |
227 | 0 | } Unexecuted instantiation: google::protobuf::internal::InternalMetadata::Container<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >* google::protobuf::Arena::Create<google::protobuf::internal::InternalMetadata::Container<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >>(google::protobuf::Arena*) Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >* google::protobuf::Arena::Create<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >>(google::protobuf::Arena*) Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >* google::protobuf::Arena::Create<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(google::protobuf::Arena*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&) Unexecuted instantiation: google::protobuf::internal::ImplicitWeakMessage* google::protobuf::Arena::Create<google::protobuf::internal::ImplicitWeakMessage>(google::protobuf::Arena*) Unexecuted instantiation: google::protobuf::internal::InternalMetadata::Container<google::protobuf::UnknownFieldSet>* google::protobuf::Arena::Create<google::protobuf::internal::InternalMetadata::Container<google::protobuf::UnknownFieldSet>>(google::protobuf::Arena*) |
228 | | |
229 | | // API to delete any objects not on an arena. This can be used to safely |
230 | | // clean up messages or repeated fields without knowing whether or not they're |
231 | | // owned by an arena. The pointer passed to this function should not be used |
232 | | // again. |
233 | | template <typename T> |
234 | | PROTOBUF_ALWAYS_INLINE static void Destroy(T* obj) { |
235 | | if (InternalGetArena(obj) == nullptr) delete obj; |
236 | | } |
237 | | |
238 | | // Allocates memory with the specific size and alignment. |
239 | 0 | void* AllocateAligned(size_t size, size_t align = 8) { |
240 | 0 | if (align <= internal::ArenaAlignDefault::align) { |
241 | 0 | return Allocate(internal::ArenaAlignDefault::Ceil(size)); |
242 | 0 | } else { |
243 | | // We are wasting space by over allocating align - 8 bytes. Compared |
244 | | // to a dedicated function that takes current alignment in consideration. |
245 | | // Such a scheme would only waste (align - 8)/2 bytes on average, but |
246 | | // requires a dedicated function in the outline arena allocation |
247 | | // functions. Possibly re-evaluate tradeoffs later. |
248 | 0 | auto align_as = internal::ArenaAlignAs(align); |
249 | 0 | return align_as.Ceil(Allocate(align_as.Padded(size))); |
250 | 0 | } |
251 | 0 | } |
252 | | |
253 | | // Create an array of object type T on the arena *without* invoking the |
254 | | // constructor of T. If `arena` is null, then the return value should be freed |
255 | | // with `delete[] x;` (or `::operator delete[](x);`). |
256 | | // To ensure safe uses, this function checks at compile time |
257 | | // (when compiled as C++11) that T is trivially default-constructible and |
258 | | // trivially destructible. |
259 | | template <typename T> |
260 | | PROTOBUF_NDEBUG_INLINE static T* CreateArray(Arena* arena, |
261 | 0 | size_t num_elements) { |
262 | 0 | static_assert(std::is_trivial<T>::value, |
263 | 0 | "CreateArray requires a trivially constructible type"); |
264 | 0 | static_assert(std::is_trivially_destructible<T>::value, |
265 | 0 | "CreateArray requires a trivially destructible type"); |
266 | 0 | ABSL_CHECK_LE(num_elements, std::numeric_limits<size_t>::max() / sizeof(T)) |
267 | 0 | << "Requested size is too large to fit into size_t."; |
268 | 0 | if (PROTOBUF_PREDICT_FALSE(arena == nullptr)) { |
269 | 0 | return new T[num_elements]; |
270 | 0 | } else { |
271 | 0 | // We count on compiler to realize that if sizeof(T) is a multiple of |
272 | 0 | // 8 AlignUpTo can be elided. |
273 | 0 | return static_cast<T*>( |
274 | 0 | arena->AllocateAlignedForArray(sizeof(T) * num_elements, alignof(T))); |
275 | 0 | } |
276 | 0 | } Unexecuted instantiation: char* google::protobuf::Arena::CreateArray<char>(google::protobuf::Arena*, unsigned long) Unexecuted instantiation: unsigned char* google::protobuf::Arena::CreateArray<unsigned char>(google::protobuf::Arena*, unsigned long) |
277 | | |
278 | | // The following are routines are for monitoring. They will approximate the |
279 | | // total sum allocated and used memory, but the exact value is an |
280 | | // implementation deal. For instance allocated space depends on growth |
281 | | // policies. Do not use these in unit tests. |
282 | | // Returns the total space allocated by the arena, which is the sum of the |
283 | | // sizes of the underlying blocks. |
284 | 0 | uint64_t SpaceAllocated() const { return impl_.SpaceAllocated(); } |
285 | | // Returns the total space used by the arena. Similar to SpaceAllocated but |
286 | | // does not include free space and block overhead. This is a best-effort |
287 | | // estimate and may inaccurately calculate space used by other threads |
288 | | // executing concurrently with the call to this method. These inaccuracies |
289 | | // are due to race conditions, and are bounded but unpredictable. Stale data |
290 | | // can lead to underestimates of the space used, and race conditions can lead |
291 | | // to overestimates (up to the current block size). |
292 | 0 | uint64_t SpaceUsed() const { return impl_.SpaceUsed(); } |
293 | | |
294 | | // Frees all storage allocated by this arena after calling destructors |
295 | | // registered with OwnDestructor() and freeing objects registered with Own(). |
296 | | // Any objects allocated on this arena are unusable after this call. It also |
297 | | // returns the total space used by the arena which is the sums of the sizes |
298 | | // of the allocated blocks. This method is not thread-safe. |
299 | 0 | uint64_t Reset() { return impl_.Reset(); } |
300 | | |
301 | | // Adds |object| to a list of heap-allocated objects to be freed with |delete| |
302 | | // when the arena is destroyed or reset. |
303 | | template <typename T> |
304 | 0 | PROTOBUF_ALWAYS_INLINE void Own(T* object) { |
305 | 0 | // Collapsing all template instantiations to one for generic Message reduces |
306 | 0 | // code size, using the virtual destructor instead. |
307 | 0 | using TypeToUse = |
308 | 0 | std::conditional_t<std::is_convertible<T*, MessageLite*>::value, |
309 | 0 | MessageLite, T>; |
310 | 0 | if (object != nullptr) { |
311 | 0 | impl_.AddCleanup(static_cast<TypeToUse*>(object), |
312 | 0 | &internal::arena_delete_object<TypeToUse>); |
313 | 0 | } |
314 | 0 | } |
315 | | |
316 | | // Adds |object| to a list of objects whose destructors will be manually |
317 | | // called when the arena is destroyed or reset. This differs from Own() in |
318 | | // that it does not free the underlying memory with |delete|; hence, it is |
319 | | // normally only used for objects that are placement-newed into |
320 | | // arena-allocated memory. |
321 | | template <typename T> |
322 | | PROTOBUF_ALWAYS_INLINE void OwnDestructor(T* object) { |
323 | | if (object != nullptr) { |
324 | | impl_.AddCleanup(object, &internal::cleanup::arena_destruct_object<T>); |
325 | | } |
326 | | } |
327 | | |
328 | | // Adds a custom member function on an object to the list of destructors that |
329 | | // will be manually called when the arena is destroyed or reset. This differs |
330 | | // from OwnDestructor() in that any member function may be specified, not only |
331 | | // the class destructor. |
332 | | PROTOBUF_ALWAYS_INLINE void OwnCustomDestructor(void* object, |
333 | 0 | void (*destruct)(void*)) { |
334 | 0 | impl_.AddCleanup(object, destruct); |
335 | 0 | } |
336 | | |
337 | | // Retrieves the arena associated with |value| if |value| is an arena-capable |
338 | | // message, or nullptr otherwise. If possible, the call resolves at compile |
339 | | // time. Note that we can often devirtualize calls to `value->GetArena()` so |
340 | | // usually calling this method is unnecessary. |
341 | | // TODO: remove this function. |
342 | | template <typename T> |
343 | | ABSL_DEPRECATED( |
344 | | "This will be removed in a future release. Call value->GetArena() " |
345 | | "instead.") |
346 | | PROTOBUF_ALWAYS_INLINE static Arena* GetArena(T* value) { |
347 | | return GetArenaInternal(value); |
348 | | } |
349 | | |
350 | | template <typename T> |
351 | | class InternalHelper { |
352 | | private: |
353 | | // A SFINAE friendly trait that probes for `U` but always evalues to |
354 | | // `Arena*`. |
355 | | template <typename U> |
356 | | using EnableIfArena = |
357 | | typename std::enable_if<std::is_same<Arena*, U>::value, Arena*>::type; |
358 | | |
359 | | // Use go/ranked-overloads for dispatching. |
360 | | struct Rank0 {}; |
361 | | struct Rank1 : Rank0 {}; |
362 | | |
363 | | static void InternalSwap(T* a, T* b) { a->InternalSwap(b); } |
364 | | |
365 | | static Arena* GetArena(T* p) { return GetArena(Rank1{}, p); } |
366 | | |
367 | | template <typename U> |
368 | | static auto GetArena(Rank1, |
369 | | U* p) -> EnableIfArena<decltype(p->GetArena())> { |
370 | | return p->GetArena(); |
371 | | } |
372 | | |
373 | | template <typename U> |
374 | | static Arena* GetArena(Rank0, U*) { |
375 | | return nullptr; |
376 | | } |
377 | | |
378 | | // If an object type T satisfies the appropriate protocol, it is deemed |
379 | | // "arena compatible" and handled more efficiently because this interface |
380 | | // (i) passes the arena pointer to the created object so that its |
381 | | // sub-objects and internal allocations can use the arena too, and (ii) |
382 | | // elides the object's destructor call when possible; e.g. protobuf |
383 | | // messages, RepeatedField, etc. Otherwise, the arena will invoke the |
384 | | // object's destructor when the arena is destroyed. |
385 | | // |
386 | | // To be "arena-compatible", a type T must satisfy the following: |
387 | | // |
388 | | // - The type T must have (at least) two constructors: a constructor |
389 | | // callable with `args` (without `arena`), called when a T is allocated on |
390 | | // the heap; and a constructor callable with `Arena* arena, Args&&... |
391 | | // args`, called when a T is allocated on an arena. If the second |
392 | | // constructor is called with a null arena pointer, it must be equivalent |
393 | | // to invoking the first |
394 | | // (`args`-only) constructor. |
395 | | // |
396 | | // - The type T must have a particular type trait: a nested type |
397 | | // |InternalArenaConstructable_|. This is usually a typedef to |void|. |
398 | | // |
399 | | // - The type T *may* have the type trait |DestructorSkippable_|. If this |
400 | | // type trait is present in the type, then its destructor will not be |
401 | | // called if and only if it was passed a non-null arena pointer. If this |
402 | | // type trait is not present on the type, then its destructor is always |
403 | | // called when the containing arena is destroyed. |
404 | | // |
405 | | // The protocol is implemented by all protobuf message classes as well as |
406 | | // protobuf container types like RepeatedPtrField and Map. It is internal to |
407 | | // protobuf and is not guaranteed to be stable. Non-proto types should not |
408 | | // rely on this protocol. |
409 | | template <typename U> |
410 | | static char DestructorSkippable(const typename U::DestructorSkippable_*); |
411 | | template <typename U> |
412 | | static double DestructorSkippable(...); |
413 | | |
414 | | typedef std::integral_constant< |
415 | | bool, sizeof(DestructorSkippable<T>(static_cast<const T*>(0))) == |
416 | | sizeof(char) || |
417 | | std::is_trivially_destructible<T>::value> |
418 | | is_destructor_skippable; |
419 | | |
420 | | template <typename U> |
421 | | static char ArenaConstructable( |
422 | | const typename U::InternalArenaConstructable_*); |
423 | | template <typename U> |
424 | | static double ArenaConstructable(...); |
425 | | |
426 | | typedef std::integral_constant<bool, sizeof(ArenaConstructable<T>( |
427 | | static_cast<const T*>(0))) == |
428 | | sizeof(char)> |
429 | | is_arena_constructable; |
430 | | |
431 | | |
432 | | template <typename... Args> |
433 | 0 | static T* Construct(void* ptr, Args&&... args) { |
434 | 0 | return new (ptr) T(static_cast<Args&&>(args)...); |
435 | 0 | } |
436 | | |
437 | 0 | static inline PROTOBUF_ALWAYS_INLINE T* New() { |
438 | 0 | return new T(nullptr); |
439 | 0 | } |
440 | | |
441 | | friend class Arena; |
442 | | friend class TestUtil::ReflectionTester; |
443 | | }; |
444 | | |
445 | | // Provides access to protected GetArena to generated messages. |
446 | | // For internal use only. |
447 | | template <typename T> |
448 | | static Arena* InternalGetArena(T* p) { |
449 | | return InternalHelper<T>::GetArena(p); |
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 | | internal::ThreadSafeArena impl_; |
472 | | |
473 | | enum class ConstructType { kUnknown, kDefault, kCopy, kMove }; |
474 | | // Overload set to detect which kind of construction is going to happen for a |
475 | | // specific set of input arguments. This is used to dispatch to different |
476 | | // helper functions. |
477 | | template <typename T> |
478 | | static auto ProbeConstructType() |
479 | | -> std::integral_constant<ConstructType, ConstructType::kDefault>; |
480 | | template <typename T> |
481 | | static auto ProbeConstructType(const T&) |
482 | | -> std::integral_constant<ConstructType, ConstructType::kCopy>; |
483 | | template <typename T> |
484 | | static auto ProbeConstructType(T&) |
485 | | -> std::integral_constant<ConstructType, ConstructType::kCopy>; |
486 | | template <typename T> |
487 | | static auto ProbeConstructType(const T&&) |
488 | | -> std::integral_constant<ConstructType, ConstructType::kCopy>; |
489 | | template <typename T> |
490 | | static auto ProbeConstructType(T&&) |
491 | | -> std::integral_constant<ConstructType, ConstructType::kMove>; |
492 | | template <typename T, typename... U> |
493 | | static auto ProbeConstructType(U&&...) |
494 | | -> std::integral_constant<ConstructType, ConstructType::kUnknown>; |
495 | | |
496 | | template <typename T, typename... Args> |
497 | | static constexpr auto GetConstructType() { |
498 | | return std::is_base_of<MessageLite, T>::value |
499 | | ? decltype(ProbeConstructType<T>(std::declval<Args>()...))::value |
500 | | : ConstructType::kUnknown; |
501 | | } |
502 | | |
503 | 0 | void ReturnArrayMemory(void* p, size_t size) { |
504 | 0 | impl_.ReturnArrayMemory(p, size); |
505 | 0 | } |
506 | | |
507 | | template <typename T, typename... Args> |
508 | | PROTOBUF_NDEBUG_INLINE static T* CreateArenaCompatible(Arena* arena, |
509 | | Args&&... args) { |
510 | | static_assert(is_arena_constructable<T>::value, |
511 | | "Can only construct types that are ArenaConstructable"); |
512 | | if (PROTOBUF_PREDICT_FALSE(arena == nullptr)) { |
513 | | return new T(nullptr, static_cast<Args&&>(args)...); |
514 | | } else { |
515 | | return arena->DoCreateMessage<T>(static_cast<Args&&>(args)...); |
516 | | } |
517 | | } |
518 | | |
519 | | // This specialization for no arguments is necessary, because its behavior is |
520 | | // slightly different. When the arena pointer is nullptr, it calls T() |
521 | | // instead of T(nullptr). |
522 | | template <typename T> |
523 | 0 | PROTOBUF_NDEBUG_INLINE static T* CreateArenaCompatible(Arena* arena) { |
524 | 0 | static_assert(is_arena_constructable<T>::value, |
525 | 0 | "Can only construct types that are ArenaConstructable"); |
526 | 0 | if (PROTOBUF_PREDICT_FALSE(arena == nullptr)) { |
527 | 0 | // Generated arena constructor T(Arena*) is protected. Call via |
528 | 0 | // InternalHelper. |
529 | 0 | return InternalHelper<T>::New(); |
530 | 0 | } else { |
531 | 0 | return arena->DoCreateMessage<T>(); |
532 | 0 | } |
533 | 0 | } |
534 | | |
535 | | template <typename T, bool trivial = std::is_trivially_destructible<T>::value> |
536 | 0 | PROTOBUF_NDEBUG_INLINE void* AllocateInternal() { |
537 | 0 | if (trivial) { |
538 | 0 | return AllocateAligned(sizeof(T), alignof(T)); |
539 | 0 | } else { |
540 | | // We avoid instantiating arena_destruct_object<T> in the trivial case. |
541 | 0 | constexpr auto dtor = &internal::cleanup::arena_destruct_object< |
542 | 0 | std::conditional_t<trivial, std::string, T>>; |
543 | 0 | return AllocateAlignedWithCleanup(sizeof(T), alignof(T), dtor); |
544 | 0 | } |
545 | 0 | } Unexecuted instantiation: void* google::protobuf::Arena::AllocateInternal<google::protobuf::internal::InternalMetadata::Container<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, false>() Unexecuted instantiation: void* google::protobuf::Arena::AllocateInternal<google::protobuf::internal::ImplicitWeakMessage, false>() Unexecuted instantiation: void* google::protobuf::Arena::AllocateInternal<google::protobuf::internal::InternalMetadata::Container<google::protobuf::UnknownFieldSet>, false>() |
546 | | |
547 | | // DefaultConstruct/CopyConstruct: |
548 | | // |
549 | | // Functions with a generic signature to support taking the address in generic |
550 | | // contexts, like RepeatedPtrField, etc. |
551 | | // These are also used as a hook for `extern template` instantiations where |
552 | | // codegen can offload the instantiations to the respective .pb.cc files. This |
553 | | // has two benefits: |
554 | | // - It reduces the library bloat as callers don't have to instantiate the |
555 | | // function. |
556 | | // - It allows the optimizer to see the constructors called to |
557 | | // further optimize the instantiation. |
558 | | template <typename T> |
559 | | static void* DefaultConstruct(Arena* arena); |
560 | | template <typename T> |
561 | | static void* CopyConstruct(Arena* arena, const void* from); |
562 | | |
563 | | template <typename T, typename... Args> |
564 | 0 | PROTOBUF_NDEBUG_INLINE T* DoCreateMessage(Args&&... args) { |
565 | 0 | return InternalHelper<T>::Construct( |
566 | 0 | AllocateInternal<T, is_destructor_skippable<T>::value>(), this, |
567 | 0 | std::forward<Args>(args)...); |
568 | 0 | } |
569 | | |
570 | | // CreateInArenaStorage is used to implement map field. Without it, |
571 | | // Map need to call generated message's protected arena constructor, |
572 | | // which needs to declare Map as friend of generated message. |
573 | | template <typename T, typename... Args> |
574 | | static void CreateInArenaStorage(T* ptr, Arena* arena, Args&&... args) { |
575 | | CreateInArenaStorageInternal(ptr, arena, is_arena_constructable<T>(), |
576 | | std::forward<Args>(args)...); |
577 | | if (PROTOBUF_PREDICT_TRUE(arena != nullptr)) { |
578 | | RegisterDestructorInternal(ptr, arena, is_destructor_skippable<T>()); |
579 | | } |
580 | | } |
581 | | |
582 | | template <typename T, typename... Args> |
583 | | static void CreateInArenaStorageInternal(T* ptr, Arena* arena, |
584 | | std::true_type, Args&&... args) { |
585 | | InternalHelper<T>::Construct(ptr, arena, std::forward<Args>(args)...); |
586 | | } |
587 | | template <typename T, typename... Args> |
588 | | static void CreateInArenaStorageInternal(T* ptr, Arena* /* arena */, |
589 | | std::false_type, Args&&... args) { |
590 | | new (ptr) T(std::forward<Args>(args)...); |
591 | | } |
592 | | |
593 | | template <typename T> |
594 | | static void RegisterDestructorInternal(T* /* ptr */, Arena* /* arena */, |
595 | | std::true_type) {} |
596 | | template <typename T> |
597 | | static void RegisterDestructorInternal(T* ptr, Arena* arena, |
598 | | std::false_type) { |
599 | | arena->OwnDestructor(ptr); |
600 | | } |
601 | | |
602 | | // Implementation for GetArena(). Only message objects with |
603 | | // InternalArenaConstructable_ tags can be associated with an arena, and such |
604 | | // objects must implement a GetArena() method. |
605 | | template <typename T> |
606 | | PROTOBUF_ALWAYS_INLINE static Arena* GetArenaInternal(T* value) { |
607 | | return InternalHelper<T>::GetArena(value); |
608 | | } |
609 | | |
610 | 0 | void* AllocateAlignedForArray(size_t n, size_t align) { |
611 | 0 | if (align <= internal::ArenaAlignDefault::align) { |
612 | 0 | return AllocateForArray(internal::ArenaAlignDefault::Ceil(n)); |
613 | 0 | } else { |
614 | 0 | // We are wasting space by over allocating align - 8 bytes. Compared |
615 | 0 | // to a dedicated function that takes current alignment in consideration. |
616 | 0 | // Such a scheme would only waste (align - 8)/2 bytes on average, but |
617 | 0 | // requires a dedicated function in the outline arena allocation |
618 | 0 | // functions. Possibly re-evaluate tradeoffs later. |
619 | 0 | auto align_as = internal::ArenaAlignAs(align); |
620 | 0 | return align_as.Ceil(AllocateForArray(align_as.Padded(n))); |
621 | 0 | } |
622 | 0 | } |
623 | | |
624 | | void* Allocate(size_t n); |
625 | | void* AllocateForArray(size_t n); |
626 | | void* AllocateAlignedWithCleanup(size_t n, size_t align, |
627 | | void (*destructor)(void*)); |
628 | | |
629 | | // Test only API. |
630 | | // It returns the objects that are in the cleanup list for the current |
631 | | // SerialArena. This API is meant for tests that want to see if something was |
632 | | // added or not to the cleanup list. Sometimes adding something to the cleanup |
633 | | // list has no visible side effect so peeking into the list is the only way to |
634 | | // test. |
635 | | std::vector<void*> PeekCleanupListForTesting(); |
636 | | |
637 | | template <typename Type> |
638 | | friend class internal::GenericTypeHandler; |
639 | | friend class internal::InternalMetadata; // For user_arena(). |
640 | | friend class internal::LazyField; // For DefaultConstruct. |
641 | | friend class internal::EpsCopyInputStream; // For parser performance |
642 | | friend class internal::TcParser; // For parser performance |
643 | | friend class MessageLite; |
644 | | template <typename Key, typename T> |
645 | | friend class Map; |
646 | | template <typename> |
647 | | friend class RepeatedField; // For ReturnArrayMemory |
648 | | friend class internal::RepeatedPtrFieldBase; // For ReturnArrayMemory |
649 | | friend class internal::UntypedMapBase; // For ReturnArenaMemory |
650 | | |
651 | | friend struct internal::ArenaTestPeer; |
652 | | }; |
653 | | |
654 | | // DefaultConstruct/CopyConstruct |
655 | | // |
656 | | // IMPORTANT: These have to be defined out of line and without an `inline` |
657 | | // keyword to make sure the `extern template` suppresses instantiations. |
658 | | template <typename T> |
659 | 1.56M | PROTOBUF_NOINLINE void* Arena::DefaultConstruct(Arena* arena) { |
660 | 1.56M | static_assert(is_destructor_skippable<T>::value, ""); |
661 | 1.56M | void* mem = arena != nullptr ? arena->AllocateAligned(sizeof(T)) |
662 | 1.56M | : ::operator new(sizeof(T)); |
663 | 1.56M | return new (mem) T(arena); |
664 | 1.56M | } void* google::protobuf::Arena::DefaultConstruct<DBOperation>(google::protobuf::Arena*) Line | Count | Source | 659 | 1.56M | PROTOBUF_NOINLINE void* Arena::DefaultConstruct(Arena* arena) { | 660 | 1.56M | static_assert(is_destructor_skippable<T>::value, ""); | 661 | 1.56M | void* mem = arena != nullptr ? arena->AllocateAligned(sizeof(T)) | 662 | 1.56M | : ::operator new(sizeof(T)); | 663 | 1.56M | return new (mem) T(arena); | 664 | 1.56M | } |
Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<DBOperations>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::Any>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::UninterpretedOption_NamePart>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::SourceCodeInfo_Location>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::GeneratedCodeInfo_Annotation>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::FieldOptions_FeatureSupport>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::FieldOptions_EditionDefault>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::FeatureSet>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::ExtensionRangeOptions_Declaration>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::EnumDescriptorProto_EnumReservedRange>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::DescriptorProto_ReservedRange>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::UninterpretedOption>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::SourceCodeInfo>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::GeneratedCodeInfo>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::FeatureSetDefaults_FeatureSetEditionDefault>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::ServiceOptions>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::OneofOptions>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::MethodOptions>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::MessageOptions>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::FileOptions>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::FieldOptions>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::FeatureSetDefaults>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::ExtensionRangeOptions>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::EnumValueOptions>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::EnumOptions>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::OneofDescriptorProto>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::MethodDescriptorProto>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::FieldDescriptorProto>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::EnumValueDescriptorProto>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::DescriptorProto_ExtensionRange>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::ServiceDescriptorProto>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::EnumDescriptorProto>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::DescriptorProto>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::FileDescriptorProto>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::FileDescriptorSet>(google::protobuf::Arena*) |
665 | | |
666 | | template <typename T> |
667 | 0 | PROTOBUF_NOINLINE void* Arena::CopyConstruct(Arena* arena, const void* from) { |
668 | 0 | static_assert(is_destructor_skippable<T>::value, ""); |
669 | 0 | void* mem = arena != nullptr ? arena->AllocateAligned(sizeof(T)) |
670 | 0 | : ::operator new(sizeof(T)); |
671 | 0 | return new (mem) T(arena, *static_cast<const T*>(from)); |
672 | 0 | } |
673 | | |
674 | | template <> |
675 | 0 | inline void* Arena::AllocateInternal<std::string, false>() { |
676 | 0 | return impl_.AllocateFromStringBlock(); |
677 | 0 | } |
678 | | |
679 | | } // namespace protobuf |
680 | | } // namespace google |
681 | | |
682 | | #include "google/protobuf/port_undef.inc" |
683 | | |
684 | | #endif // GOOGLE_PROTOBUF_ARENA_H__ |