/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 TVM_SUPPORT_ARRAY_H_
#define TVM_SUPPORT_ARRAY_H_
#include <tvm/ffi/container/array.h>
#include <tvm/ir/expr.h>

#include <list>
#include <vector>

namespace tvm {
namespace support {

/*!
 * \brief Checks if two arrays contain the same objects
 * \tparam T The type of objects in the array
 * \param a The first array
 * \param b The second array
 * \return A boolean indicating if they are the same
 */
template <class T>
inline bool ArrayWithSameContent(const ffi::Array<T>& a, const ffi::Array<T>& b) {
  if (a.size() != b.size()) {
    return false;
  }
  int n = a.size();
  for (int i = 0; i < n; ++i) {
    if (!a[i].same_as(b[i])) {
      return false;
    }
  }
  return true;
}

/*!
 * \brief Checks if two arrays contain the same objects
 * \tparam T The type of objects in the array
 * \param a The first array
 * \param b The second array
 * \return A boolean indicating if they are the same
 */
template <class T>
inline bool ArrayWithSameContent(const std::vector<T*>& a, const std::vector<T*>& b) {
  if (a.size() != b.size()) {
    return false;
  }
  int n = a.size();
  for (int i = 0; i < n; ++i) {
    if (a[i] != b[i]) {
      return false;
    }
  }
  return true;
}

/*!
 * \brief Convert a tvm::Array to std::vector
 * \tparam TSrc The type of elements in the source Array
 * \tparam TDst The type of elements in the result vector
 * \return The result vector
 */
template <class TSrc, class TDst>
inline std::vector<TDst> AsVector(const ffi::Array<TSrc>& vec);

/*!
 * \brief Convert a std::vector to tvm::Array
 * \tparam TSrc The type of elements in the source vector
 * \tparam TDst The type of elements in the result Array
 * \return The result Array
 */
template <class TSrc, class TDst>
inline ffi::Array<TDst> AsArray(const std::vector<TSrc>& vec);

/*!
 * \brief Convert a tvm::Array to std::list
 * \tparam T The type of elements in the source array
 * \return The result list
 */
template <class T>
inline std::list<T> AsList(const ffi::Array<T>& array) {
  std::list<T> list;
  for (const auto& v : array) list.push_back(v);
  return list;
}

/*!
 * \brief Convert a std::list to tvm::Array
 * \tparam T The type of elements in the source list
 * \return The result list
 */
template <class T>
inline ffi::Array<T> AsArray(const std::list<T>& list) {
  ffi::Array<T> array;
  for (const auto& v : list) array.push_back(v);
  return array;
}

/*!
 * \brief Get the shape tuple as array
 * \param shape The shape tuple
 * \return An array of the shape tuple
 */
inline ffi::Array<Integer> AsArray(const ffi::Shape& shape) {
  ffi::Array<Integer> result;
  result.reserve(shape->size);
  for (ffi::Shape::index_type i : shape) {
    result.push_back(Integer(i));
  }
  return result;
}

/*!
 * \brief Concatenate a list of arrays into a single array
 * \tparam T The type of elements in the arrays
 * \tparam Iterator The type of the iterator into the list of arrays
 * \param begin The begin iterator to the array list
 * \param end The end iterator to the array list
 * \return The concatenated array
 */
template <class T, class Iterator>
inline ffi::Array<T> ConcatArrayList(Iterator begin, Iterator end) {
  int size = 0;
  for (Iterator it = begin; it != end; ++it) {
    size += (*it).size();
  }
  ffi::Array<T> result;
  result.reserve(size);
  for (Iterator it = begin; it != end; ++it) {
    const auto& item = *it;
    result.insert(result.end(), item.begin(), item.end());
  }
  return result;
}

/********** Implementation details of AsVector<TSrc, TDst> **********/

namespace details {

template <class TSrc, class TDst>
struct AsVectorImpl {};

template <class TSrc>
struct AsVectorImpl<TSrc, TSrc> {
  inline std::vector<TSrc> operator()(const ffi::Array<TSrc>& vec) const {
    return std::vector<TSrc>(vec.begin(), vec.end());
  }
};

template <class TSrcObjectRef>
struct AsVectorImpl<TSrcObjectRef, int> {
  inline std::vector<int> operator()(const ffi::Array<TSrcObjectRef>& array) const {
    ffi::Any ret_value;
    ret_value = array;
    ffi::Array<IntImm> as_int_vec = ret_value.cast<ffi::Array<IntImm>>();

    std::vector<int> results;
    for (const auto& value : as_int_vec) {
      results.push_back(value->value);
    }
    return results;
  }
};

template <class TSrcObjectRef>
struct AsVectorImpl<TSrcObjectRef, int64_t> {
  inline std::vector<int64_t> operator()(const ffi::Array<TSrcObjectRef>& array) const {
    ffi::Any ret_value;
    ret_value = array;
    ffi::Array<IntImm> as_int_vec = ret_value.cast<ffi::Array<IntImm>>();

    std::vector<int64_t> results;
    for (const auto& value : as_int_vec) {
      results.push_back(value->value);
    }
    return results;
  }
};

template <class TSrcObjectRef>
struct AsVectorImpl<TSrcObjectRef, double> {
  inline std::vector<double> operator()(const ffi::Array<TSrcObjectRef>& array) const {
    ffi::Any ret_value;
    ret_value = array;
    ffi::Array<FloatImm> as_int_vec = ret_value.cast<ffi::Array<FloatImm>>();

    std::vector<double> results;
    for (const auto& value : as_int_vec) {
      results.push_back(value->value);
    }
    return results;
  }
};
}  // namespace details

/********** Implementation details of AsArray<TSrc, TDst> **********/

namespace details {

template <class TSrc, class TDst>
struct AsArrayImpl {};

template <class TSrc>
struct AsArrayImpl<TSrc, TSrc> {
  inline ffi::Array<TSrc> operator()(const std::vector<TSrc>& vec) const {
    return ffi::Array<TSrc>(vec.begin(), vec.end());
  }
};

template <class TDstObjectRef>
struct AsArrayImpl<int, TDstObjectRef> {
  inline ffi::Array<TDstObjectRef> operator()(const std::vector<int>& vec) const {
    ffi::Array<TDstObjectRef> result;
    result.reserve(vec.size());
    for (auto x : vec) {
      ffi::Any ret_value;
      ret_value = x;
      result.push_back(ret_value.cast<TDstObjectRef>());
    }
    return result;
  }
};

template <class TDstObjectRef>
struct AsArrayImpl<int64_t, TDstObjectRef> {
  inline ffi::Array<TDstObjectRef> operator()(const std::vector<int64_t>& vec) const {
    ffi::Array<TDstObjectRef> result;
    result.reserve(vec.size());
    for (auto x : vec) {
      ffi::Any ret_value;
      ret_value = x;
      result.push_back(ret_value.cast<TDstObjectRef>());
    }
    return result;
  }
};

template <class TDstObjectRef>
struct AsArrayImpl<double, TDstObjectRef> {
  inline ffi::Array<TDstObjectRef> operator()(const std::vector<double>& vec) const {
    ffi::Array<TDstObjectRef> result;
    result.reserve(vec.size());
    for (auto x : vec) {
      ffi::Any ret_value;
      ret_value = x;
      result.push_back(ret_value.cast<TDstObjectRef>());
    }
    return result;
  }
};

}  // namespace details

template <class TSrc, class TDst>
inline std::vector<TDst> AsVector(const ffi::Array<TSrc>& vec) {
  return details::AsVectorImpl<TSrc, TDst>()(vec);
}

template <class TSrc, class TDst>
inline ffi::Array<TDst> AsArray(const std::vector<TSrc>& vec) {
  return details::AsArrayImpl<TSrc, TDst>()(vec);
}

}  // namespace support
}  // namespace tvm
#endif  // TVM_SUPPORT_ARRAY_H_
