| 638 | } |
| 639 | |
| 640 | TfLiteStatus Subgraph::ResizeInputTensor(int tensor_index, |
| 641 | const std::vector<int>& dims) { |
| 642 | const bool delegates_applied = !pre_delegation_execution_plan_.empty(); |
| 643 | const bool graph_is_immutable = state_ == kStateInvokableAndImmutable; |
| 644 | if (graph_is_immutable && !delegates_applied) { |
| 645 | ReportError("ResizeInputTensor is disallowed when graph is immutable."); |
| 646 | return kTfLiteError; |
| 647 | } |
| 648 | |
| 649 | // TODO(aselle): All bounds checks can be implemented as one-sided bounds |
| 650 | // checks by casting to unsigned for efficiency. Profile before doing this. |
| 651 | TF_LITE_ENSURE(&context_, |
| 652 | tensor_index < context_.tensors_size && tensor_index >= 0); |
| 653 | TfLiteTensor* tensor = &context_.tensors[tensor_index]; |
| 654 | |
| 655 | // Short-circuit the state change if the dimensions don't change, avoiding |
| 656 | // unnecessary (re)allocations. |
| 657 | // |
| 658 | // Note that it's required to check `tensor->data.raw != nullptr`. Otherwise |
| 659 | // the subgraph won't allocate memory for a dynamic tensor when its size |
| 660 | // is equal to the original tensor size. |
| 661 | if (tensor->data.raw != nullptr && |
| 662 | EqualArrayAndTfLiteIntArray(tensor->dims, dims.size(), dims.data())) { |
| 663 | return kTfLiteOk; |
| 664 | } |
| 665 | |
| 666 | if (graph_is_immutable) { |
| 667 | // Undo delegation if it resulted in the graph being immutable. |
| 668 | TF_LITE_ENSURE_STATUS(UndoAllDelegates()); |
| 669 | } |
| 670 | state_ = kStateUninvokable; |
| 671 | return ResizeTensorImpl(tensor, ConvertVectorToTfLiteIntArray(dims)); |
| 672 | } |
| 673 | |
| 674 | TfLiteStatus Subgraph::OpPrepare(const TfLiteRegistration& op_reg, |
| 675 | TfLiteNode* node) { |