1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef INCLUDE_PERFETTO_PROTOZERO_MESSAGE_HANDLE_H_ 18 #define INCLUDE_PERFETTO_PROTOZERO_MESSAGE_HANDLE_H_ 19 20 #include <functional> 21 22 #include "perfetto/base/export.h" 23 #include "perfetto/protozero/message.h" 24 25 namespace protozero { 26 27 class Message; 28 29 // MessageHandle allows to decouple the lifetime of a proto message 30 // from the underlying storage. It gives the following guarantees: 31 // - The underlying message is finalized (if still alive) if the handle goes 32 // out of scope. 33 // - In Debug / DCHECK_ALWAYS_ON builds, the handle becomes null once the 34 // message is finalized. This is to enforce the append-only API. For instance 35 // when adding two repeated messages, the addition of the 2nd one forces 36 // the finalization of the first. 37 // Think about this as a WeakPtr<Message> which calls 38 // Message::Finalize() when going out of scope. 39 40 class PERFETTO_EXPORT MessageHandleBase { 41 public: 42 class FinalizationListener { 43 public: 44 virtual ~FinalizationListener(); 45 virtual void OnMessageFinalized(Message* message) = 0; 46 }; 47 48 ~MessageHandleBase(); 49 50 // Move-only type. 51 MessageHandleBase(MessageHandleBase&&) noexcept; 52 MessageHandleBase& operator=(MessageHandleBase&&); 53 explicit operator bool() const { 54 #if PERFETTO_DCHECK_IS_ON() 55 PERFETTO_DCHECK(!message_ || generation_ == message_->generation_); 56 #endif 57 return !!message_; 58 } 59 set_finalization_listener(FinalizationListener * listener)60 void set_finalization_listener(FinalizationListener* listener) { 61 listener_ = listener; 62 } 63 64 protected: 65 explicit MessageHandleBase(Message* = nullptr); 66 Message* operator->() const { 67 #if PERFETTO_DCHECK_IS_ON() 68 PERFETTO_DCHECK(!message_ || generation_ == message_->generation_); 69 #endif 70 return message_; 71 } 72 Message& operator*() const { return *(operator->()); } 73 74 private: 75 friend class Message; 76 MessageHandleBase(const MessageHandleBase&) = delete; 77 MessageHandleBase& operator=(const MessageHandleBase&) = delete; 78 reset_message()79 void reset_message() { 80 // This is called by Message::Finalize(). 81 PERFETTO_DCHECK(message_->is_finalized()); 82 message_ = nullptr; 83 listener_ = nullptr; 84 } 85 86 void Move(MessageHandleBase&&); 87 FinalizeMessage()88 void FinalizeMessage() { 89 // |message_| and |listener_| may be cleared by reset_message() during 90 // Message::Finalize(). 91 auto* listener = listener_; 92 auto* message = message_; 93 message->Finalize(); 94 if (listener) 95 listener->OnMessageFinalized(message); 96 } 97 98 Message* message_; 99 FinalizationListener* listener_ = nullptr; 100 #if PERFETTO_DCHECK_IS_ON() 101 uint32_t generation_; 102 #endif 103 }; 104 105 template <typename T> 106 class MessageHandle : public MessageHandleBase { 107 public: MessageHandle()108 MessageHandle() : MessageHandle(nullptr) {} MessageHandle(T * message)109 explicit MessageHandle(T* message) : MessageHandleBase(message) {} 110 111 T& operator*() const { 112 return static_cast<T&>(MessageHandleBase::operator*()); 113 } 114 115 T* operator->() const { 116 return static_cast<T*>(MessageHandleBase::operator->()); 117 } 118 }; 119 120 } // namespace protozero 121 122 #endif // INCLUDE_PERFETTO_PROTOZERO_MESSAGE_HANDLE_H_ 123