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 ~MessageHandleBase(); 43 44 // Move-only type. 45 MessageHandleBase(MessageHandleBase&&) noexcept; 46 MessageHandleBase& operator=(MessageHandleBase&&); 47 explicit operator bool() const { 48 #if PERFETTO_DCHECK_IS_ON() 49 PERFETTO_DCHECK(!message_ || generation_ == message_->generation_); 50 #endif 51 return !!message_; 52 } 53 54 protected: 55 explicit MessageHandleBase(Message* = nullptr); 56 Message* operator->() const { 57 #if PERFETTO_DCHECK_IS_ON() 58 PERFETTO_DCHECK(!message_ || generation_ == message_->generation_); 59 #endif 60 return message_; 61 } 62 Message& operator*() const { return *(operator->()); } 63 64 private: 65 friend class Message; 66 MessageHandleBase(const MessageHandleBase&) = delete; 67 MessageHandleBase& operator=(const MessageHandleBase&) = delete; 68 reset_message()69 void reset_message() { 70 // This is called by Message::Finalize(). 71 PERFETTO_DCHECK(message_->is_finalized()); 72 message_ = nullptr; 73 } 74 75 void Move(MessageHandleBase&&); 76 FinalizeMessage()77 void FinalizeMessage() { message_->Finalize(); } 78 79 Message* message_; 80 #if PERFETTO_DCHECK_IS_ON() 81 uint32_t generation_; 82 #endif 83 }; 84 85 template <typename T> 86 class MessageHandle : public MessageHandleBase { 87 public: MessageHandle()88 MessageHandle() : MessageHandle(nullptr) {} MessageHandle(T * message)89 explicit MessageHandle(T* message) : MessageHandleBase(message) {} 90 91 explicit operator bool() const { return MessageHandleBase::operator bool(); } 92 93 T& operator*() const { 94 return static_cast<T&>(MessageHandleBase::operator*()); 95 } 96 97 T* operator->() const { 98 return static_cast<T*>(MessageHandleBase::operator->()); 99 } 100 get()101 T* get() const { return static_cast<T*>(MessageHandleBase::operator->()); } 102 }; 103 104 } // namespace protozero 105 106 #endif // INCLUDE_PERFETTO_PROTOZERO_MESSAGE_HANDLE_H_ 107