| 188 | |
| 189 | template <typename T> |
| 190 | bool CompressTensorContent(float min_compression_ratio, |
| 191 | const TensorShape& shape, TensorProto* tensor) { |
| 192 | using TypeHelper = internal::TensorProtoHelper<T>; |
| 193 | using FieldType = typename internal::TensorProtoHelper<T>::FieldType; |
| 194 | const int64 num_tensor_values = shape.num_elements(); |
| 195 | const int64 num_bytes = tensor->tensor_content().size(); |
| 196 | const int64 num_raw_values = num_bytes / sizeof(T); |
| 197 | if (num_raw_values != num_tensor_values) { |
| 198 | // Invalid or too small. |
| 199 | return false; |
| 200 | } |
| 201 | int64 last_offset = num_bytes - 1; |
| 202 | int64 prev_offset = last_offset - sizeof(T); |
| 203 | // Inspect individual raw bytes sizeof(T) bytes apart in adjacent elements, |
| 204 | // starting from the end, to find the last pair of elements that are not |
| 205 | // identical. |
| 206 | while (prev_offset >= 0) { |
| 207 | if (tensor->tensor_content()[prev_offset] != |
| 208 | tensor->tensor_content()[last_offset]) { |
| 209 | break; |
| 210 | } |
| 211 | --last_offset; |
| 212 | --prev_offset; |
| 213 | } |
| 214 | // Round up to the next whole number of element of type T. |
| 215 | const int64 new_num_values = last_offset / sizeof(T) + 1; |
| 216 | if (new_num_values * (is_complex<T>::value ? 2 : 1) * sizeof(FieldType) > |
| 217 | static_cast<int64>(num_bytes / min_compression_ratio)) { |
| 218 | return false; |
| 219 | } |
| 220 | // Copy values to truncated repeated field. |
| 221 | if (sizeof(FieldType) == sizeof(T)) { |
| 222 | FieldType* dst_ptr = |
| 223 | TypeHelper::AppendUninitialized(new_num_values, tensor); |
| 224 | port::CopySubrangeToArray(tensor->tensor_content(), 0, |
| 225 | new_num_values * sizeof(T), |
| 226 | reinterpret_cast<char*>(dst_ptr)); |
| 227 | tensor->clear_tensor_content(); |
| 228 | } else if (sizeof(T) > 1) { |
| 229 | // Copy raw bytes to temp array first, then cast. |
| 230 | gtl::InlinedVector<T, 64> tmp(new_num_values); |
| 231 | port::CopySubrangeToArray(tensor->tensor_content(), 0, |
| 232 | new_num_values * sizeof(T), |
| 233 | reinterpret_cast<char*>(tmp.data())); |
| 234 | tensor->clear_tensor_content(); |
| 235 | const T* begin = tmp.begin(); |
| 236 | const T* end = tmp.end(); |
| 237 | TypeHelper::AddValues(begin, end, tensor); |
| 238 | } else { |
| 239 | // Copy and cast, one byte at a time. |
| 240 | for (int64 i = 0; i < new_num_values; ++i) { |
| 241 | char c = tensor->tensor_content()[i]; |
| 242 | TypeHelper::AddValue(static_cast<T>(c), tensor); |
| 243 | } |
| 244 | tensor->clear_tensor_content(); |
| 245 | } |
| 246 | return true; |
| 247 | } |
nothing calls this directly
no test coverage detected