33 #ifndef GOOGLE_PROTOBUF_ARENA_H__
34 #define GOOGLE_PROTOBUF_ARENA_H__
38 #include <type_traits>
43 #if defined(_MSC_VER) && !defined(_LIBCPP_STD_VER) && !_HAS_EXCEPTIONS
48 using type_info = ::type_info;
54 #include <type_traits>
55 #include <google/protobuf/arena_impl.h>
56 #include <google/protobuf/port.h>
58 #include <google/protobuf/port_def.inc>
61 #error "You cannot SWIG proto headers"
78 template <
typename Key,
typename T>
81 namespace arena_metrics {
89 struct ArenaStringPtr;
91 class EpsCopyInputStream;
93 template <
typename Type>
99 reinterpret_cast<T*
>(object)->~T();
101 template <
typename T>
103 delete reinterpret_cast<T*
>(object);
106 #if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation)
107 ::operator
delete(object, size);
110 ::operator
delete(object);
143 void* (*block_alloc)(size_t);
157 on_arena_reset(NULL),
158 on_arena_destruction(NULL),
159 on_arena_allocation(NULL) {}
172 void* (*on_arena_init)(
Arena* arena);
173 void (*on_arena_reset)(
Arena* arena,
void* cookie,
uint64 space_used);
174 void (*on_arena_destruction)(
Arena* arena,
void* cookie,
uint64 space_used);
181 void (*on_arena_allocation)(
const std::type_info* allocated_type,
182 uint64 alloc_size,
void* cookie);
186 static const size_t kDefaultStartBlockSize = 256;
187 static const size_t kDefaultMaxBlockSize = 8192;
197 #define RTTI_TYPE_ID(type) (&typeid(type))
199 #define RTTI_TYPE_ID(type) (NULL)
251 explicit Arena(
const ArenaOptions& options) : impl_(options) {
261 static const size_t kBlockOverhead = internal::ArenaImpl::kBlockHeaderSize +
262 internal::ArenaImpl::kSerialArenaSize;
266 Arena() : impl_(ArenaOptions()) { Init(ArenaOptions()); }
270 CallDestructorHooks();
274 void Init(
const ArenaOptions& options) {
275 on_arena_allocation_ = options.on_arena_allocation;
276 on_arena_reset_ = options.on_arena_reset;
277 on_arena_destruction_ = options.on_arena_destruction;
279 if (options.on_arena_init != NULL) {
280 hooks_cookie_ = options.on_arena_init(
this);
282 hooks_cookie_ = NULL;
296 template <
typename T,
typename... Args>
297 PROTOBUF_ALWAYS_INLINE
static T* CreateMessage(Arena* arena, Args&&... args) {
299 InternalHelper<T>::is_arena_constructable::value,
300 "CreateMessage can only construct types that are ArenaConstructable");
304 return Arena::CreateMaybeMessage<T>(arena, std::forward<Args>(args)...);
322 template <
typename T,
typename... Args>
323 PROTOBUF_ALWAYS_INLINE
static T* Create(Arena* arena, Args&&... args) {
324 return CreateNoMessage<T>(arena, is_arena_constructable<T>(),
325 std::forward<Args>(args)...);
334 template <
typename T>
335 PROTOBUF_ALWAYS_INLINE
static T* CreateArray(Arena* arena,
336 size_t num_elements) {
337 static_assert(std::is_pod<T>::value,
338 "CreateArray requires a trivially constructible type");
339 static_assert(std::is_trivially_destructible<T>::value,
340 "CreateArray requires a trivially destructible type");
341 GOOGLE_CHECK_LE(num_elements, std::numeric_limits<size_t>::max() /
sizeof(T))
342 <<
"Requested size is too large to fit into size_t.";
344 return static_cast<T*
>(::operator
new[](num_elements *
sizeof(T)));
346 return arena->CreateInternalRawArray<T>(num_elements);
353 uint64 SpaceAllocated()
const {
return impl_.SpaceAllocated(); }
358 uint64 SpaceUsed()
const {
return impl_.SpaceUsed(); }
365 PROTOBUF_NOINLINE
uint64 Reset() {
367 if (on_arena_reset_ != NULL) {
368 on_arena_reset_(
this, hooks_cookie_, impl_.SpaceAllocated());
370 return impl_.Reset();
375 template <
typename T>
376 PROTOBUF_NOINLINE
void Own(T*
object) {
377 OwnInternal(
object, std::is_convertible<T*, Message*>());
385 template <
typename T>
386 PROTOBUF_NOINLINE
void OwnDestructor(T*
object) {
387 if (
object != NULL) {
388 impl_.AddCleanup(
object, &internal::arena_destruct_object<T>);
396 PROTOBUF_NOINLINE
void OwnCustomDestructor(
void*
object,
397 void (*destruct)(
void*)) {
398 impl_.AddCleanup(
object, destruct);
405 template <
typename T>
406 PROTOBUF_ALWAYS_INLINE
static Arena* GetArena(
const T* value) {
407 return GetArenaInternal(value);
410 template <
typename T>
411 class InternalHelper {
412 template <
typename U>
413 static char DestructorSkippable(
const typename U::DestructorSkippable_*);
414 template <
typename U>
415 static double DestructorSkippable(...);
417 typedef std::integral_constant<
418 bool,
sizeof(DestructorSkippable<T>(
static_cast<const T*
>(0))) ==
420 std::is_trivially_destructible<T>::value>
421 is_destructor_skippable;
423 template <
typename U>
424 static char ArenaConstructable(
425 const typename U::InternalArenaConstructable_*);
426 template <
typename U>
427 static double ArenaConstructable(...);
429 typedef std::integral_constant<bool, sizeof(ArenaConstructable<T>(
430 static_cast<const T*
>(0))) ==
432 is_arena_constructable;
434 template <
typename U,
435 typename std::enable_if<
436 std::is_same<Arena*, decltype(std::declval<const U>()
437 .GetArena())>::value,
439 static char HasGetArena(decltype(&U::GetArena));
440 template <
typename U>
441 static double HasGetArena(...);
443 typedef std::integral_constant<bool, sizeof(HasGetArena<T>(
nullptr)) ==
447 template <
typename... Args>
448 static T* Construct(
void* ptr, Args&&... args) {
449 return new (ptr) T(std::forward<Args>(args)...);
452 static Arena* GetArena(
const T* p) {
return p->GetArena(); }
469 template <
typename T>
470 struct is_arena_constructable : InternalHelper<T>::is_arena_constructable {};
471 template <
typename T>
472 struct is_destructor_skippable : InternalHelper<T>::is_destructor_skippable {
476 template <
typename T>
477 struct has_get_arena : InternalHelper<T>::has_get_arena {};
479 template <
typename T,
typename... Args>
480 PROTOBUF_ALWAYS_INLINE
static T* CreateMessageInternal(Arena* arena,
483 InternalHelper<T>::is_arena_constructable::value,
484 "CreateMessage can only construct types that are ArenaConstructable");
486 return new T(
nullptr, std::forward<Args>(args)...);
488 return arena->DoCreateMessage<T>(std::forward<Args>(args)...);
495 template <
typename T>
496 PROTOBUF_ALWAYS_INLINE
static T* CreateMessageInternal(Arena* arena) {
498 InternalHelper<T>::is_arena_constructable::value,
499 "CreateMessage can only construct types that are ArenaConstructable");
503 return arena->DoCreateMessage<T>();
507 template <
typename T,
typename... Args>
508 PROTOBUF_ALWAYS_INLINE
static T* CreateInternal(Arena* arena,
511 return new T(std::forward<Args>(args)...);
513 return arena->DoCreate<T>(std::is_trivially_destructible<T>::value,
514 std::forward<Args>(args)...);
518 void CallDestructorHooks();
519 void OnArenaAllocation(
const std::type_info* allocated_type,
size_t n)
const;
520 inline void AllocHook(
const std::type_info* allocated_type,
size_t n)
const {
521 if (PROTOBUF_PREDICT_FALSE(hooks_cookie_ != NULL)) {
522 OnArenaAllocation(allocated_type, n);
529 template <
typename T>
530 PROTOBUF_ALWAYS_INLINE
void* AllocateInternal(
bool skip_explicit_ownership) {
531 static_assert(
alignof(T) <= 8,
"T is overaligned, see b/151247138");
532 const size_t n = internal::AlignUpTo8(
sizeof(T));
535 if (skip_explicit_ownership) {
536 return AllocateAlignedNoHook(n);
538 return impl_.AllocateAlignedAndAddCleanup(
539 n, &internal::arena_destruct_object<T>);
548 template <
typename Msg,
typename... Args>
549 PROTOBUF_ALWAYS_INLINE
static Msg* DoCreateMaybeMessage(Arena* arena,
552 return CreateMessageInternal<Msg>(arena, std::forward<Args>(args)...);
555 template <
typename T,
typename... Args>
556 PROTOBUF_ALWAYS_INLINE
static T* DoCreateMaybeMessage(Arena* arena,
559 return CreateInternal<T>(arena, std::forward<Args>(args)...);
562 template <
typename T,
typename... Args>
563 PROTOBUF_ALWAYS_INLINE
static T* CreateMaybeMessage(Arena* arena,
565 return DoCreateMaybeMessage<T>(arena, is_arena_constructable<T>(),
566 std::forward<Args>(args)...);
569 template <
typename T,
typename... Args>
570 PROTOBUF_ALWAYS_INLINE
static T* CreateNoMessage(Arena* arena, std::true_type,
575 return CreateInternal<T>(arena, std::forward<Args>(args)...);
578 template <
typename T,
typename... Args>
579 PROTOBUF_ALWAYS_INLINE
static T* CreateNoMessage(Arena* arena,
585 return CreateMaybeMessage<T>(arena, std::forward<Args>(args)...);
590 template <
typename T>
591 PROTOBUF_ALWAYS_INLINE T* CreateInternalRawArray(
size_t num_elements) {
592 GOOGLE_CHECK_LE(num_elements, std::numeric_limits<size_t>::max() /
sizeof(T))
593 <<
"Requested size is too large to fit into size_t.";
594 const size_t n = internal::AlignUpTo8(
sizeof(T) * num_elements);
597 return static_cast<T*
>(AllocateAlignedNoHook(n));
600 template <
typename T,
typename... Args>
601 PROTOBUF_ALWAYS_INLINE T* DoCreate(
bool skip_explicit_ownership,
603 return new (AllocateInternal<T>(skip_explicit_ownership))
604 T(std::forward<Args>(args)...);
606 template <
typename T,
typename... Args>
607 PROTOBUF_ALWAYS_INLINE T* DoCreateMessage(Args&&... args) {
608 return InternalHelper<T>::Construct(
609 AllocateInternal<T>(InternalHelper<T>::is_destructor_skippable::value),
610 this, std::forward<Args>(args)...);
616 template <
typename T,
typename... Args>
617 static void CreateInArenaStorage(T* ptr, Arena* arena, Args&&... args) {
618 CreateInArenaStorageInternal(ptr, arena,
620 std::forward<Args>(args)...);
621 RegisterDestructorInternal(
626 template <
typename T,
typename... Args>
627 static void CreateInArenaStorageInternal(T* ptr, Arena* arena,
628 std::true_type, Args&&... args) {
629 InternalHelper<T>::Construct(ptr, arena, std::forward<Args>(args)...);
631 template <
typename T,
typename... Args>
632 static void CreateInArenaStorageInternal(T* ptr, Arena* ,
633 std::false_type, Args&&... args) {
634 new (ptr) T(std::forward<Args>(args)...);
637 template <
typename T>
638 static void RegisterDestructorInternal(T* , Arena* ,
640 template <
typename T>
641 static void RegisterDestructorInternal(T* ptr, Arena* arena,
643 arena->OwnDestructor(ptr);
651 template <
typename T>
652 PROTOBUF_ALWAYS_INLINE
void OwnInternal(T*
object, std::true_type) {
653 if (
object != NULL) {
654 impl_.AddCleanup(
object, &internal::arena_delete_object<Message>);
657 template <
typename T>
658 PROTOBUF_ALWAYS_INLINE
void OwnInternal(T*
object, std::false_type) {
659 if (
object != NULL) {
660 impl_.AddCleanup(
object, &internal::arena_delete_object<T>);
667 template <
typename T,
typename std::enable_if<
668 is_arena_constructable<T>::value,
int>
::type = 0>
669 PROTOBUF_ALWAYS_INLINE
static Arena* GetArenaInternal(
const T* value) {
670 return InternalHelper<T>::GetArena(value);
672 template <
typename T,
673 typename std::enable_if<!is_arena_constructable<T>::value &&
674 has_get_arena<T>::value,
676 PROTOBUF_ALWAYS_INLINE
static Arena* GetArenaInternal(
const T* value) {
677 return value->GetArena();
679 template <
typename T,
680 typename std::enable_if<!is_arena_constructable<T>::value &&
681 !has_get_arena<T>::value,
683 PROTOBUF_ALWAYS_INLINE
static Arena* GetArenaInternal(
const T* value) {
689 void* AllocateAligned(
size_t n) {
691 return AllocateAlignedNoHook(internal::AlignUpTo8(n));
693 template<
size_t Align>
694 void* AllocateAlignedTo(
size_t n) {
695 static_assert(Align > 0,
"Alignment must be greater than 0");
696 static_assert((Align & (Align - 1)) == 0,
"Alignment must be power of two");
697 if (Align <= 8)
return AllocateAligned(n);
700 uintptr_t ptr =
reinterpret_cast<uintptr_t
>(AllocateAligned(n + Align - 8));
701 ptr = (ptr + Align - 1) & -Align;
702 return reinterpret_cast<void*
>(ptr);
705 void* AllocateAlignedNoHook(
size_t n);
707 internal::ArenaImpl impl_;
709 void (*on_arena_allocation_)(
const std::type_info* allocated_type,
710 uint64 alloc_size,
void* cookie);
711 void (*on_arena_reset_)(Arena* arena,
void* cookie,
uint64 space_used);
712 void (*on_arena_destruction_)(Arena* arena,
void* cookie,
uint64 space_used);
718 template <
typename Type>
719 friend class internal::GenericTypeHandler;
720 friend struct internal::ArenaStringPtr;
721 friend class internal::LazyField;
722 friend class internal::EpsCopyInputStream;
723 friend class MessageLite;
724 template <
typename Key,
typename T>
734 #include <google/protobuf/port_undef.inc>
#define RTTI_TYPE_ID(type)
void EnableArenaMetrics(ArenaOptions *options)
void arena_free(void *object, size_t size)
void arena_destruct_object(void *object)
void arena_delete_object(void *object)
class PROTOBUF_EXPORT PROTOBUF_ALIGNAS(8) Arena final
type
Generic JSON types used in JWTs.
void *(* block_alloc)(size_t)
friend class ArenaOptionsTestFriend
void(* block_dealloc)(void *, size_t)
size_t initial_block_size