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 #ifndef GOOGLE_PROTOBUF_ARENA_TEST_UTIL_H__ 9 #define GOOGLE_PROTOBUF_ARENA_TEST_UTIL_H__ 10 11 #include <cstddef> 12 13 #include "absl/container/flat_hash_set.h" 14 #include "absl/log/absl_check.h" 15 #include "google/protobuf/arena.h" 16 #include "google/protobuf/io/coded_stream.h" 17 #include "google/protobuf/io/zero_copy_stream_impl_lite.h" 18 19 // Must be included last. 20 #include "google/protobuf/port_def.inc" 21 22 namespace google { 23 namespace protobuf { 24 namespace internal { 25 26 struct ArenaTestPeer { ReturnArrayMemoryArenaTestPeer27 static void ReturnArrayMemory(Arena* arena, void* p, size_t size) { 28 arena->ReturnArrayMemory(p, size); 29 } PeekCleanupListForTestingArenaTestPeer30 static auto PeekCleanupListForTesting(Arena* arena) { 31 return arena->PeekCleanupListForTesting(); 32 } 33 template <typename T, typename... U> GetConstructTypeArenaTestPeer34 static constexpr auto GetConstructType() { 35 return Arena::GetConstructType<T, U...>(); 36 } 37 using ConstructType = Arena::ConstructType; 38 }; 39 40 struct CleanupGrowthInfo { 41 size_t space_used; 42 absl::flat_hash_set<void*> cleanups; 43 }; 44 45 template <typename Func> CleanupGrowth(Arena & arena,Func f)46CleanupGrowthInfo CleanupGrowth(Arena& arena, Func f) { 47 auto old_space_used = arena.SpaceUsed(); 48 auto old_cleanups = ArenaTestPeer::PeekCleanupListForTesting(&arena); 49 f(); 50 auto new_space_used = arena.SpaceUsed(); 51 auto new_cleanups = ArenaTestPeer::PeekCleanupListForTesting(&arena); 52 CleanupGrowthInfo res; 53 res.space_used = new_space_used - old_space_used; 54 res.cleanups.insert(new_cleanups.begin(), new_cleanups.end()); 55 for (auto p : old_cleanups) res.cleanups.erase(p); 56 return res; 57 } 58 59 class NoHeapChecker { 60 public: NoHeapChecker()61 NoHeapChecker() { capture_alloc.Hook(); } 62 ~NoHeapChecker(); 63 64 private: 65 class NewDeleteCapture { 66 public: 67 // TODO: Implement this for opensource protobuf. Hook()68 void Hook() {} Unhook()69 void Unhook() {} alloc_count()70 int alloc_count() { return 0; } free_count()71 int free_count() { return 0; } 72 } capture_alloc; 73 }; 74 75 // Owns the internal T only if it's not owned by an arena. 76 // T needs to be arena constructible and destructor skippable. 77 template <typename T> 78 class ArenaHolder { 79 public: ArenaHolder(Arena * arena)80 explicit ArenaHolder(Arena* arena) 81 : field_(Arena::Create<T>(arena)), owned_by_arena_(arena != nullptr) { 82 ABSL_DCHECK(google::protobuf::Arena::is_arena_constructable<T>::value); 83 ABSL_DCHECK(google::protobuf::Arena::is_destructor_skippable<T>::value); 84 } 85 ~ArenaHolder()86 ~ArenaHolder() { 87 if (!owned_by_arena_) { 88 delete field_; 89 } 90 } 91 get()92 T* get() { return field_; } 93 T* operator->() { return field_; } 94 T& operator*() { return *field_; } 95 96 private: 97 T* field_; 98 bool owned_by_arena_; 99 }; 100 101 } // namespace internal 102 } // namespace protobuf 103 } // namespace google 104 105 #include "google/protobuf/port_undef.inc" 106 107 #endif // GOOGLE_PROTOBUF_ARENA_TEST_UTIL_H__ 108