Move Blob to ATen/core (#11924)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/11924
Previous diffs removed Blob -> caffe2 dependencies, now we can move it to ATen/core.
This is pre-work for allowing storing Blob in IValue.
Reviewed By: ezyang
Differential Revision: D9980641
fbshipit-source-id: 32082a673ec94c42c20b2298adced8bb7ca94d07
diff --git a/aten/src/ATen/core/blob.cpp b/aten/src/ATen/core/blob.cpp
new file mode 100644
index 0000000..9302551
--- /dev/null
+++ b/aten/src/ATen/core/blob.cpp
@@ -0,0 +1 @@
+#include <ATen/core/blob.h>
diff --git a/aten/src/ATen/core/blob.h b/aten/src/ATen/core/blob.h
new file mode 100644
index 0000000..efe0774
--- /dev/null
+++ b/aten/src/ATen/core/blob.h
@@ -0,0 +1,235 @@
+#pragma once
+
+#include <cstddef>
+#include <sstream>
+#include <type_traits>
+#include <typeinfo>
+#include <vector>
+
+#include <ATen/core/typeid.h>
+#include <c10/macros/Macros.h>
+
+namespace caffe2 {
+
+class Tensor;
+
+/**
+ * @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 CAFFE2_API Blob final {
+ public:
+ using DestroyCall = void(void*);
+
+ /**
+ * Initializes an empty Blob.
+ */
+ Blob() noexcept : meta_(), pointer_(nullptr), destroy_(nullptr) {}
+ ~Blob() {
+ Reset();
+ }
+
+ Blob(Blob&& other) noexcept : Blob() {
+ swap(other);
+ }
+
+ Blob& operator=(Blob&& other) noexcept {
+ Blob(std::move(other)).swap(*this);
+ return *this;
+ }
+
+ /**
+ * Checks if the content stored in the blob is of type T.
+ */
+ template <class T>
+ bool IsType() const noexcept {
+ return meta_.Match<T>();
+ }
+
+ /**
+ * Returns the meta info of the blob.
+ */
+ inline const TypeMeta& meta() const noexcept {
+ return meta_;
+ }
+
+ /**
+ * Returns a printable typename of the blob.
+ */
+ inline const char* TypeName() const noexcept {
+ return meta_.name();
+ }
+
+ /**
+ * @brief Gets the const reference of the stored object. The code checks if
+ * the stored object is of the desired type.
+ */
+ // TODO(jerryzh): add a Get(DeviceType) function?
+ template <class T>
+ const T& Get() const {
+ AT_ASSERTM(
+ IsType<T>(),
+ "wrong type for the Blob instance. Blob contains ",
+ meta_.name(),
+ " while caller expects ",
+ TypeMeta::TypeName<T>());
+ // TODO: after we add Get<Tensor>(DeviceType)
+ // and changed all the callsites, we can add
+ // a static assert here to enforce T != Tensor
+ return *static_cast<const T*>(pointer_);
+ }
+
+ const void* GetRaw() const noexcept {
+ return pointer_;
+ }
+ void* GetRaw() noexcept {
+ 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() {
+ static_assert(
+ std::is_default_constructible<T>::value,
+ "GetMutable can't be called with non-default-constructible types. "
+ "Try using specialized methods");
+ if (IsType<T>()) {
+ return static_cast<T*>(pointer_);
+ } else {
+ // TODO Re-enable logging
+ // VLOG(1) << "Create new mutable object " << TypeMeta::TypeName<T>();
+ return Reset<T>(new T());
+ }
+ }
+
+ template <class T>
+ T* GetMutableOrNull() {
+ if (IsType<T>()) {
+ return static_cast<T*>(pointer_);
+ } else {
+ return nullptr;
+ }
+ }
+
+ /**
+ * 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;
+ }
+
+ inline void* Reset(
+ void* allocated,
+ const TypeMeta& meta,
+ DestroyCall* destroy) {
+ if (pointer_ && destroy_) {
+ destroy_(pointer_);
+ }
+ meta_ = meta;
+ pointer_ = static_cast<void*>(allocated);
+ destroy_ = destroy;
+ return allocated;
+ }
+
+ /**
+ * Releases the ownership, if any, this Blob has on the underlying pointer.
+ * The user is then responsible for freeing the data if needed
+ */
+ inline DestroyCall* Release() {
+ DestroyCall* d = destroy_;
+ destroy_ = nullptr;
+ return d;
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * @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_);
+ }
+
+ 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);
+ }
+ TypeMeta meta_;
+ void* pointer_ = nullptr;
+ DestroyCall* destroy_ = nullptr;
+
+ C10_DISABLE_COPY_AND_ASSIGN(Blob);
+};
+
+inline void swap(Blob& lhs, Blob& rhs) {
+ lhs.swap(rhs);
+}
+
+} // namespace caffe2
diff --git a/caffe2/core/blob.h b/caffe2/core/blob.h
index def0f1b..e09a54c 100644
--- a/caffe2/core/blob.h
+++ b/caffe2/core/blob.h
@@ -8,224 +8,13 @@
#include <vector>
#include "caffe2/core/common.h"
+#include <ATen/core/blob.h>
#include <ATen/core/typeid.h>
#include "caffe2/core/logging.h"
#include "caffe2/core/tensor.h"
namespace caffe2 {
-class Tensor;
-
-/**
- * @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 CAFFE2_API Blob final {
- public:
- using DestroyCall = void(void*);
-
- /**
- * Initializes an empty Blob.
- */
- Blob() noexcept : meta_(), pointer_(nullptr), destroy_(nullptr) {}
- ~Blob() { Reset(); }
-
- Blob(Blob&& other) noexcept : Blob() {
- swap(other);
- }
-
- Blob& operator=(Blob&& other) noexcept {
- Blob(std::move(other)).swap(*this);
- return *this;
- }
-
- /**
- * Checks if the content stored in the blob is of type T.
- */
- template <class T>
- bool IsType() const noexcept {
- return meta_.Match<T>();
- }
-
- /**
- * Returns the meta info of the blob.
- */
- inline const TypeMeta& meta() const noexcept { return meta_; }
-
- /**
- * Returns a printable typename of the blob.
- */
- inline const char* TypeName() const noexcept { return meta_.name(); }
-
- /**
- * @brief Gets the const reference of the stored object. The code checks if
- * the stored object is of the desired type.
- */
- // TODO(jerryzh): add a Get(DeviceType) function?
- 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::TypeName<T>());
- // TODO: after we add Get<Tensor>(DeviceType)
- // and changed all the callsites, we can add
- // a static assert here to enforce T != Tensor
- return *static_cast<const T*>(pointer_);
- }
-
- const void* GetRaw() const noexcept {
- return pointer_;
- }
- void* GetRaw() noexcept {
- 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() {
- static_assert(
- std::is_default_constructible<T>::value,
- "GetMutable can't be called with non-default-constructible types. "
- "Try using specialized methods");
- if (IsType<T>()) {
- return static_cast<T*>(pointer_);
- } else {
- VLOG(1) << "Create new mutable object " << TypeMeta::TypeName<T>();
- return Reset<T>(new T());
- }
- }
-
- template <class T>
- T* GetMutableOrNull() {
- if (IsType<T>()) {
- return static_cast<T*>(pointer_);
- } else {
- return nullptr;
- }
- }
-
- /**
- * 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;
- }
-
- inline void*
- Reset(void* allocated, const TypeMeta& meta, DestroyCall* destroy) {
- if (pointer_ && destroy_) {
- destroy_(pointer_);
- }
- meta_ = meta;
- pointer_ = static_cast<void*>(allocated);
- destroy_ = destroy;
- return allocated;
- }
-
- /**
- * Releases the ownership, if any, this Blob has on the underlying pointer.
- * The user is then responsible for freeing the data if needed
- */
- inline DestroyCall* Release() {
- DestroyCall* d = destroy_;
- destroy_ = nullptr;
- return d;
- }
-
- /**
- * 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;
- }
-
- /**
- * @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_);
- }
-
- 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);
- }
- TypeMeta meta_;
- void* pointer_ = nullptr;
- DestroyCall* destroy_ = nullptr;
-
- C10_DISABLE_COPY_AND_ASSIGN(Blob);
-};
-
-inline void swap(Blob& lhs, Blob& rhs) {
- lhs.swap(rhs);
-}
-
inline bool BlobIsTensorType(const Blob& blob, DeviceType device_type) {
bool is_match = blob.meta().Match<Tensor>();
if (!is_match) {