Support conversion between RedisModuleString
and unsigned long long
(#10889)
Since the ranges of `unsigned long long` and `long long` are different, we cannot read an `unsigned long long` integer from a `RedisModuleString` by `RedisModule_StringToLongLong` . So I added two new Redis Module APIs to support the conversion between these two types: * `RedisModule_StringToULongLong` * `RedisModule_CreateStringFromULongLong` Signed-off-by: RinChanNOWWW <hzy427@gmail.com>
This commit is contained in:
parent
d443e312ad
commit
2854637385
24
src/module.c
24
src/module.c
@ -2311,6 +2311,20 @@ RedisModuleString *RM_CreateStringFromLongLong(RedisModuleCtx *ctx, long long ll
|
||||
return RM_CreateString(ctx,buf,len);
|
||||
}
|
||||
|
||||
/* Like RedisModule_CreateString(), but creates a string starting from a `unsigned long long`
|
||||
* integer instead of taking a buffer and its length.
|
||||
*
|
||||
* The returned string must be released with RedisModule_FreeString() or by
|
||||
* enabling automatic memory management.
|
||||
*
|
||||
* The passed context 'ctx' may be NULL if necessary, see the
|
||||
* RedisModule_CreateString() documentation for more info. */
|
||||
RedisModuleString *RM_CreateStringFromULongLong(RedisModuleCtx *ctx, unsigned long long ull) {
|
||||
char buf[LONG_STR_SIZE];
|
||||
size_t len = ull2string(buf,sizeof(buf),ull);
|
||||
return RM_CreateString(ctx,buf,len);
|
||||
}
|
||||
|
||||
/* Like RedisModule_CreateString(), but creates a string starting from a double
|
||||
* instead of taking a buffer and its length.
|
||||
*
|
||||
@ -2519,6 +2533,14 @@ int RM_StringToLongLong(const RedisModuleString *str, long long *ll) {
|
||||
REDISMODULE_ERR;
|
||||
}
|
||||
|
||||
/* Convert the string into a `unsigned long long` integer, storing it at `*ull`.
|
||||
* Returns REDISMODULE_OK on success. If the string can't be parsed
|
||||
* as a valid, strict `unsigned long long` (no spaces before/after), REDISMODULE_ERR
|
||||
* is returned. */
|
||||
int RM_StringToULongLong(const RedisModuleString *str, unsigned long long *ull) {
|
||||
return string2ull(str->ptr,ull) ? REDISMODULE_OK : REDISMODULE_ERR;
|
||||
}
|
||||
|
||||
/* Convert the string into a double, storing it at `*d`.
|
||||
* Returns REDISMODULE_OK on success or REDISMODULE_ERR if the string is
|
||||
* not a valid string representation of a double value. */
|
||||
@ -12421,6 +12443,7 @@ void moduleRegisterCoreAPI(void) {
|
||||
REGISTER_API(ListInsert);
|
||||
REGISTER_API(ListDelete);
|
||||
REGISTER_API(StringToLongLong);
|
||||
REGISTER_API(StringToULongLong);
|
||||
REGISTER_API(StringToDouble);
|
||||
REGISTER_API(StringToLongDouble);
|
||||
REGISTER_API(StringToStreamID);
|
||||
@ -12443,6 +12466,7 @@ void moduleRegisterCoreAPI(void) {
|
||||
REGISTER_API(CreateStringFromCallReply);
|
||||
REGISTER_API(CreateString);
|
||||
REGISTER_API(CreateStringFromLongLong);
|
||||
REGISTER_API(CreateStringFromULongLong);
|
||||
REGISTER_API(CreateStringFromDouble);
|
||||
REGISTER_API(CreateStringFromLongDouble);
|
||||
REGISTER_API(CreateStringFromString);
|
||||
|
@ -915,6 +915,7 @@ REDISMODULE_API size_t (*RedisModule_CallReplyLength)(RedisModuleCallReply *repl
|
||||
REDISMODULE_API RedisModuleCallReply * (*RedisModule_CallReplyArrayElement)(RedisModuleCallReply *reply, size_t idx) REDISMODULE_ATTR;
|
||||
REDISMODULE_API RedisModuleString * (*RedisModule_CreateString)(RedisModuleCtx *ctx, const char *ptr, size_t len) REDISMODULE_ATTR;
|
||||
REDISMODULE_API RedisModuleString * (*RedisModule_CreateStringFromLongLong)(RedisModuleCtx *ctx, long long ll) REDISMODULE_ATTR;
|
||||
REDISMODULE_API RedisModuleString * (*RedisModule_CreateStringFromULongLong)(RedisModuleCtx *ctx, unsigned long long ull) REDISMODULE_ATTR;
|
||||
REDISMODULE_API RedisModuleString * (*RedisModule_CreateStringFromDouble)(RedisModuleCtx *ctx, double d) REDISMODULE_ATTR;
|
||||
REDISMODULE_API RedisModuleString * (*RedisModule_CreateStringFromLongDouble)(RedisModuleCtx *ctx, long double ld, int humanfriendly) REDISMODULE_ATTR;
|
||||
REDISMODULE_API RedisModuleString * (*RedisModule_CreateStringFromString)(RedisModuleCtx *ctx, const RedisModuleString *str) REDISMODULE_ATTR;
|
||||
@ -948,6 +949,7 @@ REDISMODULE_API int (*RedisModule_ReplyWithDouble)(RedisModuleCtx *ctx, double d
|
||||
REDISMODULE_API int (*RedisModule_ReplyWithBigNumber)(RedisModuleCtx *ctx, const char *bignum, size_t len) REDISMODULE_ATTR;
|
||||
REDISMODULE_API int (*RedisModule_ReplyWithCallReply)(RedisModuleCtx *ctx, RedisModuleCallReply *reply) REDISMODULE_ATTR;
|
||||
REDISMODULE_API int (*RedisModule_StringToLongLong)(const RedisModuleString *str, long long *ll) REDISMODULE_ATTR;
|
||||
REDISMODULE_API int (*RedisModule_StringToULongLong)(const RedisModuleString *str, unsigned long long *ull) REDISMODULE_ATTR;
|
||||
REDISMODULE_API int (*RedisModule_StringToDouble)(const RedisModuleString *str, double *d) REDISMODULE_ATTR;
|
||||
REDISMODULE_API int (*RedisModule_StringToLongDouble)(const RedisModuleString *str, long double *d) REDISMODULE_ATTR;
|
||||
REDISMODULE_API int (*RedisModule_StringToStreamID)(const RedisModuleString *str, RedisModuleStreamID *id) REDISMODULE_ATTR;
|
||||
@ -1260,6 +1262,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
|
||||
REDISMODULE_GET_API(ListInsert);
|
||||
REDISMODULE_GET_API(ListDelete);
|
||||
REDISMODULE_GET_API(StringToLongLong);
|
||||
REDISMODULE_GET_API(StringToULongLong);
|
||||
REDISMODULE_GET_API(StringToDouble);
|
||||
REDISMODULE_GET_API(StringToLongDouble);
|
||||
REDISMODULE_GET_API(StringToStreamID);
|
||||
@ -1282,6 +1285,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
|
||||
REDISMODULE_GET_API(CreateStringFromCallReply);
|
||||
REDISMODULE_GET_API(CreateString);
|
||||
REDISMODULE_GET_API(CreateStringFromLongLong);
|
||||
REDISMODULE_GET_API(CreateStringFromULongLong);
|
||||
REDISMODULE_GET_API(CreateStringFromDouble);
|
||||
REDISMODULE_GET_API(CreateStringFromLongDouble);
|
||||
REDISMODULE_GET_API(CreateStringFromString);
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define UNUSED(x) (void)(x)
|
||||
|
||||
@ -375,6 +376,68 @@ int test_rm_call_flags(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
|
||||
int test_ull_conv(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||
UNUSED(argv);
|
||||
UNUSED(argc);
|
||||
unsigned long long ull = 18446744073709551615ULL;
|
||||
const char *ullstr = "18446744073709551615";
|
||||
|
||||
RedisModuleString *s1 = RedisModule_CreateStringFromULongLong(ctx, ull);
|
||||
RedisModuleString *s2 =
|
||||
RedisModule_CreateString(ctx, ullstr, strlen(ullstr));
|
||||
if (RedisModule_StringCompare(s1, s2) != 0) {
|
||||
char err[4096];
|
||||
snprintf(err, 4096,
|
||||
"Failed to convert unsigned long long to string ('%s' != '%s')",
|
||||
RedisModule_StringPtrLen(s1, NULL),
|
||||
RedisModule_StringPtrLen(s2, NULL));
|
||||
RedisModule_ReplyWithError(ctx, err);
|
||||
goto final;
|
||||
}
|
||||
unsigned long long ull2 = 0;
|
||||
if (RedisModule_StringToULongLong(s2, &ull2) == REDISMODULE_ERR) {
|
||||
RedisModule_ReplyWithError(ctx,
|
||||
"Failed to convert string to unsigned long long");
|
||||
goto final;
|
||||
}
|
||||
if (ull2 != ull) {
|
||||
char err[4096];
|
||||
snprintf(err, 4096,
|
||||
"Failed to convert string to unsigned long long (%llu != %llu)",
|
||||
ull2,
|
||||
ull);
|
||||
RedisModule_ReplyWithError(ctx, err);
|
||||
goto final;
|
||||
}
|
||||
|
||||
/* Make sure we can't convert a string more than ULLONG_MAX or less than 0 */
|
||||
ullstr = "18446744073709551616";
|
||||
RedisModuleString *s3 = RedisModule_CreateString(ctx, ullstr, strlen(ullstr));
|
||||
unsigned long long ull3;
|
||||
if (RedisModule_StringToULongLong(s3, &ull3) == REDISMODULE_OK) {
|
||||
RedisModule_ReplyWithError(ctx, "Invalid string successfully converted to unsigned long long");
|
||||
RedisModule_FreeString(ctx, s3);
|
||||
goto final;
|
||||
}
|
||||
RedisModule_FreeString(ctx, s3);
|
||||
ullstr = "-1";
|
||||
RedisModuleString *s4 = RedisModule_CreateString(ctx, ullstr, strlen(ullstr));
|
||||
unsigned long long ull4;
|
||||
if (RedisModule_StringToULongLong(s4, &ull4) == REDISMODULE_OK) {
|
||||
RedisModule_ReplyWithError(ctx, "Invalid string successfully converted to unsigned long long");
|
||||
RedisModule_FreeString(ctx, s4);
|
||||
goto final;
|
||||
}
|
||||
RedisModule_FreeString(ctx, s4);
|
||||
|
||||
RedisModule_ReplyWithSimpleString(ctx, "ok");
|
||||
|
||||
final:
|
||||
RedisModule_FreeString(ctx, s1);
|
||||
RedisModule_FreeString(ctx, s2);
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
|
||||
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||
REDISMODULE_NOT_USED(argv);
|
||||
REDISMODULE_NOT_USED(argc);
|
||||
@ -387,6 +450,8 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
|
||||
return REDISMODULE_ERR;
|
||||
if (RedisModule_CreateCommand(ctx,"test.ld_conversion", test_ld_conv, "",0,0,0) == REDISMODULE_ERR)
|
||||
return REDISMODULE_ERR;
|
||||
if (RedisModule_CreateCommand(ctx,"test.ull_conversion", test_ull_conv, "",0,0,0) == REDISMODULE_ERR)
|
||||
return REDISMODULE_ERR;
|
||||
if (RedisModule_CreateCommand(ctx,"test.flushall", test_flushall,"",0,0,0) == REDISMODULE_ERR)
|
||||
return REDISMODULE_ERR;
|
||||
if (RedisModule_CreateCommand(ctx,"test.dbsize", test_dbsize,"",0,0,0) == REDISMODULE_ERR)
|
||||
|
@ -29,6 +29,11 @@ start_server {tags {"modules"}} {
|
||||
set ld [r test.ld_conversion]
|
||||
assert {[string match $ld "0.00000000000000001"]}
|
||||
}
|
||||
|
||||
test {test unsigned long long conversions} {
|
||||
set ret [r test.ull_conversion]
|
||||
assert {[string match $ret "ok"]}
|
||||
}
|
||||
|
||||
test {test module db commands} {
|
||||
r set x foo
|
||||
|
Loading…
x
Reference in New Issue
Block a user