Compute a signature for either inputs or outputs that will be the same for both the old and new OpDef if they are compatible. We assume that new_attrs is a superset of old_attrs, and that any attr in the difference has a default. Our strategy is to make a list of types, where the types are things like: "int32", "float", etc., "T" for some attr "T" in old_attrs, or "N * type" for "N" either some
| 520 | // We get the types by either using the attrs in args if they are in |
| 521 | // old_attrs, or substituting the default value from new_attrs. |
| 522 | string ComputeArgSignature( |
| 523 | const protobuf::RepeatedPtrField<OpDef::ArgDef>& args, |
| 524 | const AttrMap& old_attrs, const AttrMap& new_attrs, std::vector<bool>* ref, |
| 525 | bool names) { |
| 526 | string s; |
| 527 | bool add_comma = false; |
| 528 | for (const OpDef::ArgDef& arg : args) { |
| 529 | if (!arg.type_list_attr().empty()) { |
| 530 | const OpDef::AttrDef* old_attr = |
| 531 | gtl::FindPtrOrNull(old_attrs, arg.type_list_attr()); |
| 532 | if (old_attr) { |
| 533 | // Both old and new have the list(type) attr, so can use it directly. |
| 534 | AddComma(&s, &add_comma); |
| 535 | AddName(&s, names, arg); |
| 536 | strings::StrAppend(&s, arg.type_list_attr()); |
| 537 | ref->push_back(arg.is_ref()); |
| 538 | } else { |
| 539 | // Missing the list(type) attr in the old, so use the default |
| 540 | // value for the attr from new instead. |
| 541 | const OpDef::AttrDef* new_attr = |
| 542 | gtl::FindPtrOrNull(new_attrs, arg.type_list_attr()); |
| 543 | const auto& type_list = new_attr->default_value().list().type(); |
| 544 | if (type_list.empty()) continue; |
| 545 | for (int i = 0; i < type_list.size(); ++i) { |
| 546 | AddComma(&s, &add_comma); |
| 547 | AddName(&s, names, arg); |
| 548 | strings::StrAppend( |
| 549 | &s, DataTypeString(static_cast<DataType>(type_list.Get(i)))); |
| 550 | ref->push_back(arg.is_ref()); |
| 551 | } |
| 552 | } |
| 553 | } else { |
| 554 | int num = 1; // How many input/outputs does this represent? |
| 555 | string type; // What is the type of this arg? |
| 556 | AddName(&type, names, arg); |
| 557 | if (!arg.number_attr().empty()) { |
| 558 | // N * type case. |
| 559 | const OpDef::AttrDef* old_attr = |
| 560 | gtl::FindPtrOrNull(old_attrs, arg.number_attr()); |
| 561 | if (old_attr) { |
| 562 | // Both old and new have the number attr, so can use it directly. |
| 563 | strings::StrAppend(&type, arg.number_attr(), " * "); |
| 564 | } else { |
| 565 | // Missing the number attr in the old, so use the default |
| 566 | // value for the attr from new instead. |
| 567 | const OpDef::AttrDef* new_attr = |
| 568 | gtl::FindPtrOrNull(new_attrs, arg.number_attr()); |
| 569 | num = new_attr->default_value().i(); |
| 570 | } |
| 571 | } |
| 572 | |
| 573 | if (arg.type() != DT_INVALID) { |
| 574 | // int32, float, etc. case |
| 575 | strings::StrAppend(&type, DataTypeString(arg.type())); |
| 576 | } else { |
| 577 | const OpDef::AttrDef* old_attr = |
| 578 | gtl::FindPtrOrNull(old_attrs, arg.type_attr()); |
| 579 | if (old_attr) { |
no test coverage detected