| 432 | } |
| 433 | |
| 434 | std::vector<std::string> TokenizeRedisProtocol(const std::string &value) { |
| 435 | std::vector<std::string> tokens; |
| 436 | |
| 437 | if (value.empty()) { |
| 438 | return tokens; |
| 439 | } |
| 440 | |
| 441 | enum ParserState { stateArrayLen, stateBulkLen, stateBulkData }; |
| 442 | uint64_t array_len = 0, bulk_len = 0; |
| 443 | int state = stateArrayLen; |
| 444 | const char *start = value.data(), *end = start + value.size(), *p = nullptr; |
| 445 | |
| 446 | while (start != end) { |
| 447 | switch (state) { |
| 448 | case stateArrayLen: { |
| 449 | if (start[0] != '*') { |
| 450 | return tokens; |
| 451 | } |
| 452 | |
| 453 | p = strchr(start, '\r'); |
| 454 | if (!p || (p == end) || p[1] != '\n') { |
| 455 | tokens.clear(); |
| 456 | return tokens; |
| 457 | } |
| 458 | |
| 459 | // parse_result expects to must be parsed successfully here |
| 460 | array_len = *ParseInt<uint64_t>(std::string(start + 1, p), 10); |
| 461 | start = p + 2; |
| 462 | state = stateBulkLen; |
| 463 | break; |
| 464 | } |
| 465 | case stateBulkLen: { |
| 466 | if (start[0] != '$') { |
| 467 | return tokens; |
| 468 | } |
| 469 | |
| 470 | p = strchr(start, '\r'); |
| 471 | if (!p || (p == end) || p[1] != '\n') { |
| 472 | tokens.clear(); |
| 473 | return tokens; |
| 474 | } |
| 475 | |
| 476 | // parse_result expects to must be parsed successfully here |
| 477 | bulk_len = *ParseInt<uint64_t>(std::string(start + 1, p), 10); |
| 478 | start = p + 2; |
| 479 | state = stateBulkData; |
| 480 | break; |
| 481 | } |
| 482 | case stateBulkData: { |
| 483 | if (bulk_len + 2 > static_cast<uint64_t>(end - start)) { |
| 484 | tokens.clear(); |
| 485 | return tokens; |
| 486 | } |
| 487 | |
| 488 | tokens.emplace_back(start, start + bulk_len); |
| 489 | start += bulk_len + 2; |
| 490 | state = stateBulkLen; |
| 491 | break; |
no outgoing calls