33 #ifndef GOOGLE_PROTOBUF_ARENA_H__
34 #define GOOGLE_PROTOBUF_ARENA_H__
38 #undef max // Visual Studio defines this macro
40 #if defined(_MSC_VER) && !defined(_LIBCPP_STD_VER) && !_HAS_EXCEPTIONS
45 using type_info = ::type_info;
51 #include <google/protobuf/arena_impl.h>
52 #include <google/protobuf/stubs/port.h>
53 #include <type_traits>
62 namespace quality_webanswers {
74 namespace arena_metrics {
82 struct ArenaStringPtr;
85 template <
typename Type>
91 reinterpret_cast<T*
>(object)->~T();
95 delete reinterpret_cast<T*
>(object);
98 #if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation)
99 ::operator
delete(object, size);
102 ::operator
delete(object);
135 void* (*block_alloc)(size_t);
149 on_arena_reset(NULL),
150 on_arena_destruction(NULL),
151 on_arena_allocation(NULL) {}
163 void* (*on_arena_init)(
Arena* arena);
165 void (*on_arena_destruction)(
Arena* arena,
void* cookie,
uint64 space_used);
172 void (*on_arena_allocation)(
const std::type_info* allocated_type,
173 uint64 alloc_size,
void* cookie);
177 static const size_t kDefaultStartBlockSize = 256;
178 static const size_t kDefaultMaxBlockSize = 8192;
188 #ifndef GOOGLE_PROTOBUF_NO_RTTI
189 #define RTTI_TYPE_ID(type) (&typeid(type))
191 #define RTTI_TYPE_ID(type) (NULL)
258 static const size_t kBlockOverhead = internal::ArenaImpl::kBlockHeaderSize +
259 internal::ArenaImpl::kSerialArenaSize;
267 CallDestructorHooks();
272 on_arena_allocation_ = options.on_arena_allocation;
273 on_arena_reset_ = options.on_arena_reset;
274 on_arena_destruction_ = options.on_arena_destruction;
276 if (options.on_arena_init != NULL) {
277 hooks_cookie_ = options.on_arena_init(
this);
279 hooks_cookie_ = NULL;
293 template <
typename T,
typename... Args>
295 Arena* arena, Args&&... args) {
298 "CreateMessage can only construct types that are ArenaConstructable");
302 return Arena::CreateMaybeMessage<T>(arena, std::forward<Args>(args)...);
320 template <
typename T,
typename... Args>
321 GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
static T*
Create(
Arena* arena,
324 std::forward<Args>(args)...);
333 template <
typename T>
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 GOOGLE_CHECK_LE(num_elements, std::numeric_limits<size_t>::max() /
sizeof(T))
341 <<
"Requested size is too large to fit into size_t.";
343 return static_cast<T*
>(::operator
new[](num_elements *
sizeof(T)));
345 return arena->CreateInternalRawArray<T>(num_elements);
363 std::pair<
uint64,
uint64> SpaceAllocatedAndUsed()
const {
364 return std::make_pair(SpaceAllocated(), SpaceUsed());
372 GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE
uint64 Reset() {
374 if (on_arena_reset_ != NULL) {
375 on_arena_reset_(
this, hooks_cookie_, impl_.SpaceAllocated());
377 return impl_.Reset();
382 template <
typename T>
383 GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE
void Own(T*
object) {
384 OwnInternal(
object, std::is_convertible<T*, Message*>());
392 template <
typename T>
394 if (
object != NULL) {
395 impl_.AddCleanup(
object, &internal::arena_destruct_object<T>);
404 void*
object,
void (*destruct)(
void*)) {
405 impl_.AddCleanup(
object, destruct);
412 template <
typename T>
418 template <
typename T>
420 template <
typename U>
421 static char DestructorSkippable(
const typename U::DestructorSkippable_*);
422 template <
typename U>
423 static double DestructorSkippable(...);
425 typedef std::integral_constant<
426 bool,
sizeof(DestructorSkippable<T>(
static_cast<const T*
>(0))) ==
428 std::is_trivially_destructible<T>::value>
429 is_destructor_skippable;
431 template <
typename U>
432 static char ArenaConstructable(
433 const typename U::InternalArenaConstructable_*);
434 template <
typename U>
435 static double ArenaConstructable(...);
437 typedef std::integral_constant<bool, sizeof(ArenaConstructable<T>(
438 static_cast<const T*
>(0))) ==
440 is_arena_constructable;
442 template <
typename... Args>
443 static T* Construct(
void* ptr, Args&&... args) {
444 return new (ptr) T(std::forward<Args>(args)...);
447 static Arena* GetArena(
const T* p) {
return p->GetArenaNoVirtual(); }
464 template <
typename T>
466 template <
typename T>
471 template <
typename T,
typename... Args>
472 GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
static T* CreateMessageInternal(
473 Arena* arena, Args&&... args) {
476 "CreateMessage can only construct types that are ArenaConstructable");
478 return new T(
nullptr, std::forward<Args>(args)...);
480 return arena->DoCreateMessage<T>(std::forward<Args>(args)...);
487 template <
typename T>
488 GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
static T* CreateMessageInternal(
491 InternalHelper<T>::is_arena_constructable::value,
492 "CreateMessage can only construct types that are ArenaConstructable");
496 return arena->DoCreateMessage<T>();
500 template <
typename T,
typename... Args>
501 GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
static T* CreateInternal(
502 Arena* arena, Args&&... args) {
504 return new T(std::forward<Args>(args)...);
506 return arena->DoCreate<T>(std::is_trivially_destructible<T>::value,
507 std::forward<Args>(args)...);
511 void CallDestructorHooks();
512 void OnArenaAllocation(
const std::type_info* allocated_type,
size_t n)
const;
513 inline void AllocHook(
const std::type_info* allocated_type,
size_t n)
const {
514 if (GOOGLE_PREDICT_FALSE(hooks_cookie_ != NULL)) {
515 OnArenaAllocation(allocated_type, n);
522 template <
typename T>
523 GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
void* AllocateInternal(
524 bool skip_explicit_ownership) {
525 const size_t n = internal::AlignUpTo8(
sizeof(T));
528 if (skip_explicit_ownership) {
529 return impl_.AllocateAligned(n);
531 return impl_.AllocateAlignedAndAddCleanup(
532 n, &internal::arena_destruct_object<T>);
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)...);
547 template <
typename T,
typename... Args>
548 GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
static T* DoCreateMaybeMessage(
549 Arena* arena, std::false_type, Args&&... args) {
550 return CreateInternal<T>(arena, std::forward<Args>(args)...);
553 template <
typename T,
typename... Args>
554 GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
static T* CreateMaybeMessage(
555 Arena* arena, Args&&... args) {
556 return DoCreateMaybeMessage<T>(arena, is_arena_constructable<T>(),
557 std::forward<Args>(args)...);
560 template <
typename T,
typename... Args>
561 GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
static T* CreateNoMessage(
562 Arena* arena, std::true_type, Args&&... args) {
566 return CreateInternal<T>(arena, std::forward<Args>(args)...);
569 template <
typename T,
typename... Args>
570 GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
static T* CreateNoMessage(
571 Arena* arena, std::false_type, Args&&... args) {
575 return CreateMaybeMessage<T>(arena, std::forward<Args>(args)...);
580 template <
typename T>
581 GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE T* CreateInternalRawArray(
582 size_t num_elements) {
583 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 const size_t n = internal::AlignUpTo8(
sizeof(T) * num_elements);
588 return static_cast<T*
>(impl_.AllocateAligned(n));
591 template <
typename T,
typename... Args>
592 GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE T* DoCreate(
593 bool skip_explicit_ownership, Args&&... args) {
594 return new (AllocateInternal<T>(skip_explicit_ownership))
595 T(std::forward<Args>(args)...);
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)...);
607 template <
typename T>
608 static void CreateInArenaStorage(T* ptr, Arena* arena) {
609 CreateInArenaStorageInternal(ptr, arena,
611 RegisterDestructorInternal(
616 template <
typename T>
617 static void CreateInArenaStorageInternal(T* ptr, Arena* arena,
619 InternalHelper<T>::Construct(ptr, arena);
621 template <
typename T>
622 static void CreateInArenaStorageInternal(T* ptr, Arena* ,
627 template <
typename T>
628 static void RegisterDestructorInternal(T* , Arena* ,
630 template <
typename T>
631 static void RegisterDestructorInternal(T* ptr, Arena* arena,
633 arena->OwnDestructor(ptr);
641 template <
typename T>
642 GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
void OwnInternal(T*
object,
644 if (
object != NULL) {
645 impl_.AddCleanup(
object, &internal::arena_delete_object<Message>);
648 template <
typename T>
649 GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
void OwnInternal(T*
object,
651 if (
object != NULL) {
652 impl_.AddCleanup(
object, &internal::arena_delete_object<T>);
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);
665 template <
typename T>
666 GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
static Arena* GetArenaInternal(
667 const T* , std::false_type) {
672 void* AllocateAligned(
size_t n) {
674 return impl_.AllocateAligned(internal::AlignUpTo8(n));
677 internal::ArenaImpl impl_;
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);
688 template <
typename Type>
690 friend struct internal::ArenaStringPtr;
691 friend class internal::LazyField;
693 template <
typename Key,
typename T>
703 #endif // GOOGLE_PROTOBUF_ARENA_H__