text: //
  //  Tensor.hpp
  //  MNN
  //
  //  Created by MNN on 2018/08/14.
  //  Copyright © 2018, Alibaba Group Holding Limited
  //
  
  #ifndef Tensor_hpp
  #define Tensor_hpp
  
  #include <vector>
  #include <MNN/HalideRuntime.h>
  #include <MNN/MNNDefine.h>
  #define MNN_MAX_TENSOR_DIM 6
  
  namespace MNN {
  
  /**
   * data container.
   * data for host tensor is saved in `host` field. its memory is allocated malloc directly.
   * data for device tensor is saved in `deviceId` field. its memory is allocated by session's backend.
   * usually, device tensors are created by engine (like net, session).
   * meanwhile, host tensors could be created by engine or user.
   */
  class MNN_PUBLIC Tensor {
  public:
      struct InsideDescribe;
  
      /** dimension type used to create tensor */
      enum DimensionType {
          /** for tensorflow net type. uses NHWC as data format. */
          TENSORFLOW,
          /** for caffe net type. uses NCHW as data format. */
          CAFFE,
          /** for caffe net type. uses NC4HW4 as data format. */
          CAFFE_C4
      };
  
      /** handle type */
      enum HandleDataType {
          /** default handle type */
          HANDLE_NONE = 0,
          /** string handle type */
          HANDLE_STRING = 1
      };
      
      /** Tensor map type : Read or Write*/
      enum MapType {
          /** map Tensor for writing data*/
          MAP_TENSOR_WRITE = 0,
          MAP_TENSOR_READ = 1
      };
  
  public:
      /**
       * @brief create a tensor with dimension size and type without acquire memory for data.
       * @param dimSize   dimension size.
       * @param type      dimension type.
       */
      Tensor(int dimSize = 4, DimensionType type = CAFFE);
  
      /**
       * @brief create a tensor with same shape as given tensor.
       * @param tensor        shape provider.
       * @param type          dimension type.
       * @param allocMemory   acquire memory for data or not.
       * @warning tensor data won't be copied.
       */
      Tensor(const Tensor* tensor, DimensionType type = CAFFE, bool allocMemory = true);
  
      /** deinitializer */
      ~Tensor();
  
  private:
      Tensor(bool deepCopy, const Tensor* tensor);
      // remove all assignment operator
      Tensor(const Tensor& tensor)  = delete;
      Tensor(const Tensor&& tensor) = delete;
      Tensor& operator=(const Tensor&) = delete;
      Tensor& operator=(const Tensor&&) = delete;
  
  public:
      /**
       * @brief create tensor with shape, data type and dimension type.
       * @param shape     tensor shape.
       * @param type      data type.
       * @param dimType   dimension type.
       * @return created tensor.
       * @warning memory for data won't be acquired. call backend's onAcquireBuffer to get memory ready.
       */
      static Tensor* createDevice(const std::vector<int>& shape, halide_type_t type, DimensionType dimType = TENSORFLOW);
  
      /**
       * @brief create tensor with shape and dimension type. data type is represented by `T`.
       * @param shape     tensor shape.
       * @param dimType   dimension type.
       * @return created tensor.
       * @warning memory for data won't be acquired. call backend's onAcquireBuffer to get memory ready.
       */
      template <typename T>
      static Tensor* createDevice(const std::vector<int>& shape, DimensionType dimType = TENSORFLOW) {
          return createDevice(shape, halide_type_of<T>(), dimType);
      }
  
      /**
       * @brief create tensor with shape, data type, data and dimension type.
       * @param shape     tensor shape.
       * @param type      data type.
       * @param data      data to save.
       * @param dimType   dimension type.
       * @return created tensor.
       */
      static Tensor* create(const std::vector<int>& shape, halide_type_t type, void* data = NULL,
                            DimensionType dimType = TENSORFLOW);
  
      /**
       * @brief create tensor with shape, data and dimension type. data type is represented by `T`.
       * @param shape     tensor shape.
       * @param data      data to save.
       * @param dimType   dimension type.
       * @return created tensor.
       */
      template <typename T>
      static Tensor* create(const std::vector<int>& shape, void* data = NULL, DimensionType dimType = TENSORFLOW) {
          return create(shape, halide_type_of<T>(), data, dimType);
      }
  
      /**
       * @brief copy tensor.
       * @param src     tensor
       * @param deepCopy whether create new content and copy, currently only support deepCopy = false
       */
      static Tensor* clone(const Tensor* src, bool deepCopy = false);
  public:
      /**
       * @brief for DEVICE tensor, copy data from given host tensor.
       * @param hostTensor    host tensor, the data provider.
       * @return true for DEVICE tensor, and false for HOST tensor.
       */
      bool copyFromHostTensor(const Tensor* hostTensor);
  
      /**
       * @brief for DEVICE tensor, copy data to given host tensor.
       * @param hostTensor    host tensor, the data consumer.
       * @return true for DEVICE tensor, and false for HOST tensor.
       */
      bool copyToHostTensor(Tensor* hostTensor) const;
  
      /**
       * @brief create HOST tensor from DEVICE tensor, with or without data copying.
       * @param deviceTensor  given device tensor.
       * @param copyData      copy data or not.
       * @return created host tensor.
       */
      static Tensor* createHostTensorFromDevice(const Tensor* deviceTensor, bool copyData = true);
  
  public:
      const halide_buffer_t& buffer() const {
          return mBuffer;
      }
      halide_buffer_t& buffer() {
          return mBuffer;
      }
  
      /**
       * @brief get dimension type.
       * @return dimension type.
       */
      DimensionType getDimensionType() const;
  
      /**
       * @brief handle data type. used when data type code is halide_type_handle.
       * @return handle data type.
       */
      HandleDataType getHandleDataType() const;
  
      /**
       * @brief set data type.
       * @param type data type defined in 'Type_generated.h'.
       */
      void setType(int type);
  
      /**
       * @brief get data type.
       * @return data type.
       */
      inline halide_type_t getType() const {
          return mBuffer.type;
      }
  
      /**
       * @brief visit host memory, data type is represented by `T`.
       * @return data point in `T` type.
       */
      template <typename T>
      T* host() const {
          return (T*)mBuffer.host;
      }
  
      /**
       * @brief visit device memory.
       * @return device data ID. what the ID means varies between backends.
       */
      uint64_t deviceId() const {
          return mBuffer.device;
      }
  
  public:
      int dimensions() const {
          return mBuffer.dimensions;
      }
  
      /**
       * @brief get all dimensions' extent.
       * @return dimensions' extent.
       */
      std::vector<int> shape() const;
  
      /**
       * @brief calculate number of bytes needed to store data taking reordering flag into account.
       * @return bytes needed to store data
       */
      int size() const;
  
      /**
       * @brief calculate number of elements needed to store data taking reordering flag into account.
       * @return elements needed to store data
       */
      inline int elementSize() const {
          return size() / mBuffer.type.bytes();
      }
  
  public:
      inline int width() const {
          if (getDimensionType() == TENSORFLOW) {
              return mBuffer.dim[2].extent;
          }
  
          return mBuffer.dim[3].extent;
      }
      inline int height() const {
          if (getDimensionType() == TENSORFLOW) {
              return mBuffer.dim[1].extent;
          }
          return mBuffer.dim[2].extent;
      }
      inline int channel() const {
          if (getDimensionType() == TENSORFLOW) {
              return mBuffer.dim[3].extent;
          }
          return mBuffer.dim[1].extent;
      }
      inline int batch() const {
          return mBuffer.dim[0].extent;
      }
  
      // visit dimension's extent & stride
      inline int stride(int index) const {
          return mBuffer.dim[index].stride;
      }
      inline int length(int index) const {
          return mBuffer.dim[index].extent;
      }
      inline void setStride(int index, int stride) {
          mBuffer.dim[index].stride = stride;
      }
      inline void setLength(int index, int length) {
          mBuffer.dim[index].extent = length;
      }
  
  public:
      /**
       * @brief print tensor data. for DEBUG use only.
       */
      void print() const;
      
      /**
       *@brief print tensor shape
       */
      void printShape() const;
  
  public:
      /**
       * @brief map/umap GPU Tensor, to get host ptr
       */
      void* map(MapType mtype, DimensionType dtype);
      void unmap(MapType mtype, DimensionType dtype, void* mapPtr);
      
  private:
      halide_buffer_t mBuffer;
      struct InsideDescribe* mDescribe;
  
  private:
      friend class TensorUtils;
  };
  } // namespace MNN
  
  #endif /* Tensor_hpp */
  