| 1455 | } |
| 1456 | |
| 1457 | Value StringValue::CharAt(int64_t pos) const { |
| 1458 | if (pos < 0) { |
| 1459 | return ErrorValue(absl::InvalidArgumentError( |
| 1460 | "<string>.charAt(<pos>): <pos> is less than 0")); |
| 1461 | } |
| 1462 | return value_.Visit(absl::Overload( |
| 1463 | [this, pos](absl::string_view rep) mutable -> Value { |
| 1464 | while (!rep.empty()) { |
| 1465 | char32_t code_point; |
| 1466 | size_t code_units; |
| 1467 | std::tie(code_point, code_units) = cel::internal::Utf8Decode(rep); |
| 1468 | if (pos == 0) { |
| 1469 | StringValue result; |
| 1470 | result.value_.rep_.header.kind = |
| 1471 | common_internal::ByteStringKind::kSmall; |
| 1472 | result.value_.rep_.small.size = cel::internal::Utf8Encode( |
| 1473 | code_point, result.value_.rep_.small.data); |
| 1474 | result.value_.rep_.small.arena = value_.GetArena(); |
| 1475 | return result; |
| 1476 | } |
| 1477 | rep.remove_prefix(code_units); |
| 1478 | --pos; |
| 1479 | } |
| 1480 | // If we exit the loop, we iterated through all the code points in |
| 1481 | // `rep`. `pos == 0` means we were looking for a character at index |
| 1482 | // `size()`, which is defined to return an empty string. |
| 1483 | if (pos == 0) { |
| 1484 | return StringValue(); |
| 1485 | } |
| 1486 | return ErrorValue(absl::InvalidArgumentError( |
| 1487 | "<string>.charAt(<pos>): <pos> is greater than <string>.size()")); |
| 1488 | }, |
| 1489 | [pos](const absl::Cord& rep) mutable -> Value { |
| 1490 | absl::Cord::CharIterator begin = rep.char_begin(); |
| 1491 | absl::Cord::CharIterator end = rep.char_end(); |
| 1492 | while (begin != end) { |
| 1493 | char32_t code_point; |
| 1494 | size_t code_units; |
| 1495 | std::tie(code_point, code_units) = cel::internal::Utf8Decode(begin); |
| 1496 | if (pos == 0) { |
| 1497 | StringValue result; |
| 1498 | result.value_.rep_.header.kind = |
| 1499 | common_internal::ByteStringKind::kSmall; |
| 1500 | result.value_.rep_.small.size = cel::internal::Utf8Encode( |
| 1501 | code_point, result.value_.rep_.small.data); |
| 1502 | result.value_.rep_.small.arena = nullptr; |
| 1503 | return result; |
| 1504 | } |
| 1505 | absl::Cord::Advance(&begin, code_units); |
| 1506 | --pos; |
| 1507 | } |
| 1508 | // If we exit the loop, we iterated through all the code points in |
| 1509 | // `rep`. `pos == 0` means we were looking for a character at index |
| 1510 | // `size()`, which is defined to return an empty string. |
| 1511 | if (pos == 0) { |
| 1512 | return StringValue(); |
| 1513 | } |
| 1514 | return ErrorValue(absl::InvalidArgumentError( |