33 #ifndef GOOGLE_PROTOBUF_ARENA_H__
34 #define GOOGLE_PROTOBUF_ARENA_H__
37 #include <type_traits>
40 #undef max // Visual Studio defines this macro
42 #if defined(_MSC_VER) && !defined(_LIBCPP_STD_VER) && !_HAS_EXCEPTIONS
47 using type_info = ::type_info;
55 #include <type_traits>
57 #include <google/protobuf/port_def.inc>
60 #error "You cannot SWIG proto headers"
79 namespace arena_metrics {
90 template <
typename Type>
96 reinterpret_cast<T*
>(object)->~
T();
100 delete reinterpret_cast<T*
>(object);
103 #if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation)
104 ::operator
delete(object,
size);
107 ::operator
delete(object);
140 void* (*block_alloc)(size_t);
169 void* (*on_arena_init)(
Arena* arena);
179 uint64 alloc_size,
void* cookie);
194 #define RTTI_TYPE_ID(type) (&typeid(type))
196 #define RTTI_TYPE_ID(type) (NULL)
248 class PROTOBUF_EXPORT
alignas(8) Arena final {
271 CallDestructorHooks();
276 on_arena_allocation_ =
options.on_arena_allocation;
277 on_arena_reset_ =
options.on_arena_reset;
278 on_arena_destruction_ =
options.on_arena_destruction;
281 hooks_cookie_ =
options.on_arena_init(
this);
283 hooks_cookie_ =
NULL;
297 template <
typename T,
typename...
Args>
298 PROTOBUF_ALWAYS_INLINE
static T* CreateMessage(Arena* arena,
Args&&...
args) {
301 "CreateMessage can only construct types that are ArenaConstructable");
305 return Arena::CreateMaybeMessage<T>(arena, std::forward<Args>(
args)...);
323 template <
typename T,
typename...
Args>
324 PROTOBUF_ALWAYS_INLINE
static T* Create(Arena* arena,
Args&&...
args) {
325 return CreateNoMessage<T>(arena, is_arena_constructable<T>(),
326 std::forward<Args>(
args)...);
335 template <
typename T>
336 PROTOBUF_ALWAYS_INLINE
static T* CreateArray(Arena* arena,
337 size_t num_elements) {
339 "CreateArray requires a trivially constructible type");
341 "CreateArray requires a trivially destructible type");
342 GOOGLE_CHECK_LE(num_elements, std::numeric_limits<size_t>::max() /
sizeof(
T))
343 <<
"Requested size is too large to fit into size_t.";
345 return static_cast<T*
>(::operator
new[](num_elements *
sizeof(
T)));
347 return arena->CreateInternalRawArray<
T>(num_elements);
354 uint64 SpaceAllocated()
const {
return impl_.SpaceAllocated(); }
359 uint64 SpaceUsed()
const {
return impl_.SpaceUsed(); }
364 PROTOBUF_DEPRECATED_MSG(
"Please use SpaceAllocated() and SpaceUsed()")
365 std::pair<uint64, uint64> SpaceAllocatedAndUsed()
const {
366 return std::make_pair(SpaceAllocated(), SpaceUsed());
376 if (on_arena_reset_ !=
NULL) {
377 on_arena_reset_(
this, hooks_cookie_, impl_.SpaceAllocated());
379 return impl_.Reset();
384 template <
typename T>
385 PROTOBUF_NOINLINE
void Own(
T*
object) {
386 OwnInternal(
object, std::is_convertible<T*, Message*>());
394 template <
typename T>
395 PROTOBUF_NOINLINE
void OwnDestructor(
T*
object) {
396 if (
object !=
NULL) {
397 impl_.AddCleanup(
object, &internal::arena_destruct_object<T>);
405 PROTOBUF_NOINLINE
void OwnCustomDestructor(
void*
object,
406 void (*destruct)(
void*)) {
407 impl_.AddCleanup(
object, destruct);
414 template <
typename T>
416 return GetArenaInternal(
value);
419 template <
typename T>
420 class InternalHelper {
421 template <
typename U>
422 static char DestructorSkippable(
const typename U::DestructorSkippable_*);
423 template <
typename U>
424 static double DestructorSkippable(...);
426 typedef std::integral_constant<
427 bool,
sizeof(DestructorSkippable<T>(
static_cast<const T*
>(0))) ==
430 is_destructor_skippable;
432 template <
typename U>
433 static char ArenaConstructable(
434 const typename U::InternalArenaConstructable_*);
435 template <
typename U>
436 static double ArenaConstructable(...);
438 typedef std::integral_constant<bool, sizeof(ArenaConstructable<T>(
439 static_cast<const T*
>(0))) ==
441 is_arena_constructable;
443 template <
typename U,
444 typename std::enable_if<
445 std::is_same<Arena*, decltype(std::declval<const U>()
446 .GetArena())>::
value,
449 template <
typename U>
450 static double HasGetArena(...);
452 typedef std::integral_constant<bool, sizeof(HasGetArena<T>(
nullptr)) ==
456 template <
typename...
Args>
457 static T* Construct(
void* ptr,
Args&&...
args) {
458 return new (ptr)
T(std::forward<Args>(
args)...);
461 static Arena*
GetArena(
const T*
p) {
return p->GetArenaNoVirtual(); }
478 template <
typename T>
479 struct is_arena_constructable : InternalHelper<T>::is_arena_constructable {};
480 template <
typename T>
481 struct is_destructor_skippable : InternalHelper<T>::is_destructor_skippable {
485 template <
typename T>
486 struct has_get_arena : InternalHelper<T>::has_get_arena {};
488 template <
typename T,
typename...
Args>
489 PROTOBUF_ALWAYS_INLINE
static T* CreateMessageInternal(Arena* arena,
493 "CreateMessage can only construct types that are ArenaConstructable");
495 return new T(
nullptr, std::forward<Args>(
args)...);
497 return arena->DoCreateMessage<
T>(std::forward<Args>(
args)...);
504 template <
typename T>
505 PROTOBUF_ALWAYS_INLINE
static T* CreateMessageInternal(Arena* arena) {
508 "CreateMessage can only construct types that are ArenaConstructable");
512 return arena->DoCreateMessage<
T>();
516 template <
typename T,
typename...
Args>
517 PROTOBUF_ALWAYS_INLINE
static T* CreateInternal(Arena* arena,
520 return new T(std::forward<Args>(
args)...);
523 std::forward<Args>(
args)...);
527 void CallDestructorHooks();
528 void OnArenaAllocation(
const std::type_info* allocated_type,
size_t n)
const;
529 inline void AllocHook(
const std::type_info* allocated_type,
size_t n)
const {
530 if (PROTOBUF_PREDICT_FALSE(hooks_cookie_ !=
NULL)) {
531 OnArenaAllocation(allocated_type,
n);
538 template <
typename T>
539 PROTOBUF_ALWAYS_INLINE
void* AllocateInternal(
bool skip_explicit_ownership) {
543 if (skip_explicit_ownership) {
544 return impl_.AllocateAligned(
n);
546 return impl_.AllocateAlignedAndAddCleanup(
547 n, &internal::arena_destruct_object<T>);
556 template <
typename Msg,
typename...
Args>
557 PROTOBUF_ALWAYS_INLINE
static Msg* DoCreateMaybeMessage(Arena* arena,
560 return CreateMessageInternal<Msg>(arena, std::forward<Args>(
args)...);
563 template <
typename T,
typename...
Args>
564 PROTOBUF_ALWAYS_INLINE
static T* DoCreateMaybeMessage(Arena* arena,
567 return CreateInternal<T>(arena, std::forward<Args>(
args)...);
570 template <
typename T,
typename...
Args>
571 PROTOBUF_ALWAYS_INLINE
static T* CreateMaybeMessage(Arena* arena,
573 return DoCreateMaybeMessage<T>(arena, is_arena_constructable<T>(),
574 std::forward<Args>(
args)...);
577 template <
typename T,
typename...
Args>
578 PROTOBUF_ALWAYS_INLINE
static T* CreateNoMessage(Arena* arena,
std::true_type,
583 return CreateInternal<T>(arena, std::forward<Args>(
args)...);
586 template <
typename T,
typename...
Args>
587 PROTOBUF_ALWAYS_INLINE
static T* CreateNoMessage(Arena* arena,
593 return CreateMaybeMessage<T>(arena, std::forward<Args>(
args)...);
598 template <
typename T>
599 PROTOBUF_ALWAYS_INLINE
T* CreateInternalRawArray(
size_t num_elements) {
600 GOOGLE_CHECK_LE(num_elements, std::numeric_limits<size_t>::max() /
sizeof(
T))
601 <<
"Requested size is too large to fit into size_t.";
605 return static_cast<T*
>(impl_.AllocateAligned(
n));
608 template <
typename T,
typename...
Args>
609 PROTOBUF_ALWAYS_INLINE
T* DoCreate(
bool skip_explicit_ownership,
611 return new (AllocateInternal<T>(skip_explicit_ownership))
612 T(std::forward<Args>(
args)...);
614 template <
typename T,
typename...
Args>
615 PROTOBUF_ALWAYS_INLINE
T* DoCreateMessage(
Args&&...
args) {
616 return InternalHelper<T>::Construct(
618 this, std::forward<Args>(
args)...);
624 template <
typename T>
625 static void CreateInArenaStorage(
T* ptr, Arena* arena) {
626 CreateInArenaStorageInternal(ptr, arena,
628 RegisterDestructorInternal(
633 template <
typename T>
634 static void CreateInArenaStorageInternal(
T* ptr, Arena* arena,
636 InternalHelper<T>::Construct(ptr, arena);
638 template <
typename T>
639 static void CreateInArenaStorageInternal(
T* ptr, Arena* ,
644 template <
typename T>
645 static void RegisterDestructorInternal(
T* , Arena* ,
647 template <
typename T>
648 static void RegisterDestructorInternal(
T* ptr, Arena* arena,
650 arena->OwnDestructor(ptr);
658 template <
typename T>
660 if (
object !=
NULL) {
661 impl_.AddCleanup(
object, &internal::arena_delete_object<Message>);
664 template <
typename T>
666 if (
object !=
NULL) {
667 impl_.AddCleanup(
object, &internal::arena_delete_object<T>);
674 template <
typename T,
typename std::enable_if<
676 PROTOBUF_ALWAYS_INLINE
static Arena* GetArenaInternal(
const T*
value) {
679 template <
typename T,
683 PROTOBUF_ALWAYS_INLINE
static Arena* GetArenaInternal(
const T*
value) {
684 return value->GetArena();
686 template <
typename T,
690 PROTOBUF_ALWAYS_INLINE
static Arena* GetArenaInternal(
const T*
value) {
695 void* AllocateAligned(
size_t n) {
702 void (*on_arena_allocation_)(
const std::type_info* allocated_type,
703 uint64 alloc_size,
void* cookie);
704 void (*on_arena_reset_)(Arena* arena,
void* cookie,
uint64 space_used);
705 void (*on_arena_destruction_)(Arena* arena,
void* cookie,
uint64 space_used);
711 template <
typename Type>
714 friend class internal::LazyField;
716 template <
typename Key,
typename T>
726 #include <google/protobuf/port_undef.inc>
728 #endif // GOOGLE_PROTOBUF_ARENA_H__