| 267 | } |
| 268 | |
| 269 | bool SetOpAttrList( |
| 270 | TFE_Context* ctx, TFE_Op* op, const char* key, PyObject* py_list, |
| 271 | TF_AttrType type, |
| 272 | tensorflow::gtl::FlatMap<string, tensorflow::int64>* attr_list_sizes, |
| 273 | TF_Status* status) { |
| 274 | if (!PySequence_Check(py_list)) { |
| 275 | TF_SetStatus( |
| 276 | status, TF_INVALID_ARGUMENT, |
| 277 | tensorflow::strings::StrCat("Expecting sequence value for attr ", key, |
| 278 | ", got ", py_list->ob_type->tp_name) |
| 279 | .c_str()); |
| 280 | return false; |
| 281 | } |
| 282 | const int num_values = PySequence_Size(py_list); |
| 283 | if (attr_list_sizes != nullptr) (*attr_list_sizes)[key] = num_values; |
| 284 | |
| 285 | #define PARSE_LIST(c_type, parse_fn) \ |
| 286 | std::unique_ptr<c_type[]> values(new c_type[num_values]); \ |
| 287 | for (int i = 0; i < num_values; ++i) { \ |
| 288 | tensorflow::Safe_PyObjectPtr py_value(PySequence_ITEM(py_list, i)); \ |
| 289 | if (!parse_fn(key, py_value.get(), status, &values[i])) return false; \ |
| 290 | } |
| 291 | |
| 292 | if (type == TF_ATTR_STRING) { |
| 293 | std::unique_ptr<const void*[]> values(new const void*[num_values]); |
| 294 | std::unique_ptr<size_t[]> lengths(new size_t[num_values]); |
| 295 | for (int i = 0; i < num_values; ++i) { |
| 296 | tensorflow::StringPiece value; |
| 297 | tensorflow::Safe_PyObjectPtr py_value(PySequence_ITEM(py_list, i)); |
| 298 | if (!ParseStringValue(key, py_value.get(), status, &value)) return false; |
| 299 | values[i] = value.data(); |
| 300 | lengths[i] = value.size(); |
| 301 | } |
| 302 | TFE_OpSetAttrStringList(op, key, values.get(), lengths.get(), num_values); |
| 303 | } else if (type == TF_ATTR_INT) { |
| 304 | PARSE_LIST(int64_t, ParseInt64Value); |
| 305 | TFE_OpSetAttrIntList(op, key, values.get(), num_values); |
| 306 | } else if (type == TF_ATTR_FLOAT) { |
| 307 | PARSE_LIST(float, ParseFloatValue); |
| 308 | TFE_OpSetAttrFloatList(op, key, values.get(), num_values); |
| 309 | } else if (type == TF_ATTR_BOOL) { |
| 310 | PARSE_LIST(unsigned char, ParseBoolValue); |
| 311 | TFE_OpSetAttrBoolList(op, key, values.get(), num_values); |
| 312 | } else if (type == TF_ATTR_TYPE) { |
| 313 | PARSE_LIST(int, ParseTypeValue); |
| 314 | TFE_OpSetAttrTypeList(op, key, |
| 315 | reinterpret_cast<const TF_DataType*>(values.get()), |
| 316 | num_values); |
| 317 | } else if (type == TF_ATTR_SHAPE) { |
| 318 | // Make one pass through the input counting the total number of |
| 319 | // dims across all the input lists. |
| 320 | int total_dims = 0; |
| 321 | for (int i = 0; i < num_values; ++i) { |
| 322 | tensorflow::Safe_PyObjectPtr py_value(PySequence_ITEM(py_list, i)); |
| 323 | if (py_value.get() != Py_None) { |
| 324 | if (!PySequence_Check(py_value.get())) { |
| 325 | TF_SetStatus( |
| 326 | status, TF_INVALID_ARGUMENT, |
no test coverage detected