mirror of
https://github.com/pytorch/pytorch.git
synced 2025-10-20 21:14:14 +08:00
Summary: Closes https://github.com/caffe2/caffe2/pull/1260 Differential Revision: D5906739 Pulled By: Yangqing fbshipit-source-id: e482ba9ba60b5337d9165f28f7ec68d4518a0902
245 lines
7.0 KiB
C++
245 lines
7.0 KiB
C++
/**
|
|
* Copyright (c) 2016-present, Facebook, Inc.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#ifndef CAFFE2_CORE_BLOB_H_
|
|
#define CAFFE2_CORE_BLOB_H_
|
|
|
|
#include <cstddef>
|
|
#include <sstream>
|
|
#include <typeinfo>
|
|
#include <type_traits>
|
|
#include <vector>
|
|
|
|
#include "caffe2/core/blob_serializer_base.h"
|
|
#include "caffe2/core/common.h"
|
|
#include "caffe2/core/typeid.h"
|
|
#include "caffe2/core/logging.h"
|
|
#include "caffe2/proto/caffe2.pb.h"
|
|
|
|
namespace caffe2 {
|
|
|
|
/**
|
|
* @brief Blob is a general container that hosts a typed pointer.
|
|
*
|
|
* A Blob hosts a pointer as well as its type, and takes charge of deleting it
|
|
* properly when the blob is deallocated or re-allocated with a new type. A blob
|
|
* could contain anything, although the most common case is to contain a Tensor.
|
|
*/
|
|
class Blob {
|
|
public:
|
|
/**
|
|
* Initializes an empty Blob.
|
|
*/
|
|
Blob() : meta_(), pointer_(nullptr) {}
|
|
~Blob() { Reset(); }
|
|
|
|
Blob(Blob&& other) noexcept
|
|
: meta_(std::move(other.meta_)),
|
|
pointer_(std::move(other.pointer_)),
|
|
destroy_(std::move(other.destroy_)) {
|
|
other.meta_ = {};
|
|
other.pointer_ = nullptr;
|
|
other.destroy_ = nullptr;
|
|
}
|
|
|
|
Blob& operator=(Blob&& other) noexcept {
|
|
meta_ = std::move(other.meta_);
|
|
pointer_ = std::move(other.pointer_);
|
|
destroy_ = std::move(other.destroy_);
|
|
other.meta_ = {};
|
|
other.pointer_ = nullptr;
|
|
other.destroy_ = nullptr;
|
|
return *this;
|
|
}
|
|
|
|
/**
|
|
* Checks if the content stored in the blob is of type T.
|
|
*/
|
|
template <class T>
|
|
bool IsType() const { return meta_.Match<T>(); }
|
|
|
|
/**
|
|
* Returns the meta info of the blob.
|
|
*/
|
|
inline const TypeMeta& meta() const { return meta_; }
|
|
|
|
/**
|
|
* Returns a printable typename of the blob.
|
|
*/
|
|
inline const char* TypeName() const { return meta_.name(); }
|
|
|
|
/**
|
|
* @brief Gets the const reference of the stored object. The code checks if
|
|
* the stored object is of the desired type.
|
|
*/
|
|
template <class T>
|
|
const T& Get() const {
|
|
CAFFE_ENFORCE(IsType<T>(),
|
|
"wrong type for the Blob instance. Blob contains ",
|
|
meta_.name(), " while caller expects ", TypeMeta::Name<T>());
|
|
return *static_cast<const T*>(pointer_);
|
|
}
|
|
|
|
const void* GetRaw() const {
|
|
return pointer_;
|
|
}
|
|
void* GetRaw() {
|
|
return pointer_;
|
|
}
|
|
|
|
/**
|
|
* @brief Gets a mutable pointer to the stored object.
|
|
*
|
|
* If the current object is not of the right type, a new object is created
|
|
* and the old object is freed. Note that type T should have a default
|
|
* constructor. Otherwise, create the object yourself first, and use
|
|
* Reset().
|
|
*/
|
|
template <class T>
|
|
T* GetMutable(bool* is_new_object=nullptr) {
|
|
if (IsType<T>()) {
|
|
if (is_new_object) *is_new_object = false;
|
|
return static_cast<T*>(pointer_);
|
|
} else {
|
|
if (is_new_object) *is_new_object = true;
|
|
VLOG(1) << "Create new mutable object " << TypeMeta::Name<T>();
|
|
return Reset<T>(new T());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets the underlying object to the allocated one. The Blob then takes over
|
|
* the ownership of the passed in pointer. If there is already an object in
|
|
* the Blob, the old object is freed.
|
|
*
|
|
* This is used when the underlying class T does not have a default ctor, or
|
|
* complex initializations needs to be done outside the blob.
|
|
*/
|
|
template <class T>
|
|
T* Reset(T* allocated) {
|
|
if (pointer_ && destroy_) {
|
|
destroy_(pointer_);
|
|
}
|
|
meta_ = TypeMeta::Make<T>();
|
|
pointer_ = static_cast<void*>(allocated);
|
|
destroy_ = &Destroy<T>;
|
|
return allocated;
|
|
}
|
|
|
|
/**
|
|
* Sets the underlying object to the allocated one, but does not take over
|
|
* the ownership of the passed in pointer. If there is already an object in
|
|
* the Blob, the old object is freed.
|
|
*
|
|
* Unlike Reset, this does not take over the ownership of the pointer and the
|
|
* caller is responsible for making sure that the lifetime of the allocated
|
|
* blob outlasts the lifetime of any access to this blob, until another Reset
|
|
* call is made or the blob is destructed.
|
|
*/
|
|
template <class T>
|
|
typename std::remove_const<T>::type* ShareExternal(
|
|
typename std::remove_const<T>::type* allocated) {
|
|
return static_cast<T*>(ShareExternal(
|
|
static_cast<void*>(allocated),
|
|
TypeMeta::Make<typename std::remove_const<T>::type>()));
|
|
}
|
|
|
|
void* ShareExternal(void* allocated, const TypeMeta& meta) {
|
|
if (pointer_ && destroy_) {
|
|
destroy_(pointer_);
|
|
}
|
|
meta_ = meta;
|
|
pointer_ = static_cast<void*>(allocated);
|
|
destroy_ = nullptr;
|
|
return allocated;
|
|
}
|
|
|
|
/**
|
|
* Resets the Blob to an empty one.
|
|
*/
|
|
inline void Reset() {
|
|
if (pointer_ && destroy_) {
|
|
destroy_(pointer_);
|
|
}
|
|
pointer_ = nullptr;
|
|
meta_ = TypeMeta();
|
|
destroy_ = nullptr;
|
|
}
|
|
|
|
/**
|
|
* Serializes the current blob, if possible. Note that this serialization uses
|
|
* the registration mechanism and one has to implement specific serialization
|
|
* approaches for specific classes. Acceptor should take care of writing data
|
|
* to the actual storage.
|
|
*/
|
|
void Serialize(
|
|
const string& name,
|
|
BlobSerializerBase::SerializationAcceptor acceptor,
|
|
int chunk_size = kDefaultChunkSize) const;
|
|
|
|
/**
|
|
* @brief Convenience function to serialize a blob to a string.
|
|
*
|
|
* This is a conveinence function to serialize small Blobs that produce
|
|
* manageable serialized strings. To serialize big blobs such as
|
|
* large sparse tensors, use the fully-functional interface in
|
|
* blob_serializer_base.h.
|
|
*
|
|
* NOTE: this function doesn't do chunking and might break with big tensors.
|
|
*/
|
|
string Serialize(const string& name) const;
|
|
|
|
/**
|
|
* @brief Swaps the underlying storage of two blobs.
|
|
*/
|
|
void swap(Blob& rhs) {
|
|
using std::swap;
|
|
swap(meta_, rhs.meta_);
|
|
swap(pointer_, rhs.pointer_);
|
|
swap(destroy_, rhs.destroy_);
|
|
}
|
|
|
|
/**
|
|
* Deserializes from a string containing either BlobProto or TensorProto. If
|
|
* the deserialization fails, the content in the blob should no longer be
|
|
* trusted.
|
|
*/
|
|
void Deserialize(const string& content);
|
|
void Deserialize(const BlobProto& proto);
|
|
|
|
private:
|
|
/**
|
|
* @brief A destroy call that is used to properly deconstruct objects.
|
|
*/
|
|
template <class T>
|
|
static void Destroy(void* pointer) {
|
|
delete static_cast<T*>(pointer);
|
|
}
|
|
typedef void (*DestroyCall)(void *);
|
|
TypeMeta meta_;
|
|
void* pointer_ = nullptr;
|
|
DestroyCall destroy_ = nullptr;
|
|
|
|
DISABLE_COPY_AND_ASSIGN(Blob);
|
|
};
|
|
|
|
inline void swap(Blob& lhs, Blob& rhs) {
|
|
lhs.swap(rhs);
|
|
}
|
|
|
|
} // namespace caffe2
|
|
#endif // CAFFE2_CORE_BLOB_H_
|