#pragma once
#include <condition_variable>
#include <type_traits>
#include <ATen/core/Dict.h>
#include <ATen/core/List.h>
#include <ATen/core/functional.h>
#include <ATen/core/interned_strings.h>
#include <ATen/core/qualified_name.h>
#include <ATen/core/rref_interface.h>
#include <c10/core/Scalar.h>
#include <c10/core/Stream.h>
#include <c10/core/TensorImpl.h>
#include <c10/core/UndefinedTensorImpl.h>
#include <c10/util/intrusive_ptr.h>
#include <c10/util/hash.h>
namespace torch {
namespace jit {
struct Function;
struct CompilationUnit;
} // namespace jit
TORCH_API bool isCustomClass(const c10::IValue& v);
} // namespace torch
namespace c10 {
struct IValue;
struct ClassType;
struct TupleType;
struct EnumType;
struct InferredType;
// For custom class __init__ registration, we need to pass in a function
// that looks like this: [](IValue x, args...)
// However, make_boxed_from_unboxed_functor.h automatically sets the input types
// of the function by introspecting the types of the functor (which is IValue in
// this case). However, we need the type it binds to be Foo.
// Instead, we pass in a lambda [](ivalue_holder<CurClass> x, args...) from
// which getTypePtr can recover the original class pointer.
template <typename TaggedCapsuleType>
struct tagged_capsule {
IValue ivalue;
};
template <class T, class NullType>
c10::intrusive_ptr<T, NullType> IValue::moveToIntrusivePtr() {
auto t = c10::intrusive_ptr<T, NullType>::reclaim(
payload.u.as_intrusive_ptr == c10::UndefinedTensorImpl::singleton()
? NullType::singleton()
: static_cast<T*>(payload.u.as_intrusive_ptr));
clearToNone();
return t;
}
template <typename T, class NullType>
c10::intrusive_ptr<T, NullType> IValue::toIntrusivePtr() const {
auto r = c10::intrusive_ptr<T, NullType>::reclaim(
payload.u.as_intrusive_ptr == c10::UndefinedTensorImpl::singleton()
? NullType::singleton()
: static_cast<T*>(payload.u.as_intrusive_ptr));
auto p = r;
r.release();
return p;
}
template <class T, class U>
intrusive_ptr<T> static_intrusive_pointer_cast(intrusive_ptr<U> r) {
return intrusive_ptr<T>::reclaim(static_cast<T*>(r.release()));
}
template <class T, class U>
intrusive_ptr<T> dynamic_intrusive_pointer_cast(intrusive_ptr<U> r) {
return intrusive_ptr<T>::reclaim(dynamic_cast<T*>(r.release()));
}
inline c10::intrusive_ptr<ivalue::Future> IValue::toFuture() && {
AT_ASSERT(isFuture(), "Expected Future but got ", tagKind());
return moveToIntrusivePtr<ivalue::Future>();
}
inline c10::intrusive_ptr<ivalue::Future> IValue::toFuture() const& {
AT_ASSERT(isFuture(), "Expected Future but got ", tagKind());
return toIntrusivePtr<ivalue::Future>();
}
inline c10::intrusive_ptr<c10::RRefInterface> IValue::toRRef() && {
AT_ASSERT(isRRef(), "Expected RRef but got ", tagKind());
return moveToIntrusivePtr<c10::RRefInterface>();
}
inline c10::intrusive_ptr<c10::RRefInterface> IValue::toRRef() const& {
AT_ASSERT(isRRef(), "Expected RRef but got ", tagKind());
return toIntrusivePtr<c10::RRefInterface>();
}
inline c10::intrusive_ptr<at::Quantizer> IValue::toQuantizer() && {
AT_ASSERT(isQuantizer(), "Expected Quantizer but got ", tagKind());
return moveToIntrusivePtr<at::Quantizer>();
}
inline c10::intrusive_ptr<at::Quantizer> IValue::toQuantizer() const& {
AT_ASSERT(isQuantizer(), "Expected Quantizer but got ", tagKind());
return toIntrusivePtr<at::Quantizer>();
}
inline c10::intrusive_ptr<ivalue::ConstantString> IValue::toString() && {
AT_ASSERT(isString(), "Expected String but got ", tagKind());
return moveToIntrusivePtr<ivalue::ConstantString>();
}
inline c10::intrusive_ptr<ivalue::ConstantString> IValue::toString() const& {
AT_ASSERT(isString(), "Expected String but got ", tagKind());
return toIntrusivePtr<ivalue::ConstantString>();
}
inline c10::intrusive_ptr<ivalue::Object> IValue::toObject() && {
AT_ASSERT(isObject(), "Expected Object but got ", tagKind());
return moveToIntrusivePtr<ivalue::Object>();
}
inline c10::intrusive_ptr<ivalue::Object> IValue::toObject() const& {
AT_ASSERT(isObject(), "Expected Object but got ", tagKind());
return toIntrusivePtr<ivalue::Object>();
}
inline c10::intrusive_ptr<ivalue::PyObjectHolder> IValue::
toPyObjectHolder() && {
TORCH_INTERNAL_ASSERT(isPyObject(), "Expected PyObject but got ", tagKind());
return moveToIntrusivePtr<ivalue::PyObjectHolder>();
}
inline c10::intrusive_ptr<ivalue::PyObjectHolder> IValue::toPyObjectHolder()
const& {
TORCH_INTERNAL_ASSERT(isPyObject(), "Expected PyObject but got ", tagKind());
return toIntrusivePtr<ivalue::PyObjectHolder>();
}
inline c10::intrusive_ptr<ivalue::EnumHolder> IValue::toEnumHolder() && {
TORCH_INTERNAL_ASSERT(isEnum(), "Expected Enum but got ", tagKind());
return moveToIntrusivePtr<ivalue::EnumHolder>();
}
inline c10::intrusive_ptr<ivalue::EnumHolder> IValue::toEnumHolder() const& {
TORCH_INTERNAL_ASSERT(isEnum(), "Expected Enum but got ", tagKind());
return toIntrusivePtr<ivalue::EnumHolder>();
}
inline c10::complex<double> IValue::toComplexDouble() const {
TORCH_INTERNAL_ASSERT(isComplexDouble(), "Expected ComplexDouble but got ", tagKind());
auto ptr = toIntrusivePtr<ivalue::ComplexHolder>();
return (*ptr).val;
}
inline at::Tensor IValue::toTensor() && {
AT_ASSERT(isTensor(), "Expected Tensor but got ", tagKind());
auto result = std::move(payload.as_tensor);
// As far as I can tell, omitting the usual explicit destructor call
// is not UB in and of itself, and it's a slight perf win. The
// destructor is a no-op, because the moved-from Tensor is
// effectively an intrusive_ptr in the null state, so we don't need
// the behavior for correctness reasons either. Leaving this
// explanatory comment, including commented-out destructor call, to
// make this abundantly clear.
//
// payload.as_tensor.~Tensor();
clearToNone();
return result;
}
inline at::Tensor& IValue::toTensor() & {
AT_ASSERT(isTensor(), "Expected Tensor but got ", tagKind());
return payload.as_tensor;
}
inline const at::Tensor& IValue::toTensor() const& {
AT_ASSERT(isTensor(), "Expected Tensor but got ", tagKind());
return payload.as_tensor;
}
inline c10::Storage IValue::toStorage() && {
AT_ASSERT(isStorage(), "Expected Storage but got ", tagKind());
return c10::Storage(
moveToIntrusivePtr<at::StorageImpl>());
}
inline c10::Storage IValue::toStorage() const& {
AT_ASSERT(isStorage(), "Expected Storage but got ", tagKind());
return c10::Storage(toIntrusivePtr<at::StorageImpl>());
}
inline c10::Stream IValue::toStream() && {
return c10::Stream::unpack(payload.u.as_int);
}
inline c10::Stream IValue::toStream() const& {
return c10::Stream::unpack(payload.u.as_int);
}
inline c10::intrusive_ptr<caffe2::Blob> IValue::toBlob() && {
AT_ASSERT(isBlob(), "Expected Blob but got ", tagKind());
return moveToIntrusivePtr<caffe2::Blob>();
}
inline c10::intrusive_ptr<caffe2::Blob> IValue::toBlob() const& {
AT_ASSERT(isBlob(), "Expected Blob but got ", tagKind());
return toIntrusivePtr<caffe2::Blob>();
;
}
inline c10::intrusive_ptr<torch::CustomClassHolder> IValue::toCapsule() && {
TORCH_INTERNAL_ASSERT(isCapsule());
return moveToIntrusivePtr<torch::CustomClassHolder>();
}
inline c10::intrusive_ptr<torch::CustomClassHolder> IValue::toCapsule() const& {
TORCH_INTERNAL_ASSERT(isCapsule());
return toIntrusivePtr<torch::CustomClassHolder>();
}
inline at::Generator IValue::toGenerator() && {
AT_ASSERT(isGenerator(), "Expected Generator but got ", tagKind());
return at::Generator(moveToIntrusivePtr<at::GeneratorImpl>());
}
inline at::Generator IValue::toGenerator() const& {
AT_ASSERT(isGenerator(), "Expected Generator but got ", tagKind());
return at::Generator(toIntrusivePtr<at::GeneratorImpl>());
}
namespace ivalue {
void TORCH_API
checkCustomClassType(const Type* expected_type, const Type* actual_type);
template <typename T>
using Shared = c10::intrusive_ptr<T>;
// string
struct TORCH_API ConstantString final : c10::intrusive_ptr_target {
private:
const std::string str_;
public:
ConstantString(std::string str) : str_(std::move(str)) {}
static c10::intrusive_ptr<ConstantString> create(std::string str_);
const std::string& string() const {
return str_;
}
operator const std::string&() const {
return string();
}
TORCH_API friend std::ostream& operator<<(
std::ostream& out,
const ConstantString& v);
};
struct Future;
struct TORCH_API Tuple : c10::intrusive_ptr_target {
private:
std::vector<IValue> elements_;
mutable std::shared_ptr<TupleType>
type_; // lazily computed for unnamed tuples
public:
// named tuples have additional type information, so we
// directly create them tagged
static c10::intrusive_ptr<Tuple> createNamed(
std::vector<IValue> elements_,
std::shared_ptr<TupleType> type_) {
return c10::make_intrusive<Tuple>(std::move(elements_), type_);
}
static c10::intrusive_ptr<Tuple> create(std::vector<IValue> elements_) {
return c10::make_intrusive<Tuple>(std::move(elements_));
}
template <typename... Args>
static c10::intrusive_ptr<Tuple> create(Args... elements_) {
return c10::make_intrusive<Tuple>(
std::vector<IValue>{IValue(elements_)...});
}
const std::vector<IValue>& elements() const& {
return elements_;
}
operator const std::vector<IValue>&() const {
return elements();
}
std::vector<IValue>& elements() & {
return elements_;
}
operator std::vector<IValue>&() {
return elements();
}
std::vector<IValue>&& elements() && {
return std::move(elements_);
}
std::shared_ptr<TupleType> type() const;
static size_t hash(const Tuple& t) {
return c10::get_hash(t.elements());
}
TORCH_API friend bool operator==(
const ivalue::Tuple& lhs,
const ivalue::Tuple& rhs);
private:
Tuple(std::vector<IValue> elements, std::shared_ptr<TupleType> type = nullptr)
: elements_(std::move(elements)), type_(std::move(type)) {}
friend class c10::intrusive_ptr<Tuple>;
};
struct Object;
struct PyObjectHolder;
struct EnumHolder;
} // namespace ivalue
// Future
struct C10_EXPORT ivalue::Future : c10::intrusive_ptr_target {
private:
c10::intrusive_ptr<Future> intrusive_from_this() {
c10::raw::intrusive_ptr::incref(this); // we are creating a new pointer
// from a raw `this` pointer
// so we need to bump the refcount
// to account for this ownership
return c10::intrusive_ptr<Future>::reclaim(this);
}
public:
explicit Future(TypePtr type) : type_(type) {}
struct TORCH_API FutureError final : public std::exception {
explicit FutureError(std::string&& error_msg_)
: error_msg(std::move(error_msg_)) {}
FutureError() = default;
const char* what() const noexcept override {
return error_msg.c_str();
}
std::string error_msg;
};
/**
* Wait on the future until it completes.
*/
void wait() {
std::unique_lock<std::mutex> lock(mutex_);
while (!completed_) {
finished_cv_.wait(lock);
}
if (!eptr_) {
postWaitHook(value_);
}
}
/**
* Wait on the future until it completes and throw an
* exception if an error exists.
*/
void waitAndThrow() {
std::unique_lock<std::mutex> lock(mutex_);
while (!completed_) {
finished_cv_.wait(lock);
}
Loading ...