summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/module.c24
-rw-r--r--src/redismodule.h4
-rw-r--r--tests/modules/misc.c65
-rw-r--r--tests/unit/moduleapi/misc.tcl5
4 files changed, 98 insertions, 0 deletions
diff --git a/src/module.c b/src/module.c
index f81b2c042..fd2de983d 100644
--- a/src/module.c
+++ b/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);
diff --git a/src/redismodule.h b/src/redismodule.h
index e36d5f3c0..a55c2e712 100644
--- a/src/redismodule.h
+++ b/src/redismodule.h
@@ -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);
diff --git a/tests/modules/misc.c b/tests/modules/misc.c
index dce78ca2b..c9ebcc5f9 100644
--- a/tests/modules/misc.c
+++ b/tests/modules/misc.c
@@ -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)
diff --git a/tests/unit/moduleapi/misc.tcl b/tests/unit/moduleapi/misc.tcl
index 3fca1cf7f..e9efdc2b3 100644
--- a/tests/unit/moduleapi/misc.tcl
+++ b/tests/unit/moduleapi/misc.tcl
@@ -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