/**
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
 * CANN Open Software License Agreement Version 2.0 (the "License").
 * Please refer to the License for details. You may not use this file except in compliance with the License.
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
 * See LICENSE in the root of the software repository for the full text of the License.
 */

#include "acl_attr_utils.h"
#include <cmath>
#include "securec.h"

#include "mmpa/mmpa_api.h"
#include "common/log_inner.h"
#include "acl_hash_utils.h"

namespace {
constexpr float32_t FLOAT_DELTA = 1e-6F;
constexpr uint32_t FP16_MAX_EXP = 0x001FU;
constexpr uint32_t FP32_SIGN_INDEX = 31U;
constexpr uint32_t FP32_MAN_LEN = 23U;
constexpr uint32_t FP32_MAX_MAN = 0x7FFFFFU;
constexpr uint32_t FP16_MAN_HIDE_BIT = 0x0400U;
constexpr uint32_t FP32_EXP_BIAS = 127U;
constexpr uint32_t FP16_MAN_MASK = 0x03FFU;
constexpr uint32_t FP16_MAN_LEN = 10U;
constexpr uint32_t FP16_EXP_BIAS = 15U;

#define FP16_EXTRAC_SIGN(x) (((x) >> 15U) & 1U)
#define FP16_EXTRAC_EXP(x) (((x) >> 10U) & FP16_MAX_EXP)
#define FP16_EXTRAC_MAN(x) ((((x) >> 0U) & 0x3FFU) | ((((((x) >> 10U) & 0x1FU) > 0U) ? 1U : 0U) * 0x400U))
#define FP32_CONSTRUCTOR(s, e, m) (((s) << FP32_SIGN_INDEX) | ((e) << FP32_MAN_LEN) | ((m) & FP32_MAX_MAN))

union TypeUnion {
  float32_t fVal;
  uint32_t uVal;
};

static void ExtractFP16(const uint16_t val, uint16_t *const s, int16_t *const e, uint16_t *const m) {
  // 1.Extract
  *s = FP16_EXTRAC_SIGN(val);
  *e = static_cast<int16_t>(FP16_EXTRAC_EXP(val));
  *m = FP16_EXTRAC_MAN(val);

  // Denormal
  if ((*e) == 0) {
    *e = 1;
  }
}

float32_t Fp16ToFloat(const uint16_t val) {
  uint16_t hfSign;
  uint16_t hfMan;
  int16_t hfExp;
  ExtractFP16(val, &hfSign, &hfExp, &hfMan);

  while ((hfMan != 0U) && ((hfMan & FP16_MAN_HIDE_BIT) == 0U)) {
    hfMan <<= 1U;
    hfExp--;
  }

  uint32_t eRet;
  uint32_t mRet;
  if (hfMan == 0U) {
    eRet = 0U;
    mRet = 0U;
  } else {
    eRet = static_cast<uint32_t>(hfExp + static_cast<int16_t>(FP32_EXP_BIAS - FP16_EXP_BIAS));
    mRet = static_cast<uint32_t>(hfMan & FP16_MAN_MASK);
    mRet = mRet << (FP32_MAN_LEN - FP16_MAN_LEN);
  }

  const uint32_t sRet = hfSign;
  TypeUnion u;
  u.uVal = FP32_CONSTRUCTOR(sRet, eRet, mRet);
  const auto ret = u.fVal;
  return ret;
}

template <typename T>
std::string ScalarAttrToString(const ge::GeAttrValue &attrVal) {
  std::stringstream ss;
  T val{};
  (void)attrVal.GetValue<T>(val);
  ss << val;
  return ss.str();
}

template <>
std::string ScalarAttrToString<std::string>(const ge::GeAttrValue &attrVal) {
  std::string val;
  (void)attrVal.GetValue<std::string>(val);
  return val;
}

template <>
std::string ScalarAttrToString<bool>(const ge::GeAttrValue &attrVal) {
  bool val = false;
  (void)attrVal.GetValue<bool>(val);
  return val ? "True" : "False";
}

template <typename T>
std::string ListAttrToString(const ge::GeAttrValue &attrVal) {
  std::vector<T> values;
  (void)attrVal.GetValue<std::vector<T>>(values);
  return acl::StringUtils::VectorToString(values);
}

template <>
std::string ListAttrToString<bool>(const ge::GeAttrValue &attrVal) {
  std::stringstream ss;
  std::vector<bool> values;
  (void)attrVal.GetValue<std::vector<bool>>(values);
  ss << '[';
  const auto size = values.size();
  for (size_t i = 0U; i < size; ++i) {
    if (values[i]) {
      ss << "True";
    } else {
      ss << "False";
    }
    if (i != (size - 1U)) {
      ss << ", ";
    }
  }
  ss << ']';
  return ss.str();
}

template <typename T>
std::string ListListAttrToString(const ge::GeAttrValue &attrVal) {
  std::stringstream ss;
  ss << '[';
  std::vector<std::vector<T>> values;
  (void)attrVal.GetValue<std::vector<std::vector<T>>>(values);
  return acl::StringUtils::VectorToString(values);
}

template <typename T>
void ListAttrToStringForDigest(std::string &buffer, const ge::GeAttrValue &attrVal) {
  std::vector<T> values;
  (void)attrVal.GetValue<std::vector<T>>(values);
  for (const T &str : values) {
    buffer += std::to_string(str);
    buffer.push_back(',');
  }
}

template <typename T>
void ListAttrToDigest(size_t &seed, const ge::GeAttrValue &attrVal) {
  std::vector<T> values;
  (void)attrVal.GetValue<std::vector<T>>(values);
  for (const T &str : values) {
    acl::hash_utils::HashCombine(seed, str);
  }
}

template <typename T>
void GetAttrValueAndGenHash(size_t &seed, const ge::GeAttrValue &val, const T &init_value) {
  T value = init_value;
  (void)val.GetValue<T>(value);
  acl::hash_utils::HashCombine(seed, value);
}

template <typename T>
void ListListAttrToStringForDigest(std::string &buffer, const ge::GeAttrValue &attrVal) {
  std::vector<std::vector<T>> values;
  (void)attrVal.GetValue<std::vector<std::vector<T>>>(values);
  for (auto &subVec : values) {
    for (auto &val : subVec) {
      buffer += std::to_string(val);
      buffer.push_back(',');
    }
    buffer.push_back('|');
  }
}

template <typename T>
void ListListAttrToDigest(size_t &seed, const ge::GeAttrValue &attrVal) {
  std::vector<std::vector<T>> values;
  (void)attrVal.GetValue<std::vector<std::vector<T>>>(values);
  for (auto &subVec : values) {
    for (auto &val : subVec) {
      acl::hash_utils::HashCombine(seed, val);
    }
  }
}

template <typename T>
bool AttrScalarValueEquals(const ge::GeAttrValue &lhs, const ge::GeAttrValue &rhs) {
  T lhsValue{};
  T rhsValue{};
  (void)lhs.GetValue<T>(lhsValue);
  (void)rhs.GetValue<T>(rhsValue);
  return lhsValue == rhsValue;
}

template <>
bool AttrScalarValueEquals<float32_t>(const ge::GeAttrValue &lhs, const ge::GeAttrValue &rhs) {
  float32_t lhsValue = 0.0F;
  float32_t rhsValue = 0.0F;
  (void)lhs.GetValue<float32_t>(lhsValue);
  (void)rhs.GetValue<float32_t>(rhsValue);
  if (std::isnan(lhsValue) && std::isnan(rhsValue)) {
    return true;
  }
  if (std::isinf(lhsValue) && std::isinf(rhsValue)) {
    return true;
  }
  return fabsf(lhsValue - rhsValue) <= FLOAT_DELTA;
}

template <typename T>
bool AttrListValueEquals(const ge::GeAttrValue &lhs, const ge::GeAttrValue &rhs) {
  std::vector<T> lhsValue;
  std::vector<T> rhsValue;
  (void)(lhs.GetValue<std::vector<T>>(lhsValue));
  (void)(rhs.GetValue<std::vector<T>>(rhsValue));
  return lhsValue == rhsValue;
}

template <>
bool AttrListValueEquals<float32_t>(const ge::GeAttrValue &lhs, const ge::GeAttrValue &rhs) {
  std::vector<float32_t> lhsValue;
  std::vector<float32_t> rhsValue;
  (void)lhs.GetValue<std::vector<float32_t>>(lhsValue);
  (void)rhs.GetValue<std::vector<float32_t>>(rhsValue);
  return acl::attr_utils::IsListFloatEquals(lhsValue, rhsValue);
}

template <typename T>
bool AttrListListValueEquals(const ge::GeAttrValue &lhs, const ge::GeAttrValue &rhs) {
  std::vector<std::vector<T>> lhsValue;
  std::vector<std::vector<T>> rhsValue;
  (void)lhs.GetValue<std::vector<std::vector<T>>>(lhsValue);
  (void)rhs.GetValue<std::vector<std::vector<T>>>(rhsValue);
  return lhsValue == rhsValue;
}

template <typename T>
bool CheckValExact(const std::vector<T> &valueRange, const std::vector<T> &data) {
  if (valueRange.size() != data.size()) {
    ACL_LOG_DEBUG("input data size [%zu] must be equal to value range size [%zu]", data.size(), valueRange.size());
    return false;
  }
  for (size_t i = 0U; i < valueRange.size(); ++i) {
    if (valueRange[i] != data[i]) {
      return false;
    }
  }
  return true;
}

template <typename T1, typename T2>
void SetInputValue(const aclDataBuffer *const dataBuffer, std::vector<T1> &inputData) {
  for (size_t i = 0U; i < (dataBuffer->length / sizeof(T2)); ++i) {
    inputData.push_back(static_cast<T1>(*(reinterpret_cast<const T2 *>(dataBuffer->data) + i)));
  }
  return;
}

template <typename T>
bool CheckValRange(const std::vector<std::vector<T>> &valueRange, const std::vector<T> &data) {
  if (valueRange.size() != data.size()) {
    ACL_LOG_DEBUG("input data size [%zu] must be equal to value range size [%zu]", data.size(), valueRange.size());
    return false;
  }
  for (size_t i = 0U; i < valueRange.size(); ++i) {
    // 2 is range size
    if (valueRange[i].size() != 2U) {
      ACL_LOG_WARN("range size must be 2");
      return false;
    }
    if ((valueRange[i][0U] > data[i]) || (valueRange[i][1U] < data[i])) {
      return false;
    }
  }
  return true;
}
}  // namespace

namespace acl {
namespace attr_utils {
std::string GeAttrValueToString(const ge::GeAttrValue &val) {
  switch (val.GetValueType()) {
    case ge::GeAttrValue::VT_STRING:
      return ScalarAttrToString<std::string>(val);
    case ge::GeAttrValue::VT_BOOL:
      return ScalarAttrToString<bool>(val);
    case ge::GeAttrValue::VT_INT:
      return ScalarAttrToString<int64_t>(val);
    case ge::GeAttrValue::VT_FLOAT:
      return ScalarAttrToString<float32_t>(val);
    case ge::GeAttrValue::VT_DATA_TYPE:
      return ScalarAttrToString<ge::GeAttrValue::DATA_TYPE>(val);
    case ge::GeAttrValue::VT_LIST_STRING:
      return ListAttrToString<std::string>(val);
    case ge::GeAttrValue::VT_LIST_BOOL:
      return ListAttrToString<bool>(val);
    case ge::GeAttrValue::VT_LIST_INT:
      return ListAttrToString<int64_t>(val);
    case ge::GeAttrValue::VT_LIST_FLOAT:
      return ListAttrToString<float32_t>(val);
    case ge::GeAttrValue::VT_LIST_DATA_TYPE:
      return ListAttrToString<ge::GeAttrValue::DATA_TYPE>(val);
    case ge::GeAttrValue::VT_LIST_LIST_INT:
      return ListListAttrToString<int64_t>(val);
    default:
      std::stringstream ss;
      ss << "Unknown type ";
      ss << val.GetValueType();
      return ss.str();
  }
}

void GeAttrValueToDigest(size_t &seed, const ge::GeAttrValue &val) {
  switch (val.GetValueType()) {
    case ge::GeAttrValue::VT_BOOL:
      GetAttrValueAndGenHash<bool>(seed, val, false);
      break;
    case ge::GeAttrValue::VT_STRING:
      GetAttrValueAndGenHash<std::string>(seed, val, "");
      break;
    case ge::GeAttrValue::VT_INT:
      GetAttrValueAndGenHash<int64_t>(seed, val, 0L);
      break;
    case ge::GeAttrValue::VT_DATA_TYPE:
      GetAttrValueAndGenHash<ge::GeAttrValue::DATA_TYPE>(seed, val, {});
      break;
    case ge::GeAttrValue::VT_FLOAT:
      GetAttrValueAndGenHash<float32_t>(seed, val, 0.0f);
      break;
    case ge::GeAttrValue::VT_LIST_STRING:
      ListAttrToDigest<std::string>(seed, val);
      break;
    case ge::GeAttrValue::VT_LIST_BOOL:
      ListAttrToDigest<bool>(seed, val);
      break;
    case ge::GeAttrValue::VT_LIST_INT:
      ListAttrToDigest<int64_t>(seed, val);
      break;
    case ge::GeAttrValue::VT_LIST_DATA_TYPE:
      ListAttrToDigest<ge::GeAttrValue::DATA_TYPE>(seed, val);
      break;
    case ge::GeAttrValue::VT_LIST_FLOAT:
      ListAttrToDigest<float32_t>(seed, val);
      break;
    case ge::GeAttrValue::VT_LIST_LIST_INT:
      ListListAttrToDigest<int64_t>(seed, val);
      break;
    default:
      break;
  }
}

std::string AttrMapToString(const std::map<std::string, ge::GeAttrValue> &attrMap) {
  std::stringstream ss;
  ss << "{";
  const size_t size = attrMap.size();
  size_t cnt = 0U;
  for (auto &attr : attrMap) {
    ss << attr.first << " = " << GeAttrValueToString(attr.second);
    cnt++;
    if (cnt != size) {
      ss << ", ";
    }
  }
  ss << "}";
  return ss.str();
}

size_t AttrMapToDigest(const std::map<std::string, ge::GeAttrValue> &attrMap) {
  if (attrMap.empty()) {
    return 0U;
  }

  size_t digest = 0U;
  for (auto &attr : attrMap) {
    GeAttrValueToDigest(digest, attr.second);
  }

  return digest;
}

bool IsListFloatEquals(const std::vector<float32_t> &lhsValue, const std::vector<float32_t> &rhsValue) {
  if (lhsValue.size() != rhsValue.size()) {
    return false;
  }

  for (size_t i = 0U; i < lhsValue.size(); ++i) {
    const float32_t val1 = lhsValue[i];
    const float32_t val2 = rhsValue[i];
    if (std::isnan(val1) && std::isnan(val2)) {
      continue;
    }
    if (std::isinf(val1) && std::isinf(val2)) {
      continue;
    }
    if (fabsf(val1 - val2) > FLOAT_DELTA) {
      return false;
    }
  }

  return true;
}

bool AttrValueEquals(const ge::GeAttrValue &lhs, const ge::GeAttrValue &rhs) {
  const auto type = lhs.GetValueType();
  if (rhs.GetValueType() != type) {
    ACL_LOG_INFO("type mismatch, lhs type = %d, rhs type = %d", static_cast<int32_t>(type),
                 static_cast<int32_t>(rhs.GetValueType()));
    return false;
  }

  switch (type) {
    case ge::GeAttrValue::VT_STRING:
      return AttrScalarValueEquals<std::string>(lhs, rhs);
    case ge::GeAttrValue::VT_BOOL:
      return AttrScalarValueEquals<bool>(lhs, rhs);
    case ge::GeAttrValue::VT_INT:
      return AttrScalarValueEquals<int64_t>(lhs, rhs);
    case ge::GeAttrValue::VT_FLOAT:
      return AttrScalarValueEquals<float32_t>(lhs, rhs);
    case ge::GeAttrValue::VT_DATA_TYPE:
      return AttrScalarValueEquals<ge::GeAttrValue::DATA_TYPE>(lhs, rhs);
    case ge::GeAttrValue::VT_LIST_STRING:
      return AttrListValueEquals<std::string>(lhs, rhs);
    case ge::GeAttrValue::VT_LIST_BOOL:
      return AttrListValueEquals<bool>(lhs, rhs);
    case ge::GeAttrValue::VT_LIST_INT:
      return AttrListValueEquals<int64_t>(lhs, rhs);
    case ge::GeAttrValue::VT_LIST_FLOAT:
      return AttrListValueEquals<float32_t>(lhs, rhs);
    case ge::GeAttrValue::VT_LIST_DATA_TYPE:
      return AttrListValueEquals<ge::GeAttrValue::DATA_TYPE>(lhs, rhs);
    case ge::GeAttrValue::VT_LIST_LIST_INT:
      return AttrListListValueEquals<int64_t>(lhs, rhs);
    default:
      ACL_LOG_INNER_ERROR("[Check][Type]Unknown type %d", static_cast<int32_t>(type));
      return false;
  }
}

static bool GetInputData(const aclDataBuffer *const dataBuffer, const aclDataType dataType,
                         std::vector<int64_t> &inputIntData, std::vector<float32_t> &inputFloatData) {
  switch (dataType) {
    case ACL_FLOAT:
      SetInputValue<float32_t, float32_t>(dataBuffer, inputFloatData);
      break;
    case ACL_FLOAT16:
      for (size_t i = 0U; i < (dataBuffer->length / sizeof(aclFloat16)); ++i) {
        inputFloatData.push_back(Fp16ToFloat(*(static_cast<const aclFloat16 *>(dataBuffer->data) + i)));
      }
      break;
    case ACL_INT8:
      SetInputValue<int64_t, int8_t>(dataBuffer, inputIntData);
      break;
    case ACL_UINT8:
      SetInputValue<int64_t, uint8_t>(dataBuffer, inputIntData);
      break;
    case ACL_INT16:
      SetInputValue<int64_t, int16_t>(dataBuffer, inputIntData);
      break;
    case ACL_UINT16:
      SetInputValue<int64_t, uint16_t>(dataBuffer, inputIntData);
      break;
    case ACL_INT32:
      SetInputValue<int64_t, int32_t>(dataBuffer, inputIntData);
      break;
    case ACL_UINT32:
      SetInputValue<int64_t, uint32_t>(dataBuffer, inputIntData);
      break;
    case ACL_INT64:
      SetInputValue<int64_t, int64_t>(dataBuffer, inputIntData);
      break;
    case ACL_UINT64:
      SetInputValue<int64_t, uint64_t>(dataBuffer, inputIntData);
      break;
    default:
      ACL_LOG_WARN("unsupported type: %d", dataType);
      return false;
  }
  ACL_LOG_INFO("Get input data success, dt is %d, int type size is %zu, float type size is %zu", dataType,
               inputIntData.size(), inputFloatData.size());
  return true;
}

static bool CheckIntValueRange(const std::map<AttrRangeType, ge::GeAttrValue> &valueRange,
                               const std::vector<int64_t> &inputIntData) {
  // Check range
  const auto it = valueRange.find(AttrRangeType::RANGE_TYPE);
  if (it != valueRange.end()) {
    std::vector<std::vector<int64_t>> valRangeInt;
    if (it->second.GetValue<std::vector<std::vector<int64_t>>>(valRangeInt) == ge::GRAPH_SUCCESS) {
      return CheckValRange(valRangeInt, inputIntData);
    } else {
      std::vector<int64_t> tmpInt;
      if (it->second.GetValue<std::vector<int64_t>>(tmpInt) == ge::GRAPH_SUCCESS) {
        valRangeInt.push_back(tmpInt);
        return CheckValRange(valRangeInt, inputIntData);
      } else {
        ACL_LOG_WARN("cannot find listlist or list data struct");
        return false;
      }
    }
  }
  return true;
}

static bool CheckFloatValueRange(const std::map<AttrRangeType, ge::GeAttrValue> &valueRange,
                                 const std::vector<float32_t> &inputFloatData) {
  // Check range
  const auto it = valueRange.find(AttrRangeType::RANGE_TYPE);
  if (it != valueRange.end()) {
    std::vector<std::vector<float32_t>> valRangeFloat;
    if (it->second.GetValue<std::vector<std::vector<float32_t>>>(valRangeFloat) == ge::GRAPH_SUCCESS) {
      return CheckValRange(valRangeFloat, inputFloatData);
    } else {
      std::vector<float32_t> tmpFloat;
      if (it->second.GetValue<std::vector<float32_t>>(tmpFloat) == ge::GRAPH_SUCCESS) {
        valRangeFloat.push_back(tmpFloat);
        return CheckValRange(valRangeFloat, inputFloatData);
      }
    }
  }
  return true;
}

static bool CheckGeTensorValue(const std::map<AttrRangeType, ge::GeAttrValue> &valueRange,
                               const aclDataBuffer *const dataBuffer) {
  const auto it = valueRange.find(AttrRangeType::VALUE_TYPE);
  if (it == valueRange.end()) {
    return true;
  }
  const auto geTensor = const_cast<ge::GeAttrValue *>(&(it->second))->MutableGet<ge::GeTensor>();
  if (geTensor != nullptr) {
    void *const geDataPtr = reinterpret_cast<void *>(geTensor->MutableData().data());
    const size_t dataSize = geTensor->MutableData().size();
    auto *const inputDataPtr = dataBuffer->data;
    if ((dataSize >= dataBuffer->length) && (memcmp(geDataPtr, inputDataPtr, dataBuffer->length) == 0)) {
      return true;
    }
  }
  return false;
}

static bool IsSameRange(const std::map<AttrRangeType, ge::GeAttrValue> &value1,
                        const std::map<AttrRangeType, ge::GeAttrValue> &value2) {
  const auto it1 = value1.find(AttrRangeType::RANGE_TYPE);
  const auto it2 = value2.find(AttrRangeType::RANGE_TYPE);
  if ((it1 == value1.end()) && (it2 == value2.end())) {
    return true;
  }
  if ((it1 != value1.end()) && (it2 != value2.end())) {
    std::vector<std::vector<int64_t>> valRangeInt1;
    std::vector<std::vector<int64_t>> valRangeInt2;
    if ((it1->second.GetValue<std::vector<std::vector<int64_t>>>(valRangeInt1) == ge::GRAPH_SUCCESS) &&
        (it1->second.GetValue<std::vector<std::vector<int64_t>>>(valRangeInt2) == ge::GRAPH_SUCCESS)) {
      return (valRangeInt1 == valRangeInt2);
    }
  }

  return false;
}

static bool IsSameValue(const std::map<AttrRangeType, ge::GeAttrValue> &value1,
                        const std::map<AttrRangeType, ge::GeAttrValue> &value2) {
  const auto it1 = value1.find(AttrRangeType::VALUE_TYPE);
  const auto it2 = value2.find(AttrRangeType::VALUE_TYPE);
  if ((it1 == value1.end()) && (it2 == value2.end())) {
    return true;
  }
  if ((it1 != value1.end()) && (it2 != value2.end())) {
    const auto geTensor1 = (&(it1->second))->Get<ge::GeTensor>();
    const auto geTensor2 = (&(it2->second))->Get<ge::GeTensor>();
    if ((geTensor1 != nullptr) && (geTensor2 != nullptr)) {
      const void *const geDataPtr1 = static_cast<const void *>(geTensor1->GetData().data());
      const void *const geDataPtr2 = static_cast<const void *>(geTensor2->GetData().data());
      const size_t dataSize1 = geTensor1->GetData().size();
      const size_t dataSize2 = geTensor2->GetData().size();
      if ((dataSize1 == dataSize2) && (memcmp(geDataPtr1, geDataPtr2, dataSize1) == 0)) {
        return true;
      }
    }
  }
  return false;
}

bool IsSameValueRange(const std::map<AttrRangeType, ge::GeAttrValue> &valueRange1,
                      const std::map<AttrRangeType, ge::GeAttrValue> &valueRange2) {
  if (valueRange1.size() != valueRange2.size()) {
    ACL_LOG_INFO("IsSameValueRange return fasle, size of valueRange1 is %zu, ize of valueRange2 is %zu",
                 valueRange1.size(), valueRange1.size());
    return false;
  }

  if (!IsSameValue(valueRange1, valueRange2)) {
    ACL_LOG_INFO("Value of valueRange1 mismatch value of valueRange1");
    return false;
  }
  if (!IsSameRange(valueRange1, valueRange2)) {
    ACL_LOG_INFO("Range of valueRange1 mismatch range of valueRange1");
    return false;
  }
  return true;
}

bool ValueRangeCheck(const std::map<AttrRangeType, ge::GeAttrValue> &valueRange, const aclDataBuffer *const dataBuffer,
                     const aclDataType dataType) {
  // value is not nullptr
  if (dataBuffer->data == nullptr) {
    return true;
  }
  // check value first
  if (!CheckGeTensorValue(valueRange, dataBuffer)) {
    return false;
  }
  std::vector<int64_t> inputIntData;
  std::vector<float32_t> inputFloatData;
  if (!GetInputData(dataBuffer, dataType, inputIntData, inputFloatData)) {
    return false;
  }
  // check value range
  if (!inputIntData.empty()) {
    return CheckIntValueRange(valueRange, inputIntData);
  }
  if (!inputFloatData.empty()) {
    return CheckFloatValueRange(valueRange, inputFloatData);
  }
  return true;
}

bool OpAttrEquals(const aclopAttr *const lhs, const aclopAttr *const rhs) {
  if (lhs == rhs) {
    return true;
  }
  // inner logic, must not be nullptr
  if ((lhs == nullptr) || (rhs == nullptr)) {
    return false;
  }
  const size_t lhsAttrNum = lhs->Attrs().size();
  const size_t rhsAttrNum = rhs->Attrs().size();
  if (lhsAttrNum != rhsAttrNum) {
    return false;
  }
  // attr num of lhs and rhs is not 0, so attr is not nullptr
  const auto &lhsAttrs = lhs->Attrs();
  for (const auto &iter : rhs->Attrs()) {
    const std::string &attrName = iter.first;
    const ge::GeAttrValue &attrValue = iter.second;

    const auto it = lhsAttrs.find(attrName);
    if (it == lhsAttrs.end()) {
      return false;
    }
    // no overloaded operator != for GeAttrValue
    if (!attr_utils::AttrValueEquals(it->second, attrValue)) {
      return false;
    }
  }
  const auto constStrLeft = lhs->GetConstBuf();
  const auto constStrRight = rhs->GetConstBuf();
  if (constStrLeft != constStrRight) {
    return false;
  }
  return true;
}

uint64_t GetCurrentTimestamp() {
  static uint64_t timeStamp = 0UL;
  ++timeStamp;
  return timeStamp;
}

static bool ConstToAttr(const vector<aclTensorDesc> &tensorDesc, std::vector<std::string> &constStr) {
  for (auto &desc : tensorDesc) {
    if (desc.isConst) {
      if ((desc.constDataBuf != nullptr) && (desc.constDataLen <= 0U)) {
        ACL_LOG_INNER_ERROR("[Check][constDataBuf]constDataBuf is not nullptr and dataLen is <= 0");
        return false;
      }
      if ((desc.constDataBuf == nullptr) && (desc.constDataLen > 0U)) {
        ACL_LOG_INNER_ERROR("[Check][constDataBuf]constDataBuf is nullptr and dataLen is > 0");
        return false;
      }
      std::string constBufStr;
      (void)constBufStr.assign(reinterpret_cast<const char_t *>(desc.constDataBuf.get()), desc.constDataLen);
      constStr.emplace_back(constBufStr);
    }
  }
  return true;
}

bool SaveConstToAttr(OpModelDef &modelDef) {
  std::vector<std::string> constStr;
  bool ret = ConstToAttr(modelDef.inputDescArr, constStr);
  if (!ret) {
    ACL_LOG_INNER_ERROR("[Check][InputTenspr]inputTenspr get const dataLen failed");
    return false;
  }
  ret = ConstToAttr(modelDef.outputDescArr, constStr);
  if (!ret) {
    ACL_LOG_INNER_ERROR("[Check][OutputTensor]outputTensor get const dataLen failed");
    return false;
  }
  // opAttr is not nullptr
  for (size_t i = 0U; i < constStr.size(); ++i) {
    modelDef.opAttr.EmplaceConstBuf(constStr[i]);
  }
  return true;
}

static bool ConstToAttr(const int32_t tensorNum, const aclTensorDesc *const tensorDesc[],
                        std::vector<std::string> &constStr) {
  for (int32_t i = 0; i < tensorNum; ++i) {
    const aclTensorDesc *const desc = tensorDesc[i];
    if (desc->isConst) {
      if ((desc->constDataBuf != nullptr) && (desc->constDataLen <= 0U)) {
        ACL_LOG_INNER_ERROR("[Check][constDataBuf]constDataBuf is not nullptr and dataLen is <= 0");
        return false;
      }
      if ((desc->constDataBuf == nullptr) && (desc->constDataLen > 0U)) {
        ACL_LOG_INNER_ERROR("[Check][constDataBuf]constDataBuf is nullptr and dataLen is > 0");
        return false;
      }
      std::string constBufStr =
          std::string(reinterpret_cast<const char_t *>(desc->constDataBuf.get()), desc->constDataLen);
      constStr.emplace_back(constBufStr);
    }
  }
  return true;
}

bool SaveConstToAttr(const AclOp &opDesc, aclopAttr *const opAttr) {
  std::vector<std::string> constStr;
  bool ret = ConstToAttr(opDesc.numInputs, opDesc.inputDesc, constStr);
  if (!ret) {
    ACL_LOG_INNER_ERROR("[Check][InputTenspr]inputTenspr get const dataLen failed");
    return false;
  }
  ret = ConstToAttr(opDesc.numOutputs, opDesc.outputDesc, constStr);
  if (!ret) {
    ACL_LOG_INNER_ERROR("[Check][OutputTensor]outputTensor get const dataLen failed");
    return false;
  }
  // opAttr is not nullptr
  opAttr->ClearConstBuf();
  for (size_t i = 0U; i < constStr.size(); ++i) {
    opAttr->EmplaceConstBuf(constStr[i]);
  }
  return true;
}
}  // namespace attr_utils
}  // namespace acl