| 718 | } |
| 719 | |
| 720 | void Compute(OpKernelContext* ctx) override { |
| 721 | const Tensor& buf_tensor = ctx->input(0); |
| 722 | int message_count = buf_tensor.NumElements(); |
| 723 | OP_REQUIRES(ctx, message_count >= 1, |
| 724 | errors::InvalidArgument( |
| 725 | "Bufs argument must contain at least one value")); |
| 726 | |
| 727 | int field_count = fields_.size(); |
| 728 | |
| 729 | // Save the argument shape for later, then flatten the input Tensor since we |
| 730 | // are working componentwise. We will restore the same shape in the returned |
| 731 | // Tensor. |
| 732 | const TensorShape& shape_prefix = buf_tensor.shape(); |
| 733 | |
| 734 | TensorShape sizes_shape = shape_prefix; |
| 735 | sizes_shape.AddDim(field_count); |
| 736 | Tensor* sizes_tensor = nullptr; |
| 737 | OP_REQUIRES_OK(ctx, ctx->allocate_output(0, sizes_shape, &sizes_tensor)); |
| 738 | |
| 739 | // This is used to allocate binary bufs if used. It serves only to define |
| 740 | // memory ownership. |
| 741 | std::vector<tstring> tmp_binary_bufs(message_count); |
| 742 | |
| 743 | // These are the actual buffers to use, which may be in tmp_binary_bufs |
| 744 | // or may be pointers into the buf_tensor. Either way they are not owned |
| 745 | // here. |
| 746 | std::vector<const tstring*> bufs; |
| 747 | |
| 748 | if (is_binary_ && !sanitize_) { |
| 749 | // Fast path. |
| 750 | for (int mi = 0; mi < message_count; ++mi) { |
| 751 | const tstring* buf = &buf_tensor.flat<tstring>()(mi); |
| 752 | bufs.push_back(buf); |
| 753 | } |
| 754 | } else { |
| 755 | // We will have to allocate a copy, either to convert from text to binary |
| 756 | // or to sanitize a binary proto. |
| 757 | for (int mi = 0; mi < message_count; ++mi) { |
| 758 | ReserializeMessage(ctx, buf_tensor.flat<tstring>()(mi), |
| 759 | &tmp_binary_bufs[mi]); |
| 760 | if (!ctx->status().ok()) { |
| 761 | return; |
| 762 | } |
| 763 | bufs.push_back(&tmp_binary_bufs[mi]); |
| 764 | } |
| 765 | } |
| 766 | |
| 767 | // Walk through all the strings in the input tensor, counting the number of |
| 768 | // fields in each. We can't allocate our actual output Tensor until we know |
| 769 | // the maximum repeat count, so we do a first pass through the serialized |
| 770 | // proto just counting fields. We always allocate at least one value so that |
| 771 | // optional fields are populated with default values - this avoids a TF |
| 772 | // conditional when handling the output data. The caller can distinguish |
| 773 | // between real data and defaults using the repeat count matrix that is |
| 774 | // returned by decode_proto. |
| 775 | std::vector<int32> max_sizes(field_count, 1); |
| 776 | for (int mi = 0; mi < message_count; ++mi) { |
| 777 | CountFields(ctx, mi, *bufs[mi], sizes_tensor, &max_sizes); |
nothing calls this directly
no test coverage detected