mediapipe/mediapipe/framework/packet.h
MediaPipe Team 2c82f67097 Add location info in registry (debug mode only)
PiperOrigin-RevId: 508786558
2023-02-10 16:58:44 -08:00

799 lines
30 KiB
C++

// Copyright 2019 The MediaPipe Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Defines Packet, a container capable of holding an object of any type.
#ifndef MEDIAPIPE_FRAMEWORK_PACKET_H_
#define MEDIAPIPE_FRAMEWORK_PACKET_H_
#include <cstddef>
#include <memory>
#include <string>
#include <type_traits>
#include "absl/base/macros.h"
#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
#include "absl/synchronization/mutex.h"
#include "mediapipe/framework/deps/no_destructor.h"
#include "mediapipe/framework/deps/registration.h"
#include "mediapipe/framework/port.h"
#include "mediapipe/framework/port/canonical_errors.h"
#include "mediapipe/framework/port/logging.h"
#include "mediapipe/framework/port/proto_ns.h"
#include "mediapipe/framework/port/status.h"
#include "mediapipe/framework/port/status_builder.h"
#include "mediapipe/framework/port/status_macros.h"
#include "mediapipe/framework/port/statusor.h"
#include "mediapipe/framework/timestamp.h"
#include "mediapipe/framework/tool/type_util.h"
#include "mediapipe/framework/type_map.h"
namespace mediapipe {
class Packet;
namespace packet_internal {
class HolderBase;
Packet Create(HolderBase* holder);
Packet Create(HolderBase* holder, Timestamp timestamp);
Packet Create(std::shared_ptr<HolderBase> holder, Timestamp timestamp);
const HolderBase* GetHolder(const Packet& packet);
const std::shared_ptr<HolderBase>& GetHolderShared(const Packet& packet);
std::shared_ptr<HolderBase> GetHolderShared(Packet&& packet);
absl::StatusOr<Packet> PacketFromDynamicProto(const std::string& type_name,
const std::string& serialized);
} // namespace packet_internal
// A generic container class which can hold data of any type. The type of
// the data is specified when accessing the data (using Packet::Get<T>()).
//
// The Packet is implemented as a reference-counted pointer. This means
// that copying Packets creates a fast, shallow copy. Packets are
// copyable, movable, and assignable. Packets can be stored in STL
// containers. A Packet may optionally contain a timestamp.
//
// The preferred method of creating a Packet is with MakePacket<T>().
// The Packet typically owns the object that it contains, but
// PointToForeign allows a Packet to be constructed which does not
// own its data.
//
// This class is thread compatible.
class Packet {
public:
// Creates an empty Packet, for which IsEmpty()==true and
// Timestamp()==Timestamp::Unset(). Calling Get() on this Packet leads
// to CHECK-failure.
Packet() = default;
// Copy constructor and assignment operator.
Packet(const Packet&);
Packet& operator=(const Packet&);
// Move constructor and assignment operator that take non-const rvalue
// reference.
Packet(Packet&&);
Packet& operator=(Packet&&);
// Returns a Packet that contains the same data as *this, and has the
// given timestamp. Does not modify *this.
Packet At(class Timestamp timestamp) const&;
// The rvalue reference overload of Packet's member function
// Packet::At(class Timestamp). Moves *this to a new Packet and returns
// the new Packet with the given timestamp.
Packet At(class Timestamp timestamp) &&;
// Returns true iff the Packet has been created using the default
// constructor Packet(), or is a copy of such a Packet.
bool IsEmpty() const;
// Returns the reference to the object of typename T if it contains
// one, crashes otherwise. It is safe to concurrently call Get()
// on the same packet from multiple threads.
template <typename T>
const T& Get() const;
// Transfers the ownership of holder's data to a unique pointer
// of the object if the packet is the sole owner of a non-foreign
// holder. Otherwise, returns error when the packet can't be consumed.
// See ConsumeOrCopy for threading requirements and example usage.
template <typename T>
absl::StatusOr<std::unique_ptr<T>> Consume();
// Consumes the packet and transfers the ownership of the data to a
// unique pointer if the packet is the sole owner of a non-foreign
// holder. Otherwise, the unique pointer holds a copy of the original
// data. In either case, the original packet is set to empty. The
// method returns error when the packet can't be consumed or copied. If
// was_copied is not nullptr, it is set to indicate whether the packet
// data was copied.
// Packet is thread-compatible, therefore Packet::ConsumeOrCopy()
// must be thread-compatible: clients who use this function are
// responsible for ensuring that no other thread is doing anything
// with the Packet.
// Example usage:
// ASSIGN_OR_RETURN(std::unique_ptr<Detection> detection,
// p.ConsumeOrCopy<Detection>());
// // The unique_ptr type can be omitted with auto.
// ASSIGN_OR_RETURN(auto detection, p.ConsumeOrCopy<Detection>());
// If you would like to crash on failure (prefer ASSIGN_OR_RETURN):
// auto detection = p.ConsumeOrCopy<Detection>().value();
// // In functions which do not return absl::Status use an adaptor
// // function as the third argument to ASSIGN_OR_RETURN. In tests,
// // use an adaptor which returns void.
// ASSIGN_OR_RETURN(auto detection, p.ConsumeOrCopy<Detection>(),
// _.With([](const absl::Status& status) {
// MP_EXPECT_OK(status);
// // Use CHECK_OK to crash and report a usable line
// // number (which the value() alternative does not).
// // Include a return statement if the return value is
// // non-void. For example: return 1;
// }));
//
// Version for non-arrays.
template <typename T>
absl::StatusOr<std::unique_ptr<T>> ConsumeOrCopy(
bool* was_copied = nullptr,
typename std::enable_if<!std::is_array<T>::value>::type* = nullptr);
// Version for bounded array.
template <typename T>
absl::StatusOr<std::unique_ptr<T>> ConsumeOrCopy(
bool* was_copied = nullptr,
typename std::enable_if<std::is_array<T>::value &&
std::extent<T>::value != 0>::type* = nullptr);
// TODO: Support unbounded array after fixing the bug in holder's
// delete helper.
// Version for unbounded array.
template <typename T>
absl::StatusOr<std::unique_ptr<T>> ConsumeOrCopy(
bool* was_copied = nullptr,
typename std::enable_if<std::is_array<T>::value &&
std::extent<T>::value == 0>::type* = nullptr);
// Returns the reference to type MessageLite data, if the underlying
// object type is protocol buffer, crashes otherwise.
const proto_ns::MessageLite& GetProtoMessageLite() const;
// Returns a vector of pointers to MessageLite data, if the underlying
// object type is a vector of MessageLite data, returns an error otherwise.
// Note: This function is meant to be used internally within the MediaPipe
// framework only.
StatusOr<std::vector<const proto_ns::MessageLite*>>
GetVectorOfProtoMessageLitePtrs() const;
// Returns an error if the packet does not contain data of type T.
template <typename T>
absl::Status ValidateAsType() const {
return ValidateAsType(kTypeId<T>);
}
// Returns an error if the packet is not an instance of
// a protocol buffer message.
absl::Status ValidateAsProtoMessageLite() const;
// Get the type id for the underlying type stored in the Packet.
// Crashes if IsEmpty() == true.
TypeId GetTypeId() const;
// Returns the timestamp.
class Timestamp Timestamp() const;
std::string DebugString() const;
friend std::ostream& operator<<(std::ostream& stream, const Packet& p) {
return stream << p.DebugString();
}
// Returns the type name. If the packet is empty or the type is not
// registered (with MEDIAPIPE_REGISTER_TYPE or companion macros) then
// the empty string is returned.
std::string RegisteredTypeName() const;
// Returns a string with the best guess at the type name.
std::string DebugTypeName() const;
private:
friend Packet packet_internal::Create(packet_internal::HolderBase* holder);
friend Packet packet_internal::Create(packet_internal::HolderBase* holder,
class Timestamp timestamp);
friend Packet packet_internal::Create(
std::shared_ptr<packet_internal::HolderBase> holder,
class Timestamp timestamp);
friend const packet_internal::HolderBase* packet_internal::GetHolder(
const Packet& packet);
friend const std::shared_ptr<packet_internal::HolderBase>&
packet_internal::GetHolderShared(const Packet& packet);
friend std::shared_ptr<packet_internal::HolderBase>
packet_internal::GetHolderShared(Packet&& packet);
friend class PacketType;
absl::Status ValidateAsType(TypeId type_id) const;
std::shared_ptr<packet_internal::HolderBase> holder_;
class Timestamp timestamp_;
};
// Factory functions for creating Packets. Non-members as opposed to static
// methods, to prevent users from mistakenly calling them on Packet instances.
// Returns a Packet that adopts the object; the Packet assumes the ownership.
// The timestamp of the returned Packet is Timestamp::Unset(). To set the
// timestamp, the caller should do Adopt(...).At(...).
//
// Generally prefer MakePacket<T>().
template <typename T>
Packet Adopt(const T* ptr);
// Returns a Packet that does not own its data. The data pointed to by *ptr
// remains owned by the caller, who must ensure that it outlives not only the
// returned Packet but also all of its copies. The timestamp of the returned
// Packet is Timestamp::Unset(). To set the timestamp, the caller should do
// PointToForeign(...).At(...).
template <typename T>
Packet PointToForeign(const T* ptr);
// Adopts the data but places it in a std::unique_ptr inside the
// resulting Packet, leaving the timestamp unset. This allows the
// adopted data to be mutated, with the mutable data accessible as
// packet.Get<std::unique_ptr<T>>().get(). GetFromUniquePtr below provides
// a more syntactically-pleasing way of accomplishing that.
template <typename T>
Packet AdoptAsUniquePtr(T* ptr) {
static_assert(
!std::is_const<T>::value,
"AdoptAsUniquePtr should not be called with a pointer-to-const.");
return Adopt(new std::unique_ptr<T>(ptr));
}
// A SyncedPacket is a packet containing a reference to another packet, and the
// reference can be updated.
// SyncedPacket is thread-safe.
class SyncedPacket {
public:
explicit SyncedPacket(const Packet& packet) : packet_(packet) {}
void UpdatePacket(const Packet& packet) {
absl::WriterMutexLock writer_lock(&mutex_);
packet_ = packet;
}
Packet Get() {
absl::ReaderMutexLock reader_lock(&mutex_);
return packet_;
}
private:
absl::Mutex mutex_;
Packet packet_;
};
// Adopt the data as SyncedPacket, so that the content of the packet can be
// updated in a thread-safe way.
// Usage:
// Packet synced_packet = AdoptAsSyncedPacket(new int(100));
// Packet value_packet =
// synced_packet.Get<std::unique_ptr<SyncedPacket>>()->Get();
// EXPECT_EQ(100, value_packet.Get<int>());
// // update the value.
// Packet new_value_packet = Adopt(new int(999));
// synced_packet.Get<std::unique_ptr<SyncedPacket>>()
// ->UpdatePacket(new_value_packet);
// Packet packet_new =
// synced_packet.Get<std::unique_ptr<SyncedPacket>>()->Get();
// EXPECT_EQ(999, packet_new.Get<int>());
template <typename T>
Packet AdoptAsSyncedPacket(const T* ptr) {
Packet packet = Adopt(ptr);
return AdoptAsUniquePtr(new SyncedPacket(packet));
}
// Create a packet containing an object of type T initialized with the
// provided arguments. Similar to MakeUnique. Especially convenient for arrays,
// since it ensures the packet gets the right type (see below).
//
// Version for scalars.
template <typename T,
typename std::enable_if<!std::is_array<T>::value>::type* = nullptr,
typename... Args>
Packet MakePacket(Args&&... args) { // NOLINT(build/c++11)
return Adopt(new T(std::forward<Args>(args)...));
}
// Version for arrays. We have to use reinterpret_cast because new T[N]
// returns a T* instead of a T(*)[N] (i.e. a pointer to the first element
// instead of a pointer to the array itself - they have the same value, but
// different types), which would prevent Adopt from seeing the array's type
// if we did not have the cast.
template <typename T,
typename std::enable_if<std::is_array<T>::value>::type* = nullptr,
typename... Args>
Packet MakePacket(Args&&... args) { // NOLINT(build/c++11)
return Adopt(reinterpret_cast<T*>(
new T{std::forward<typename std::remove_extent<T>::type>(args)...}));
}
// Returns a mutable pointer to the data in a unique_ptr in a packet. This
// is useful in combination with AdoptAsUniquePtr. The caller must
// exercise caution when mutating the retrieved data, since the data
// may be accessible from other locations.
template <typename T>
T* GetFromUniquePtr(const Packet& packet) {
return packet.Get<std::unique_ptr<T>>().get();
}
// Returns a shared_ptr to the payload of the packet which retains its object
// through a copy of the packet.
// Use std::const_pointer_cast if you need a shared_ptr<T>, but remember that
// you must not change the payload if the packet has other owners. Use Consume
// if you want to try and modify the payload directly.
template <typename T>
std::shared_ptr<const T> SharedPtrWithPacket(Packet packet) {
// This needs to be a separate statement because the evaluation order of
// function arguments is unspecified, and if the lambda is created first it
// moves the packet.
const T* ptr = &packet.Get<T>();
return std::shared_ptr<const T>(
ptr, [packet = std::move(packet)](const T* ptr) mutable { packet = {}; });
}
//// Implementation details.
namespace packet_internal {
template <typename T>
class Holder;
template <typename T>
class ForeignHolder;
class HolderBase {
public:
HolderBase() {}
HolderBase(const HolderBase&) = delete;
HolderBase& operator=(const HolderBase&) = delete;
virtual ~HolderBase();
template <typename T>
bool PayloadIsOfType() const {
return GetTypeId() == kTypeId<T>;
}
// Returns a printable string identifying the type stored in the holder.
virtual const std::string DebugTypeName() const = 0;
// Returns the registered type name if it's available, otherwise the
// empty string.
virtual const std::string RegisteredTypeName() const = 0;
// Get the type id of the underlying data type.
virtual TypeId GetTypeId() const = 0;
// Downcasts this to Holder<T>. Returns nullptr if deserialization
// failed or if the requested type is not what is stored.
template <typename T>
Holder<T>* As();
// Same as non-const As() function.
template <typename T>
const Holder<T>* As() const;
// Returns the pointer to MessageLite type for the data in holder, if
// underlying object is protocol buffer type, otherwise, nullptr is returned.
virtual const proto_ns::MessageLite* GetProtoMessageLite() = 0;
// Returns a vector<MessageLite*> for the data in the holder, if the
// underlying object is a vector of protocol buffer objects, otherwise,
// returns an error.
virtual StatusOr<std::vector<const proto_ns::MessageLite*>>
GetVectorOfProtoMessageLite() const = 0;
virtual bool HasForeignOwner() const { return false; }
};
// Two helper functions to get the proto base pointers.
template <typename T>
const proto_ns::MessageLite* ConvertToProtoMessageLite(const T* data,
std::false_type) {
return nullptr;
}
template <typename T>
const proto_ns::MessageLite* ConvertToProtoMessageLite(const T* data,
std::true_type) {
return data;
}
// Helper structs for determining if a type is an std::vector<Proto>.
template <typename Type>
struct is_proto_vector : public std::false_type {};
template <typename ItemT, typename Allocator>
struct is_proto_vector<std::vector<ItemT, Allocator>>
: public std::is_base_of<proto_ns::MessageLite, ItemT>::type {};
// Helper function to create and return a vector of pointers to proto message
// elements of the vector passed into the function.
template <typename T>
StatusOr<std::vector<const proto_ns::MessageLite*>>
ConvertToVectorOfProtoMessageLitePtrs(const T* data,
/*is_proto_vector=*/std::false_type) {
return absl::InvalidArgumentError(absl::StrCat(
"The Packet stores \"", kTypeId<T>.name(), "\"",
"which is not convertible to vector<proto_ns::MessageLite*>."));
}
template <typename T>
StatusOr<std::vector<const proto_ns::MessageLite*>>
ConvertToVectorOfProtoMessageLitePtrs(const T* data,
/*is_proto_vector=*/std::true_type) {
std::vector<const proto_ns::MessageLite*> result;
for (auto it = data->begin(); it != data->end(); ++it) {
const proto_ns::MessageLite* element = &(*it);
result.push_back(element);
}
return result;
}
// This registry is used to create Holders of the right concrete C++ type given
// a proto type string (which is used as the registration key).
class MessageHolderRegistry
: public GlobalFactoryRegistry<std::unique_ptr<HolderBase>> {};
template <typename T>
struct is_concrete_proto_t
: public std::integral_constant<
bool, std::is_base_of<proto_ns::MessageLite, T>{} &&
!std::is_same<proto_ns::MessageLite, T>{} &&
!std::is_same<proto_ns::Message, T>{}> {};
// Registers a message type. T must be a non-cv-qualified concrete proto type.
template <typename T>
struct MessageRegistrationImpl {
static NoDestructor<mediapipe::RegistrationToken> registration;
// This could have been a lambda inside registration's initializer below, but
// MSVC has a bug with lambdas, so we put it here as a workaround.
static std::unique_ptr<Holder<T>> CreateMessageHolder() {
return absl::make_unique<Holder<T>>(new T);
}
};
// Static members of template classes can be defined in the header.
template <typename T>
NoDestructor<mediapipe::RegistrationToken>
MessageRegistrationImpl<T>::registration(MessageHolderRegistry::Register(
T{}.GetTypeName(), MessageRegistrationImpl<T>::CreateMessageHolder,
__FILE__, __LINE__));
// For non-Message payloads, this does nothing.
template <typename T, typename Enable = void>
struct HolderSupport {
static void EnsureStaticInit() {}
};
// This template ensures that, for each concrete MessageLite subclass that is
// stored in a Packet, we register a function that allows us to create a
// Holder with the correct payload type from the proto's type name.
template <typename T>
struct HolderSupport<T,
typename std::enable_if<is_concrete_proto_t<T>{}>::type> {
// We must use std::remove_cv to ensure we don't try to register Foo twice if
// there are Holder<Foo> and Holder<const Foo>. TODO: lift this
// up to Holder?
using R = MessageRegistrationImpl<typename std::remove_cv<T>::type>;
// For the registration static member to be instantiated, it needs to be
// referenced in a context that requires the definition to exist (see ISO/IEC
// C++ 2003 standard, 14.7.1). Calling this ensures that's the case.
// We need two different call-sites to cover proto types for which packets
// are only ever created (i.e. the protos are only produced by calculators)
// and proto types for which packets are only ever consumed (i.e. the protos
// are only consumed by calculators).
static void EnsureStaticInit() { CHECK(R::registration.get() != nullptr); }
};
template <typename T>
class Holder : public HolderBase {
public:
explicit Holder(const T* ptr) : ptr_(ptr) {
HolderSupport<T>::EnsureStaticInit();
}
~Holder() override { delete_helper(); }
const T& data() const {
HolderSupport<T>::EnsureStaticInit();
return *ptr_;
}
TypeId GetTypeId() const final { return kTypeId<T>; }
// Releases the underlying data pointer and transfers the ownership to a
// unique pointer.
// This method is dangerous and is only used by Packet::Consume() if the
// packet is the only owner of the holder.
template <typename U = T>
absl::StatusOr<std::unique_ptr<T>> Release(
typename std::enable_if<!std::is_array<U>::value ||
std::extent<U>::value != 0>::type* = 0) {
if (HasForeignOwner()) {
return InternalError(
"Foreign holder can't release data ptr without ownership.");
}
// Casts away constness to make the data mutable after the release.
std::unique_ptr<T> data_ptr(const_cast<T*>(ptr_));
ptr_ = nullptr;
return std::move(data_ptr);
}
// TODO: support unbounded array after fixing the bug in holder's
// delete helper.
template <typename U = T>
absl::StatusOr<std::unique_ptr<T>> Release(
typename std::enable_if<std::is_array<U>::value &&
std::extent<U>::value == 0>::type* = 0) {
return absl::InternalError("Release T[] isn't supported.");
}
const std::string DebugTypeName() const final {
return MediaPipeTypeStringOrDemangled<T>();
}
const std::string RegisteredTypeName() const final {
const std::string* type_string = MediaPipeTypeString<T>();
if (type_string) {
return *type_string;
}
return "";
}
protected:
// The pointer that uniquely owns the data. However, the ownership of the
// Holder itself may be shared by several Packets.
const T* ptr_;
// Returns the MessageLite pointer to the data, if the underlying object type
// is protocol buffer, otherwise, nullptr is returned.
const proto_ns::MessageLite* GetProtoMessageLite() override {
return ConvertToProtoMessageLite(
ptr_, std::is_base_of<proto_ns::MessageLite, T>());
}
// Returns a vector<MessageLite*> for the data in the holder, if the
// underlying object is a vector of protocol buffer objects, otherwise,
// returns an error.
StatusOr<std::vector<const proto_ns::MessageLite*>>
GetVectorOfProtoMessageLite() const override {
return ConvertToVectorOfProtoMessageLitePtrs(ptr_, is_proto_vector<T>());
}
private:
// Call delete[] if T is an array, delete otherwise.
template <typename U = T>
inline void delete_helper(
typename std::enable_if<!std::is_array<U>::value>::type* = 0) {
delete ptr_;
}
template <typename U = T>
inline void delete_helper(
typename std::enable_if<std::is_array<U>::value>::type* = 0) {
// Casts ptr_ from const Type(*)[] or const Type(*)[N] to const Type*.
// Deleting a pointer to incomplete type (Type(*)[]) causes compile error.
delete[] reinterpret_cast<const typename std::remove_extent<U>::type*>(
ptr_);
}
};
// Like Holder, but does not own its data.
template <typename T>
class ForeignHolder : public Holder<T> {
public:
using Holder<T>::Holder;
~ForeignHolder() override {
// Null out ptr_ so it doesn't get deleted by ~Holder.
// Note that ~Holder cannot call HasForeignOwner because the subclass's
// destructor runs first.
this->ptr_ = nullptr;
}
bool HasForeignOwner() const final { return true; }
};
template <typename T>
Holder<T>* HolderBase::As() {
if (PayloadIsOfType<T>()) {
return static_cast<Holder<T>*>(this);
}
// Does not hold a T.
return nullptr;
}
template <typename T>
const Holder<T>* HolderBase::As() const {
if (PayloadIsOfType<T>()) {
return static_cast<const Holder<T>*>(this);
}
// Does not hold a T.
return nullptr;
}
} // namespace packet_internal
inline Packet::Packet(const Packet& packet)
: holder_(packet.holder_), timestamp_(packet.timestamp_) {
VLOG(4) << "Using copy constructor of " << packet.DebugString();
}
inline Packet& Packet::operator=(const Packet& packet) {
VLOG(4) << "Using copy assignment operator of " << packet.DebugString();
if (this != &packet) {
holder_ = packet.holder_;
timestamp_ = packet.timestamp_;
}
return *this;
}
template <typename T>
inline absl::StatusOr<std::unique_ptr<T>> Packet::Consume() {
// If type validation fails, returns error.
MP_RETURN_IF_ERROR(ValidateAsType<T>());
// Clients who use this function are responsible for ensuring that no
// other thread is doing anything with this Packet.
if (!holder_->HasForeignOwner() && holder_.unique()) {
VLOG(2) << "Consuming the data of " << DebugString();
absl::StatusOr<std::unique_ptr<T>> release_result =
holder_->As<T>()->Release();
if (release_result.ok()) {
VLOG(2) << "Setting " << DebugString() << " to empty.";
holder_.reset();
}
return release_result;
}
// If packet isn't the sole owner of the holder, returns kFailedPrecondition
// error with message.
return absl::Status(absl::StatusCode::kFailedPrecondition,
"Packet isn't the sole owner of the holder.");
}
template <typename T>
inline absl::StatusOr<std::unique_ptr<T>> Packet::ConsumeOrCopy(
bool* was_copied,
typename std::enable_if<!std::is_array<T>::value>::type*) {
MP_RETURN_IF_ERROR(ValidateAsType<T>());
// If holder is the sole owner of the underlying data, consumes this packet.
if (!holder_->HasForeignOwner() && holder_.unique()) {
VLOG(2) << "Consuming the data of " << DebugString();
absl::StatusOr<std::unique_ptr<T>> release_result =
holder_->As<T>()->Release();
if (release_result.ok()) {
VLOG(2) << "Setting " << DebugString() << " to empty.";
holder_.reset();
}
if (was_copied) {
*was_copied = false;
}
return release_result;
}
VLOG(2) << "Copying the data of " << DebugString();
std::unique_ptr<T> data_ptr = absl::make_unique<T>(Get<T>());
VLOG(2) << "Setting " << DebugString() << " to empty.";
holder_.reset();
if (was_copied) {
*was_copied = true;
}
return std::move(data_ptr);
}
template <typename T>
inline absl::StatusOr<std::unique_ptr<T>> Packet::ConsumeOrCopy(
bool* was_copied,
typename std::enable_if<std::is_array<T>::value &&
std::extent<T>::value != 0>::type*) {
MP_RETURN_IF_ERROR(ValidateAsType<T>());
// If holder is the sole owner of the underlying data, consumes this packet.
if (!holder_->HasForeignOwner() && holder_.unique()) {
VLOG(2) << "Consuming the data of " << DebugString();
absl::StatusOr<std::unique_ptr<T>> release_result =
holder_->As<T>()->Release();
if (release_result.ok()) {
VLOG(2) << "Setting " << DebugString() << " to empty.";
holder_.reset();
}
if (was_copied) {
*was_copied = false;
}
return release_result;
}
VLOG(2) << "Copying the data of " << DebugString();
const auto& original_array = Get<T>();
// Type T is bounded array type, such as int[N] and float[M].
// The new operator creates a new bounded array.
std::unique_ptr<T> data_ptr(reinterpret_cast<T*>(new T));
// Copies bounded array data into data_ptr.
std::copy(std::begin(original_array), std::end(original_array),
std::begin(*data_ptr));
VLOG(2) << "Setting " << DebugString() << " to empty.";
holder_.reset();
if (was_copied) {
*was_copied = true;
}
return std::move(data_ptr);
}
template <typename T>
inline absl::StatusOr<std::unique_ptr<T>> Packet::ConsumeOrCopy(
bool* was_copied,
typename std::enable_if<std::is_array<T>::value &&
std::extent<T>::value == 0>::type*) {
return absl::InternalError("Unbounded array isn't supported.");
}
inline Packet::Packet(Packet&& packet) {
VLOG(4) << "Using move constructor of " << packet.DebugString();
holder_ = std::move(packet.holder_);
timestamp_ = packet.timestamp_;
packet.timestamp_ = Timestamp::Unset();
}
inline Packet& Packet::operator=(Packet&& packet) {
VLOG(4) << "Using move assignment operator of " << packet.DebugString();
if (this != &packet) {
holder_ = std::move(packet.holder_);
timestamp_ = packet.timestamp_;
packet.timestamp_ = Timestamp::Unset();
}
return *this;
}
inline bool Packet::IsEmpty() const { return holder_ == nullptr; }
inline TypeId Packet::GetTypeId() const {
CHECK(holder_);
return holder_->GetTypeId();
}
template <typename T>
inline const T& Packet::Get() const {
packet_internal::Holder<T>* holder = IsEmpty() ? nullptr : holder_->As<T>();
if (holder == nullptr) {
// Produce a good error message.
absl::Status status = ValidateAsType<T>();
LOG(FATAL) << "Packet::Get() failed: " << status.message();
}
return holder->data();
}
inline Timestamp Packet::Timestamp() const { return timestamp_; }
template <typename T>
Packet Adopt(const T* ptr) {
CHECK(ptr != nullptr);
return packet_internal::Create(new packet_internal::Holder<T>(ptr));
}
template <typename T>
Packet PointToForeign(const T* ptr) {
CHECK(ptr != nullptr);
return packet_internal::Create(new packet_internal::ForeignHolder<T>(ptr));
}
// Equal Packets refer to the same memory contents, like equal pointers.
inline bool operator==(const Packet& p1, const Packet& p2) {
return packet_internal::GetHolder(p1) == packet_internal::GetHolder(p2);
}
inline bool operator!=(const Packet& p1, const Packet& p2) {
return !(p1 == p2);
}
namespace packet_internal {
inline const std::shared_ptr<HolderBase>& GetHolderShared(
const Packet& packet) {
return packet.holder_;
}
inline std::shared_ptr<HolderBase> GetHolderShared(Packet&& packet) {
return std::move(packet.holder_);
}
} // namespace packet_internal
} // namespace mediapipe
#endif // MEDIAPIPE_FRAMEWORK_PACKET_H_