Repository: microsoft/onnxruntime
File: onnxruntime/core/optimizer/common_subexpression_elimination.cc (C++)

Code before:
    case onnx::AttributeProto_AttributeType_INTS:
      return AreRangesEqual(lhs.ints(), rhs.ints());
    case onnx::AttributeProto_AttributeType_STRINGS:
      return AreRangesEqual(lhs.strings(), rhs.strings());
    case onnx::AttributeProto_AttributeType_TENSOR:
      return AreScalarTensorAttributeEqual(lhs.t(), rhs.t());
    case onnx::AttributeProto_AttributeType_GRAPH:
    case onnx::AttributeProto_AttributeType_SPARSE_TENSOR:
    case onnx::AttributeProto_AttributeType_TYPE_PROTO:
    case onnx::AttributeProto_AttributeType_TENSORS:
    case onnx::AttributeProto_AttributeType_GRAPHS:
    case onnx::AttributeProto_AttributeType_SPARSE_TENSORS:
    case onnx::AttributeProto_AttributeType_TYPE_PROTOS:
    case onnx::AttributeProto_AttributeType_UNDEFINED:
      return false;  // Don't support these attributes for now; corresponding nodes will be considered distinct.
  }

  return false;
}

// Support scalar float/int64/fp16 tensor attribute only for now.
std::size_t GetTensorAttributeHash(const ONNX_NAMESPACE::TensorProto& attr_t) {
  std::size_t hash = 0;
  if (utils::HasDataType(attr_t) && attr_t.dims_size() == 1 && attr_t.dims()[0] == 1) {
    int data_type = attr_t.data_type();
    switch (data_type) {
      case onnx::TensorProto_DataType_FLOAT:
      case onnx::TensorProto_DataType_FLOAT16:
      case onnx::TensorProto_DataType_INT64: {
        std::vector<uint8_t> unpacked_tensor;
        if (utils::UnpackInitializerData(attr_t, unpacked_tensor).IsOK()) {
          UpdateHash(data_type, hash);
          UpdateHashWithContainer(unpacked_tensor, hash);
        }
        break;
      }
      default:
        break;
    }
  }
  return hash;
}

std::size_t GetAttributeHash(const ONNX_NAMESPACE::AttributeProto& attr) {
  std::size_t hash = 0;
  UpdateHash(
      static_cast<std::underlying_type<ONNX_NAMESPACE::AttributeProto_AttributeType>::type>(attr.type()),
      hash);
  UpdateHash(attr.name(), hash);
  switch (attr.type()) {
    case onnx::AttributeProto_AttributeType_FLOAT:

Review comment (suggestion):
This is much better. Here is an idea, let's make this function type independent.
We will check if the attribute tensor is not of string type using `ORT_ENFORCE(data_type != TensorDataType_STRING, "Unexpected tensor string type");` at the start of the function.
We can then remove the switch, Unpack the data, compute and return the hash regardless of the type.



Code after:
      return AreRangesEqual(lhs.strings(), rhs.strings());
    case onnx::AttributeProto_AttributeType_TENSOR:
      return AreScalarTensorAttributeEqual(lhs.t(), rhs.t());
    case onnx::AttributeProto_AttributeType_GRAPH:
    case onnx::AttributeProto_AttributeType_SPARSE_TENSOR:
    case onnx::AttributeProto_AttributeType_TYPE_PROTO:
    case onnx::AttributeProto_AttributeType_TENSORS:
    case onnx::AttributeProto_AttributeType_GRAPHS:
    case onnx::AttributeProto_AttributeType_SPARSE_TENSORS:
    case onnx::AttributeProto_AttributeType_TYPE_PROTOS:
    case onnx::AttributeProto_AttributeType_UNDEFINED:
      return false;  // Don't support these attributes for now; corresponding nodes will be considered distinct.
  }

  return false;
}

// Support scalar tensor attribute only for now.
std::size_t GetTensorAttributeHash(const ONNX_NAMESPACE::TensorProto& attr_t) {
  std::size_t hash = 0;
  if (utils::HasDataType(attr_t) && attr_t.dims_size() == 1 && attr_t.dims()[0] == 1) {
    int data_type = attr_t.data_type();
    ORT_ENFORCE(data_type != onnx::TensorProto_DataType_STRING, "Unexpected tensor string type");
    std::vector<uint8_t> unpacked_tensor;
    if (utils::UnpackInitializerData(attr_t, unpacked_tensor).IsOK()) {
      UpdateHash(data_type, hash);
      UpdateHashWithContainer(unpacked_tensor, hash);
    }
  }
  return hash;
}

std::size_t GetAttributeHash(const ONNX_NAMESPACE::AttributeProto& attr) {
  std::size_t hash = 0;
  UpdateHash(
      static_cast<std::underlying_type<ONNX_NAMESPACE::AttributeProto_AttributeType>::type>(attr.type()),
      hash);
  UpdateHash(attr.name(), hash);
  switch (attr.type()) {
    case onnx::AttributeProto_AttributeType_FLOAT:
      UpdateHash(attr.f(), hash);
      break;
    case onnx::AttributeProto_AttributeType_INT:
      UpdateHash(attr.i(), hash);
      break;
    case onnx::AttributeProto_AttributeType_STRING:
      UpdateHash(attr.s(), hash);
      break;
    case onnx::AttributeProto_AttributeType_FLOATS:
      UpdateHashWithContainer(attr.floats(), hash);
      break;