| 1165 | } |
| 1166 | |
| 1167 | StringValue StringValue::Reverse(google::protobuf::Arena* absl_nonnull arena) const { |
| 1168 | return value_.Visit(absl::Overload( |
| 1169 | [arena](absl::string_view string) -> StringValue { |
| 1170 | if (string.empty()) { |
| 1171 | return StringValue(); |
| 1172 | } |
| 1173 | std::string reversed; |
| 1174 | reversed.reserve(string.size()); |
| 1175 | const char* ptr = string.data() + string.size(); |
| 1176 | const char* begin = string.data(); |
| 1177 | while (ptr > begin) { |
| 1178 | const char* char_end = ptr; |
| 1179 | --ptr; |
| 1180 | // Back up to beginning of encoded UTF-8 code point. |
| 1181 | while (ptr > begin && (*ptr & 0xC0) == 0x80) { |
| 1182 | --ptr; |
| 1183 | } |
| 1184 | reversed.append(ptr, char_end - ptr); |
| 1185 | } |
| 1186 | return StringValue::From(std::move(reversed), arena); |
| 1187 | }, |
| 1188 | [arena](const absl::Cord& cord) -> StringValue { |
| 1189 | if (cord.empty()) { |
| 1190 | return StringValue(); |
| 1191 | } |
| 1192 | std::vector<char32_t> code_points; |
| 1193 | absl::Cord::CharIterator char_begin = cord.char_begin(); |
| 1194 | absl::Cord::CharIterator char_end = cord.char_end(); |
| 1195 | while (char_begin != char_end) { |
| 1196 | char32_t code_point; |
| 1197 | size_t code_units = |
| 1198 | cel::internal::Utf8Decode(char_begin, &code_point); |
| 1199 | code_points.push_back(code_point); |
| 1200 | absl::Cord::Advance(&char_begin, code_units); |
| 1201 | } |
| 1202 | std::string reversed; |
| 1203 | reversed.reserve(cord.size()); |
| 1204 | for (auto it = code_points.rbegin(); it != code_points.rend(); ++it) { |
| 1205 | cel::internal::Utf8Encode(*it, &reversed); |
| 1206 | } |
| 1207 | return StringValue::From(std::move(reversed), arena); |
| 1208 | })); |
| 1209 | } |
| 1210 | |
| 1211 | absl::StatusOr<Value> StringValue::Join( |
| 1212 | const ListValue& list, |