This command implements ZRANGEBYLEX, ZREVRANGEBYLEX. */
| 3431 | |
| 3432 | /* This command implements ZRANGEBYLEX, ZREVRANGEBYLEX. */ |
| 3433 | void genericZrangebylexCommand(zrange_result_handler *handler, |
| 3434 | zlexrangespec *range, robj *zobj, int withscores, long offset, long limit, |
| 3435 | int reverse) |
| 3436 | { |
| 3437 | client *c = handler->client; |
| 3438 | unsigned long rangelen = 0; |
| 3439 | |
| 3440 | handler->beginResultEmission(handler); |
| 3441 | |
| 3442 | if (zobj->encoding == OBJ_ENCODING_ZIPLIST) { |
| 3443 | unsigned char *zl = zobj->ptr; |
| 3444 | unsigned char *eptr, *sptr; |
| 3445 | unsigned char *vstr; |
| 3446 | unsigned int vlen; |
| 3447 | long long vlong; |
| 3448 | |
| 3449 | /* If reversed, get the last node in range as starting point. */ |
| 3450 | if (reverse) { |
| 3451 | eptr = zzlLastInLexRange(zl,range); |
| 3452 | } else { |
| 3453 | eptr = zzlFirstInLexRange(zl,range); |
| 3454 | } |
| 3455 | |
| 3456 | /* Get score pointer for the first element. */ |
| 3457 | if (eptr) |
| 3458 | sptr = ziplistNext(zl,eptr); |
| 3459 | |
| 3460 | /* If there is an offset, just traverse the number of elements without |
| 3461 | * checking the score because that is done in the next loop. */ |
| 3462 | while (eptr && offset--) { |
| 3463 | if (reverse) { |
| 3464 | zzlPrev(zl,&eptr,&sptr); |
| 3465 | } else { |
| 3466 | zzlNext(zl,&eptr,&sptr); |
| 3467 | } |
| 3468 | } |
| 3469 | |
| 3470 | while (eptr && limit--) { |
| 3471 | double score = 0; |
| 3472 | if (withscores) /* don't bother to extract the score if it's gonna be ignored. */ |
| 3473 | score = zzlGetScore(sptr); |
| 3474 | |
| 3475 | /* Abort when the node is no longer in range. */ |
| 3476 | if (reverse) { |
| 3477 | if (!zzlLexValueGteMin(eptr,range)) break; |
| 3478 | } else { |
| 3479 | if (!zzlLexValueLteMax(eptr,range)) break; |
| 3480 | } |
| 3481 | |
| 3482 | /* We know the element exists, so ziplistGet should always |
| 3483 | * succeed. */ |
| 3484 | serverAssertWithInfo(c,zobj,ziplistGet(eptr,&vstr,&vlen,&vlong)); |
| 3485 | |
| 3486 | rangelen++; |
| 3487 | if (vstr == NULL) { |
| 3488 | handler->emitResultFromLongLong(handler, vlong, score); |
| 3489 | } else { |
| 3490 | handler->emitResultFromCBuffer(handler, vstr, vlen, score); |
no test coverage detected