#pragma once
#include "ATen/Type.h"
#include "ATen/Context.h"
#include "ATen/TensorMethods.h"
#include "ATen/CheckGenerator.h"

#ifdef _MSC_VER
#ifdef Type
#undef Type
#endif
#endif

namespace at {

struct CPUHalfType final : public Type {
  explicit CPUHalfType(Context* context);
  virtual ScalarType scalarType() const override;
  virtual Backend backend() const override;
  virtual bool isCuda() const override;
  virtual bool isSparse() const override;
  virtual bool isDistributed() const override;
  virtual std::unique_ptr<Storage> storage() const override;
  virtual std::unique_ptr<Storage> storage(size_t size) const override;
  virtual std::unique_ptr<Storage> storageFromBlob(void * data, int64_t size, const std::function<void(void*)> & deleter) const override;
  virtual std::unique_ptr<Generator> generator() const override;
  virtual const char * toString() const override;
  virtual std::size_t elementSizeInBytes() const override;
  virtual TypeID ID() const override;
  static const char * typeString();
  Tensor unsafeTensorFromTH(void * th_pointer, bool retain) const override;

  // example
  // virtual Tensor * add(Tensor & a, Tensor & b) override;

  virtual void s_copy(const Tensor & src, Tensor & dst) const override;
  virtual int64_t m_storage_offset(const Tensor & self) const override;
  virtual Tensor & m_resize_(Tensor & self, IntList size) const override;
  virtual int64_t numel(const Tensor & self) const override;
  virtual Tensor & m_set_(Tensor & self, Storage & storage) const override;
  virtual Tensor & m_set_(Tensor & self, Storage & sourceStorage, int64_t storage_offset, IntList size, IntList stride) const override;
  virtual Tensor & m_set_(Tensor & self, const Tensor & source) const override;
  virtual Tensor & m_set_(Tensor & self) const override;
  virtual bool m_is_contiguous(const Tensor & self) const override;
  virtual bool m_is_set_to(const Tensor & self, const Tensor & tensor) const override;
  virtual Tensor transpose(const Tensor & self, int64_t dim0, int64_t dim1) const override;
  virtual Tensor & m_transpose_(Tensor & self, int64_t dim0, int64_t dim1) const override;
  virtual Tensor & squeeze_out(Tensor & result, const Tensor & self, int64_t dim) const override;
  virtual Tensor squeeze(const Tensor & self, int64_t dim) const override;
  virtual Tensor & squeeze_out(Tensor & result, const Tensor & self) const override;
  virtual Tensor squeeze(const Tensor & self) const override;
  virtual Tensor & m_squeeze_(Tensor & self, int64_t dim) const override;
  virtual Tensor & m_squeeze_(Tensor & self) const override;
  virtual Tensor & unsqueeze_out(Tensor & result, const Tensor & self, int64_t dim) const override;
  virtual Tensor unsqueeze(const Tensor & self, int64_t dim) const override;
  virtual Tensor & m_unsqueeze_(Tensor & self, int64_t dim) const override;
  virtual Tensor m_narrow(const Tensor & self, int64_t dimension, int64_t start, int64_t length) const override;
  virtual Tensor m_unfold(const Tensor & self, int64_t dimension, int64_t size, int64_t step) const override;
  virtual void* m_data_ptr(const Tensor & self) const override;
  virtual int64_t m_size(const Tensor & self, int64_t dim) const override;
  virtual int64_t m_stride(const Tensor & self, int64_t dim) const override;
  virtual Tensor tensor(Storage & storage, int64_t storageOffset, IntList size, IntList stride) const override;
  virtual Tensor tensor(IntList size) const override;
  virtual Tensor tensor(IntList size, IntList stride) const override;
  virtual Tensor tensor() const override;
  virtual Tensor alias(const Tensor & tensor) const override;
  virtual Tensor & select_out(Tensor & result, const Tensor & self, int64_t dim, int64_t sliceIndex) const override;
  virtual Tensor select(const Tensor & self, int64_t dim, int64_t sliceIndex) const override;
  virtual Tensor & m_assign_(Tensor & self, const Tensor & src) const override;
  virtual Tensor & m_reshape_(Tensor & self, IntList size, IntList stride) const override;
};

} // namespace at
