|
16 | 16 | #define THIRD_PARTY_CEL_CPP_COMMON_ARENA_H_ |
17 | 17 |
|
18 | 18 | #include <type_traits> |
| 19 | +#include <utility> |
19 | 20 |
|
20 | 21 | #include "absl/base/nullability.h" |
21 | | -#include "absl/meta/type_traits.h" |
22 | 22 | #include "google/protobuf/arena.h" |
23 | 23 |
|
24 | 24 | namespace cel { |
25 | 25 |
|
26 | | -template <typename T> |
27 | | -using IsArenaConstructible = google::protobuf::Arena::is_arena_constructable<T>; |
| 26 | +template <typename T = void> |
| 27 | +struct ArenaTraits; |
| 28 | + |
| 29 | +namespace common_internal { |
28 | 30 |
|
29 | 31 | template <typename T> |
30 | | -using IsArenaDestructorSkippable = |
31 | | - absl::conjunction<IsArenaConstructible<T>, |
32 | | - google::protobuf::Arena::is_destructor_skippable<T>>; |
| 32 | +struct AssertArenaType : std::false_type { |
| 33 | + static_assert(!std::is_void_v<T>, "T must not be void"); |
| 34 | + static_assert(!std::is_reference_v<T>, "T must not be a reference"); |
| 35 | + static_assert(!std::is_volatile_v<T>, "T must not be volatile qualified"); |
| 36 | + static_assert(!std::is_const_v<T>, "T must not be const qualified"); |
| 37 | + static_assert(!std::is_array_v<T>, "T must not be an array"); |
| 38 | +}; |
33 | 39 |
|
34 | | -namespace common_internal { |
| 40 | +template <typename, typename = void> |
| 41 | +struct ArenaTraitsConstructible { |
| 42 | + using type = std::false_type; |
| 43 | +}; |
35 | 44 |
|
36 | 45 | template <typename T> |
37 | | -std::enable_if_t<IsArenaConstructible<T>::value, absl::Nullable<google::protobuf::Arena*>> |
38 | | -GetArena(const T* ptr) { |
| 46 | +struct ArenaTraitsConstructible< |
| 47 | + T, std::void_t<decltype(ArenaTraits<T>::constructible)>> { |
| 48 | + using type = typename ArenaTraits<T>::constructible; |
| 49 | +}; |
| 50 | + |
| 51 | +template <typename T> |
| 52 | +std::enable_if_t<google::protobuf::Arena::is_arena_constructable<T>::value, |
| 53 | + absl::Nullable<google::protobuf::Arena*>> |
| 54 | +GetArena(absl::Nullable<const T*> ptr) { |
39 | 55 | return ptr != nullptr ? ptr->GetArena() : nullptr; |
40 | 56 | } |
41 | 57 |
|
42 | 58 | template <typename T> |
43 | | -std::enable_if_t<!IsArenaConstructible<T>::value, |
| 59 | +std::enable_if_t<!google::protobuf::Arena::is_arena_constructable<T>::value, |
44 | 60 | absl::Nullable<google::protobuf::Arena*>> |
45 | | -GetArena([[maybe_unused]] const T* ptr) { |
| 61 | +GetArena([[maybe_unused]] absl::Nullable<const T*> ptr) { |
46 | 62 | return nullptr; |
47 | 63 | } |
48 | 64 |
|
| 65 | +template <typename, typename = void> |
| 66 | +struct HasArenaTraitsTriviallyDestructible : std::false_type {}; |
| 67 | + |
| 68 | +template <typename T> |
| 69 | +struct HasArenaTraitsTriviallyDestructible< |
| 70 | + T, std::void_t<decltype(ArenaTraits<T>::trivially_destructible( |
| 71 | + std::declval<const T&>()))>> : std::true_type {}; |
| 72 | + |
49 | 73 | } // namespace common_internal |
50 | 74 |
|
| 75 | +template <> |
| 76 | +struct ArenaTraits<void> { |
| 77 | + template <typename U> |
| 78 | + using constructible = std::disjunction< |
| 79 | + typename common_internal::AssertArenaType<U>::type, |
| 80 | + typename common_internal::ArenaTraitsConstructible<U>::type>; |
| 81 | + |
| 82 | + template <typename U> |
| 83 | + using always_trivially_destructible = |
| 84 | + std::disjunction<typename common_internal::AssertArenaType<U>::type, |
| 85 | + std::is_trivially_destructible<U>>; |
| 86 | + |
| 87 | + template <typename U> |
| 88 | + static bool trivially_destructible(const U& obj) { |
| 89 | + static_assert(!std::is_void_v<U>, "T must not be void"); |
| 90 | + static_assert(!std::is_reference_v<U>, "T must not be a reference"); |
| 91 | + static_assert(!std::is_volatile_v<U>, "T must not be volatile qualified"); |
| 92 | + static_assert(!std::is_const_v<U>, "T must not be const qualified"); |
| 93 | + static_assert(!std::is_array_v<U>, "T must not be an array"); |
| 94 | + |
| 95 | + if constexpr (always_trivially_destructible<U>()) { |
| 96 | + return true; |
| 97 | + } else if constexpr (google::protobuf::Arena::is_destructor_skippable<U>::value) { |
| 98 | + return obj.GetArena() != nullptr; |
| 99 | + } else if constexpr (common_internal::HasArenaTraitsTriviallyDestructible< |
| 100 | + U>::value) { |
| 101 | + return ArenaTraits<U>::trivially_destructible(obj); |
| 102 | + } else { |
| 103 | + return false; |
| 104 | + } |
| 105 | + } |
| 106 | +}; |
| 107 | + |
51 | 108 | } // namespace cel |
52 | 109 |
|
53 | 110 | #endif // THIRD_PARTY_CEL_CPP_COMMON_ARENA_H_ |
0 commit comments