@@ -61,6 +61,10 @@ MP::CmdType From(string_view token) {
6161 return MP::INVALID;
6262}
6363
64+ void MaterializeArgs (absl::Span<std::string_view> args, MP::Command* dest) {
65+ dest->Assign (args.begin (), args.end (), args.size ());
66+ }
67+
6468MP::Result ParseStore (ArgSlice tokens, MP::Command* res) {
6569 const size_t num_tokens = tokens.size ();
6670 unsigned opt_pos = 3 ;
@@ -93,7 +97,7 @@ MP::Result ParseStore(ArgSlice tokens, MP::Command* res) {
9397 return MP::OK;
9498}
9599
96- MP::Result ParseValueless (ArgSlice tokens, MP::Command* res) {
100+ MP::Result ParseValueless (ArgSlice tokens, vector<string_view>* args, MP::Command* res) {
97101 const size_t num_tokens = tokens.size ();
98102 size_t key_pos = 0 ;
99103 if (res->type == MP::GAT || res->type == MP::GATS) {
@@ -105,13 +109,15 @@ MP::Result ParseValueless(ArgSlice tokens, MP::Command* res) {
105109
106110 // We support only `flushall` or `flushall 0`
107111 if (key_pos < num_tokens && res->type == MP::FLUSHALL) {
112+ DCHECK (args->empty ());
113+
108114 int delay = 0 ;
109115 if (key_pos + 1 == num_tokens && absl::SimpleAtoi (tokens[key_pos], &delay) && delay == 0 )
110116 return MP::OK;
111117 return MP::PARSE_ERROR;
112118 }
113119
114- res-> key = tokens[key_pos++];
120+ args-> push_back ( tokens[key_pos++]) ;
115121
116122 if (key_pos < num_tokens && res->type == MP::STATS)
117123 return MP::PARSE_ERROR; // we don't support additional arguments to stats for now
@@ -126,16 +132,17 @@ MP::Result ParseValueless(ArgSlice tokens, MP::Command* res) {
126132 }
127133
128134 while (key_pos < num_tokens) {
129- res-> keys_ext . push_back (tokens[key_pos++]);
135+ args-> push_back (tokens[key_pos++]);
130136 }
131137
132138 if (res->type >= MP::DELETE) { // write commands
133- if (!res-> keys_ext . empty () && res-> keys_ext . back () == " noreply" ) {
139+ if (args-> size () > 1 && args-> back () == " noreply" ) {
134140 res->no_reply = true ;
135- res-> keys_ext . pop_back ();
141+ args-> pop_back ();
136142 }
137143 }
138144
145+ MaterializeArgs (absl::MakeSpan (*args), res);
139146 return MP::OK;
140147}
141148
@@ -180,7 +187,7 @@ bool ParseMetaMode(char m, MP::Command* res) {
180187}
181188
182189// See https://raw.githubusercontent.com/memcached/memcached/refs/heads/master/doc/protocol.txt
183- MP::Result ParseMeta (ArgSlice tokens, MP::Command* res) {
190+ MP::Result ParseMeta (ArgSlice tokens, vector<string_view>* args, MP::Command* res) {
184191 DCHECK (!tokens.empty ());
185192
186193 if (res->type == MP::META_DEBUG) {
@@ -192,11 +199,11 @@ MP::Result ParseMeta(ArgSlice tokens, MP::Command* res) {
192199 return MP::PARSE_ERROR;
193200
194201 res->meta = true ;
195- res->key = tokens[0 ];
196202 res->bytes_len = 0 ;
197203 res->flags = 0 ;
198204 res->expire_ts = 0 ;
199205
206+ args->push_back (tokens[0 ]);
200207 tokens.remove_prefix (1 );
201208
202209 // We emulate the behavior by returning the high level commands.
@@ -228,6 +235,8 @@ MP::Result ParseMeta(ArgSlice tokens, MP::Command* res) {
228235 return MP::PARSE_ERROR;
229236 }
230237
238+ string blob;
239+
231240 for (size_t i = 0 ; i < tokens.size (); ++i) {
232241 string_view token = tokens[i];
233242
@@ -239,9 +248,9 @@ MP::Result ParseMeta(ArgSlice tokens, MP::Command* res) {
239248 case ' b' :
240249 if (token.size () != 1 )
241250 return MP::PARSE_ERROR;
242- if (!absl::Base64Unescape (res-> key , &res-> blob ))
251+ if (!absl::Base64Unescape (args-> front () , &blob))
243252 return MP::PARSE_ERROR;
244- res-> key = res-> blob ;
253+ args-> front () = blob;
245254 res->base64 = true ;
246255 break ;
247256 case ' F' :
@@ -282,6 +291,7 @@ MP::Result ParseMeta(ArgSlice tokens, MP::Command* res) {
282291 return MP::PARSE_ERROR;
283292 }
284293 }
294+ MaterializeArgs (absl::MakeSpan (*args), res);
285295
286296 return MP::OK;
287297}
@@ -321,20 +331,27 @@ auto MP::Parse(string_view str, uint32_t* consumed, Command* cmd) -> Result {
321331
322332 ArgSlice tokens_view{tokens};
323333 tokens_view.remove_prefix (1 );
334+ cmd->clear ();
335+ tmp_args_.clear ();
324336
325337 if (cmd->type <= CAS) { // Store command
326338 if (tokens_view.size () < 4 || tokens[0 ].size () > 250 ) { // key length limit
327339 return MP::PARSE_ERROR;
328340 }
329341
330- cmd->key = tokens_view[0 ];
331-
342+ tmp_args_.push_back (tokens_view[0 ]);
332343 tokens_view.remove_prefix (1 );
333- return ParseStore (tokens_view, cmd);
344+ auto res = ParseStore (tokens_view, cmd);
345+ if (res != MP::OK) {
346+ return res;
347+ }
348+ MaterializeArgs (absl::MakeSpan (tmp_args_), cmd);
349+
350+ return MP::OK;
334351 }
335352
336353 if (cmd->type >= META_SET) {
337- return tokens_view.empty () ? MP::PARSE_ERROR : ParseMeta (tokens_view, cmd);
354+ return tokens_view.empty () ? MP::PARSE_ERROR : ParseMeta (tokens_view, &tmp_args_, cmd);
338355 }
339356
340357 if (tokens_view.empty ()) {
@@ -344,7 +361,7 @@ auto MP::Parse(string_view str, uint32_t* consumed, Command* cmd) -> Result {
344361 return MP::PARSE_ERROR;
345362 }
346363
347- return ParseValueless (tokens_view, cmd);
364+ return ParseValueless (tokens_view, &tmp_args_, cmd);
348365};
349366
350367} // namespace facade
0 commit comments